XMMS2
src/xmms/visualization/udp.c
Go to the documentation of this file.
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 }