XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2011 XMMS2 Team 00003 * 00004 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 */ 00016 00017 #include <stdlib.h> 00018 #include <unistd.h> 00019 #include "common.h" 00020 00021 static gboolean 00022 udpwatcher (GIOChannel *src, GIOCondition cond, xmms_visualization_t *vis) 00023 { 00024 struct sockaddr_storage from; 00025 socklen_t sl = sizeof (from); 00026 xmmsc_vis_udp_timing_t packet_d; 00027 char* packet = packet_init_timing (&packet_d); 00028 if ((recvfrom (vis->socket, packet, packet_d.size, 0, (struct sockaddr *)&from, &sl)) > 0) { 00029 if (*packet_d.__unaligned_type == 'H') { 00030 xmms_vis_client_t *c; 00031 int32_t id; 00032 00033 XMMSC_VIS_UNALIGNED_READ (id, packet_d.__unaligned_id, int32_t); 00034 id = ntohl (id); 00035 00036 /* debug code starts 00037 char adrb[INET6_ADDRSTRLEN]; 00038 struct sockaddr_in6 *a = (struct sockaddr_in6 *)&from; 00039 printf ("Client address: %s:%d, %d\n", inet_ntop (AF_INET6, &a->sin6_addr, 00040 adrb, INET6_ADDRSTRLEN), a->sin6_port, id); 00041 debug code ends */ 00042 g_mutex_lock (vis->clientlock); 00043 c = get_client (id); 00044 if (!c || c->type != VIS_UDP) { 00045 g_mutex_unlock (vis->clientlock); 00046 return TRUE; 00047 } 00048 /* save client address according to id */ 00049 memcpy (&c->transport.udp.addr, &from, sizeof (from)); 00050 c->transport.udp.socket[0] = 1; 00051 c->transport.udp.grace = 2000; 00052 g_mutex_unlock (vis->clientlock); 00053 } else if (*packet_d.__unaligned_type == 'T') { 00054 struct timeval time; 00055 xmms_vis_client_t *c; 00056 int32_t id; 00057 00058 XMMSC_VIS_UNALIGNED_READ (id, packet_d.__unaligned_id, int32_t); 00059 id = ntohl (id); 00060 00061 g_mutex_lock (vis->clientlock); 00062 c = get_client (id); 00063 if (!c || c->type != VIS_UDP) { 00064 g_mutex_unlock (vis->clientlock); 00065 free (packet); 00066 return TRUE; 00067 } 00068 c->transport.udp.grace = 2000; 00069 g_mutex_unlock (vis->clientlock); 00070 00071 /* give pong */ 00072 gettimeofday (&time, NULL); 00073 00074 struct timeval cts, sts; 00075 00076 XMMSC_VIS_UNALIGNED_READ (cts.tv_sec, &packet_d.__unaligned_clientstamp[0], int32_t); 00077 XMMSC_VIS_UNALIGNED_READ (cts.tv_usec, &packet_d.__unaligned_clientstamp[1], int32_t); 00078 cts.tv_sec = ntohl (cts.tv_sec); 00079 cts.tv_usec = ntohl (cts.tv_usec); 00080 00081 sts.tv_sec = time.tv_sec - cts.tv_sec; 00082 sts.tv_usec = time.tv_usec - cts.tv_usec; 00083 if (sts.tv_usec < 0) { 00084 sts.tv_sec--; 00085 sts.tv_usec += 1000000; 00086 } 00087 00088 XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_serverstamp[0], 00089 (int32_t)htonl (sts.tv_sec), int32_t); 00090 XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_serverstamp[1], 00091 (int32_t)htonl (sts.tv_usec), int32_t); 00092 00093 sendto (vis->socket, packet, packet_d.size, 0, (struct sockaddr *)&from, sl); 00094 00095 /* new debug: 00096 printf ("Timings: local %f, remote %f, diff %f\n", tv2ts (&time), net2ts (packet_d.clientstamp), net2ts (packet_d.clientstamp) - tv2ts (&time)); 00097 ends */ 00098 } else { 00099 xmms_log_error ("Received invalid UDP package!"); 00100 } 00101 } 00102 free (packet); 00103 return TRUE; 00104 } 00105 00106 int32_t 00107 init_udp (xmms_visualization_t *vis, int32_t id, xmms_error_t *err) 00108 { 00109 // TODO: we need the currently used port, not only the default one! */ 00110 int32_t port = XMMS_DEFAULT_TCP_PORT; 00111 xmms_vis_client_t *c; 00112 00113 // setup socket if needed 00114 if (!xmms_socket_valid (vis->socket)) { 00115 struct addrinfo hints; 00116 struct addrinfo *result, *rp; 00117 int s; 00118 00119 memset (&hints, 0, sizeof (hints)); 00120 hints.ai_family = AF_UNSPEC; 00121 hints.ai_socktype = SOCK_DGRAM; 00122 hints.ai_flags = AI_PASSIVE; 00123 hints.ai_protocol = 0; 00124 00125 if ((s = getaddrinfo (NULL, G_STRINGIFY (XMMS_DEFAULT_TCP_PORT), &hints, &result)) != 0) 00126 { 00127 xmms_log_error ("Could not setup socket! getaddrinfo: %s", gai_strerror (s)); 00128 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "Could not setup socket!"); 00129 return -1; 00130 } 00131 00132 for (rp = result; rp != NULL; rp = rp->ai_next) { 00133 vis->socket = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); 00134 if (!xmms_socket_valid (vis->socket)) { 00135 continue; 00136 } 00137 if (bind (vis->socket, rp->ai_addr, rp->ai_addrlen) != -1) { 00138 break; 00139 } else { 00140 close (vis->socket); 00141 } 00142 } 00143 if (rp == NULL) { 00144 xmms_log_error ("Could not bind socket!"); 00145 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "Could not bind socket!"); 00146 freeaddrinfo (result); 00147 return -1; 00148 } 00149 freeaddrinfo (result); 00150 00151 /* register into mainloop: */ 00152 /* perhaps needed, perhaps not .. #ifdef __WIN32__ 00153 vis->socketio = g_io_channel_win32_new_socket (vis->socket); 00154 #else */ 00155 vis->socketio = g_io_channel_unix_new (vis->socket); 00156 /*#endif */ 00157 g_io_channel_set_encoding (vis->socketio, NULL, NULL); 00158 g_io_channel_set_buffered (vis->socketio, FALSE); 00159 g_io_add_watch (vis->socketio, G_IO_IN, (GIOFunc) udpwatcher, vis); 00160 } 00161 00162 /* set up client structure */ 00163 x_fetch_client (id); 00164 c->type = VIS_UDP; 00165 memset (&c->transport.udp.addr, 0, sizeof (c->transport.udp.addr)); 00166 c->transport.udp.socket[0] = 0; 00167 x_release_client (); 00168 00169 xmms_log_info ("Visualization client %d initialised using UDP", id); 00170 return port; 00171 } 00172 00173 void 00174 cleanup_udp (xmmsc_vis_udp_t *t, xmms_socket_t socket) 00175 { 00176 socklen_t sl = sizeof (t->addr); 00177 char packet = 'K'; 00178 sendto (socket, &packet, 1, 0, (struct sockaddr *)&t->addr, sl); 00179 } 00180 00181 gboolean 00182 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) 00183 { 00184 xmmsc_vis_udp_data_t packet_d; 00185 xmmsc_vischunk_t *__unaligned_dest; 00186 short res; 00187 int offset; 00188 char* packet; 00189 00190 /* first check if the client is still there */ 00191 if (t->grace == 0) { 00192 delete_client (id); 00193 return FALSE; 00194 } 00195 if (t->socket == 0) { 00196 return FALSE; 00197 } 00198 00199 packet = packet_init_data (&packet_d); 00200 t->grace--; 00201 XMMSC_VIS_UNALIGNED_WRITE (packet_d.__unaligned_grace, htons (t->grace), uint16_t); 00202 __unaligned_dest = packet_d.__unaligned_data; 00203 00204 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->timestamp[0], 00205 (int32_t)htonl (time->tv_sec), int32_t); 00206 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->timestamp[1], 00207 (int32_t)htonl (time->tv_usec), int32_t); 00208 00209 00210 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->format, (uint16_t)htons (c->format), uint16_t); 00211 res = fill_buffer (__unaligned_dest->data, &c->prop, channels, size, buf); 00212 XMMSC_VIS_UNALIGNED_WRITE (&__unaligned_dest->size, (uint16_t)htons (res), uint16_t); 00213 00214 offset = ((char*)&__unaligned_dest->data - (char*)__unaligned_dest); 00215 00216 sendto (socket, packet, XMMS_VISPACKET_UDP_OFFSET + offset + res * sizeof (int16_t), 0, (struct sockaddr *)&t->addr, sizeof (t->addr)); 00217 free (packet); 00218 00219 00220 return TRUE; 00221 }