XMMS2
udp.c
Go to the documentation of this file.
1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2011 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17#include <stdlib.h>
18#include <unistd.h>
19#include "common.h"
20
21static gboolean
22udpwatcher (GIOChannel *src, GIOCondition cond, xmms_visualization_t *vis)
23{
24 struct sockaddr_storage from;
25 socklen_t sl = sizeof (from);
27 char* packet = packet_init_timing (&packet_d);
28 if ((recvfrom (vis->socket, packet, packet_d.size, 0, (struct sockaddr *)&from, &sl)) > 0) {
29 if (*packet_d.__unaligned_type == 'H') {
31 int32_t id;
32
33 XMMSC_VIS_UNALIGNED_READ (id, packet_d.__unaligned_id, int32_t);
34 id = ntohl (id);
35
36 /* debug code starts
37 char adrb[INET6_ADDRSTRLEN];
38 struct sockaddr_in6 *a = (struct sockaddr_in6 *)&from;
39 printf ("Client address: %s:%d, %d\n", inet_ntop (AF_INET6, &a->sin6_addr,
40 adrb, INET6_ADDRSTRLEN), a->sin6_port, id);
41 debug code ends */
42 g_mutex_lock (vis->clientlock);
43 c = get_client (id);
44 if (!c || c->type != VIS_UDP) {
45 g_mutex_unlock (vis->clientlock);
46 return TRUE;
47 }
48 /* save client address according to id */
49 memcpy (&c->transport.udp.addr, &from, sizeof (from));
50 c->transport.udp.socket[0] = 1;
51 c->transport.udp.grace = 2000;
52 g_mutex_unlock (vis->clientlock);
53 } else if (*packet_d.__unaligned_type == 'T') {
54 struct timeval time;
56 int32_t id;
57
58 XMMSC_VIS_UNALIGNED_READ (id, packet_d.__unaligned_id, int32_t);
59 id = ntohl (id);
60
61 g_mutex_lock (vis->clientlock);
62 c = get_client (id);
63 if (!c || c->type != VIS_UDP) {
64 g_mutex_unlock (vis->clientlock);
65 free (packet);
66 return TRUE;
67 }
68 c->transport.udp.grace = 2000;
69 g_mutex_unlock (vis->clientlock);
70
71 /* give pong */
72 gettimeofday (&time, NULL);
73
74 struct timeval cts, sts;
75
76 XMMSC_VIS_UNALIGNED_READ (cts.tv_sec, &packet_d.__unaligned_clientstamp[0], int32_t);
77 XMMSC_VIS_UNALIGNED_READ (cts.tv_usec, &packet_d.__unaligned_clientstamp[1], int32_t);
78 cts.tv_sec = ntohl (cts.tv_sec);
79 cts.tv_usec = ntohl (cts.tv_usec);
80
81 sts.tv_sec = time.tv_sec - cts.tv_sec;
82 sts.tv_usec = time.tv_usec - cts.tv_usec;
83 if (sts.tv_usec < 0) {
84 sts.tv_sec--;
85 sts.tv_usec += 1000000;
86 }
87
89 (int32_t)htonl (sts.tv_sec), int32_t);
91 (int32_t)htonl (sts.tv_usec), int32_t);
92
93 sendto (vis->socket, packet, packet_d.size, 0, (struct sockaddr *)&from, sl);
94
95 /* new debug:
96 printf ("Timings: local %f, remote %f, diff %f\n", tv2ts (&time), net2ts (packet_d.clientstamp), net2ts (packet_d.clientstamp) - tv2ts (&time));
97 ends */
98 } else {
99 xmms_log_error ("Received invalid UDP package!");
100 }
101 }
102 free (packet);
103 return TRUE;
104}
105
106int32_t
108{
109 // TODO: we need the currently used port, not only the default one! */
110 int32_t port = XMMS_DEFAULT_TCP_PORT;
112
113 // setup socket if needed
114 if (!xmms_socket_valid (vis->socket)) {
115 struct addrinfo hints;
116 struct addrinfo *result, *rp;
117 int s;
118
119 memset (&hints, 0, sizeof (hints));
120 hints.ai_family = AF_UNSPEC;
121 hints.ai_socktype = SOCK_DGRAM;
122 hints.ai_flags = AI_PASSIVE;
123 hints.ai_protocol = 0;
124
125 if ((s = getaddrinfo (NULL, G_STRINGIFY (XMMS_DEFAULT_TCP_PORT), &hints, &result)) != 0)
126 {
127 xmms_log_error ("Could not setup socket! getaddrinfo: %s", gai_strerror (s));
128 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "Could not setup socket!");
129 return -1;
130 }
131
132 for (rp = result; rp != NULL; rp = rp->ai_next) {
133 vis->socket = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
134 if (!xmms_socket_valid (vis->socket)) {
135 continue;
136 }
137 if (bind (vis->socket, rp->ai_addr, rp->ai_addrlen) != -1) {
138 break;
139 } else {
140 close (vis->socket);
141 }
142 }
143 if (rp == NULL) {
144 xmms_log_error ("Could not bind socket!");
145 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "Could not bind socket!");
146 freeaddrinfo (result);
147 return -1;
148 }
149 freeaddrinfo (result);
150
151 /* register into mainloop: */
152/* perhaps needed, perhaps not .. #ifdef __WIN32__
153 vis->socketio = g_io_channel_win32_new_socket (vis->socket);
154#else */
155 vis->socketio = g_io_channel_unix_new (vis->socket);
156/*#endif */
157 g_io_channel_set_encoding (vis->socketio, NULL, NULL);
158 g_io_channel_set_buffered (vis->socketio, FALSE);
159 g_io_add_watch (vis->socketio, G_IO_IN, (GIOFunc) udpwatcher, vis);
160 }
161
162 /* set up client structure */
163 x_fetch_client (id);
164 c->type = VIS_UDP;
165 memset (&c->transport.udp.addr, 0, sizeof (c->transport.udp.addr));
166 c->transport.udp.socket[0] = 0;
168
169 xmms_log_info ("Visualization client %d initialised using UDP", id);
170 return port;
171}
172
173void
175{
176 socklen_t sl = sizeof (t->addr);
177 char packet = 'K';
178 sendto (socket, &packet, 1, 0, (struct sockaddr *)&t->addr, sl);
179}
180
181gboolean
182write_udp (xmmsc_vis_udp_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf, int socket)
183{
184 xmmsc_vis_udp_data_t packet_d;
185 xmmsc_vischunk_t *__unaligned_dest;
186 short res;
187 int offset;
188 char* packet;
189
190 /* first check if the client is still there */
191 if (t->grace == 0) {
192 delete_client (id);
193 return FALSE;
194 }
195 if (t->socket == 0) {
196 return FALSE;
197 }
198
199 packet = packet_init_data (&packet_d);
200 t->grace--;
201 XMMSC_VIS_UNALIGNED_WRITE (packet_d.__unaligned_grace, htons (t->grace), uint16_t);
202 __unaligned_dest = packet_d.__unaligned_data;
203
204 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->timestamp[0],
205 (int32_t)htonl (time->tv_sec), int32_t);
206 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->timestamp[1],
207 (int32_t)htonl (time->tv_usec), int32_t);
208
209
210 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->format, (uint16_t)htons (c->format), uint16_t);
211 res = fill_buffer (__unaligned_dest->data, &c->prop, channels, size, buf);
212 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->size, (uint16_t)htons (res), uint16_t);
213
214 offset = ((char*)&__unaligned_dest->data - (char*)__unaligned_dest);
215
216 sendto (socket, packet, XMMS_VISPACKET_UDP_OFFSET + offset + res * sizeof (int16_t), 0, (struct sockaddr *)&t->addr, sizeof (t->addr));
217 free (packet);
218
219
220 return TRUE;
221}
short fill_buffer(int16_t *dest, xmmsc_vis_properties_t *prop, int channels, int size, short *src)
Definition: format.c:149
#define x_fetch_client(id)
Definition: common.h:63
#define x_release_client()
Definition: common.h:71
char * packet_init_timing(xmmsc_vis_udp_timing_t *p)
Definition: udp.c:22
xmms_vis_client_t * get_client(int32_t id)
Definition: object.c:73
void delete_client(int32_t id)
Definition: object.c:84
#define XMMS_VISPACKET_UDP_OFFSET
char * packet_init_data(xmmsc_vis_udp_data_t *p)
Definition: udp.c:8
#define XMMSC_VIS_UNALIGNED_READ(dst, src, typ)
#define XMMSC_VIS_UNALIGNED_WRITE(dst, src, typ)
The structures for a vis client.
Definition: common.h:30
xmmsc_vis_udp_t udp
Definition: common.h:33
unsigned short format
Definition: common.h:36
xmmsc_vis_transport_t type
Definition: common.h:35
xmmsc_vis_properties_t prop
Definition: common.h:37
union xmms_vis_client_t::@2 transport
The structures for the vis module.
Definition: common.h:78
GIOChannel * socketio
Definition: common.h:82
xmms_socket_t socket
Definition: common.h:81
GMutex * clientlock
Definition: common.h:84
UDP package descriptor to deliver a vis chunk.
xmmsc_vischunk_t * __unaligned_data
data describing a udp transport
xmms_socket_t socket[2]
struct sockaddr_storage addr
UDP package descriptor to synchronize time.
Package format for vis data, encapsulated by unixshm or udp transport.
int16_t data[2 *XMMSC_VISUALIZATION_WINDOW_SIZE]
gboolean write_udp(xmmsc_vis_udp_t *t, xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf, int socket)
Definition: udp.c:182
int32_t init_udp(xmms_visualization_t *vis, int32_t id, xmms_error_t *err)
Definition: udp.c:107
void cleanup_udp(xmmsc_vis_udp_t *t, xmms_socket_t socket)
Definition: udp.c:174
#define xmms_log_error(fmt,...)
Definition: xmms_log.h:35
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
G_BEGIN_DECLS struct xmms_error_St xmms_error_t
@ XMMS_ERROR_NO_SAUSAGE
int xmms_socket_t
Definition: xmmsc_sockets.h:37
int xmms_socket_valid(xmms_socket_t socket)
Definition: socket_unix.c:36
#define XMMS_DEFAULT_TCP_PORT
Definition: xmmsc_util.h:46