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 
21 static gboolean
22 udpwatcher (GIOChannel *src, GIOCondition cond, xmms_visualization_t *vis)
23 {
24  struct sockaddr_storage from;
25  socklen_t sl = sizeof (from);
26  xmmsc_vis_udp_timing_t packet_d;
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 
106 int32_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;
167  x_release_client ();
168 
169  xmms_log_info ("Visualization client %d initialised using UDP", id);
170  return port;
171 }
172 
173 void
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 
181 gboolean
182 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)
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 }
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:107
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:182
xmms_vis_client_t * get_client(int32_t id)
Definition: object.c:73
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:174
#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:46
#define XMMSC_VIS_UNALIGNED_WRITE(dst, src, typ)
#define XMMS_VISPACKET_UDP_OFFSET
void delete_client(int32_t id)
Definition: object.c:84
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