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