static double udp_timediff (int32_t id, int socket) { int i; double lag; struct timeval time; double diff = 0.0; int diffc = 0; xmmsc_vis_udp_timing_t packet_d; char* packet = packet_init_timing (&packet_d); gettimeofday (&time, NULL); XMMSC_VIS_UNALIGNED_WRITE (packet_d.__unaligned_id, (int32_t)htonl (id), int32_t); XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_clientstamp[0], (int32_t)htonl (time.tv_sec), int32_t); XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_clientstamp[1], (int32_t)htonl (time.tv_usec), int32_t); /* TODO: handle lost packages! */ for (i = 0; i < 10; ++i) { send (socket, packet, packet_d.size, 0); } printf ("Syncing "); do { if ((recv (socket, packet, packet_d.size, 0) == packet_d.size) && (*packet_d.__unaligned_type == 'T')) { struct timeval rtv; gettimeofday (&time, NULL); XMMSC_VIS_UNALIGNED_READ (rtv.tv_sec, &packet_d.__unaligned_clientstamp[0], int32_t); XMMSC_VIS_UNALIGNED_READ (rtv.tv_usec, &packet_d.__unaligned_clientstamp[1], int32_t); rtv.tv_sec = ntohl (rtv.tv_sec); rtv.tv_usec = ntohl (rtv.tv_usec); lag = (tv2ts (&time) - tv2ts (&rtv)) / 2.0; diffc++; XMMSC_VIS_UNALIGNED_READ (rtv.tv_sec, &packet_d.__unaligned_serverstamp[0], int32_t); XMMSC_VIS_UNALIGNED_READ (rtv.tv_usec, &packet_d.__unaligned_serverstamp[1], int32_t); rtv.tv_sec = ntohl (rtv.tv_sec); rtv.tv_usec = ntohl (rtv.tv_usec); diff += tv2ts (&rtv) - lag; /* debug output printf("server diff: %f \t old timestamp: %f, new timestamp %f\n", net2ts (packet_d.serverstamp), net2ts (packet_d.clientstamp), tv2ts (&time)); end of debug */ putchar('.'); } } while (diffc < 10); free (packet); puts (" done."); return diff / (double)diffc; }
static gboolean udpwatcher (GIOChannel *src, GIOCondition cond, xmms_visualization_t *vis) { struct sockaddr_storage from; socklen_t sl = sizeof (from); xmmsc_vis_udp_timing_t packet_d; char* packet = packet_init_timing (&packet_d); if ((recvfrom (vis->socket, packet, packet_d.size, 0, (struct sockaddr *)&from, &sl)) > 0) { if (*packet_d.__unaligned_type == 'H') { xmms_vis_client_t *c; int32_t id; XMMSC_VIS_UNALIGNED_READ (id, packet_d.__unaligned_id, int32_t); id = ntohl (id); /* debug code starts char adrb[INET6_ADDRSTRLEN]; struct sockaddr_in6 *a = (struct sockaddr_in6 *)&from; printf ("Client address: %s:%d, %d\n", inet_ntop (AF_INET6, &a->sin6_addr, adrb, INET6_ADDRSTRLEN), a->sin6_port, id); debug code ends */ g_mutex_lock (vis->clientlock); c = get_client (id); if (!c || c->type != VIS_UDP) { g_mutex_unlock (vis->clientlock); return TRUE; } /* save client address according to id */ memcpy (&c->transport.udp.addr, &from, sizeof (from)); c->transport.udp.socket[0] = 1; c->transport.udp.grace = 2000; g_mutex_unlock (vis->clientlock); } else if (*packet_d.__unaligned_type == 'T') { struct timeval time; xmms_vis_client_t *c; int32_t id; XMMSC_VIS_UNALIGNED_READ (id, packet_d.__unaligned_id, int32_t); id = ntohl (id); g_mutex_lock (vis->clientlock); c = get_client (id); if (!c || c->type != VIS_UDP) { g_mutex_unlock (vis->clientlock); free (packet); return TRUE; } c->transport.udp.grace = 2000; g_mutex_unlock (vis->clientlock); /* give pong */ gettimeofday (&time, NULL); struct timeval cts, sts; XMMSC_VIS_UNALIGNED_READ (cts.tv_sec, &packet_d.__unaligned_clientstamp[0], int32_t); XMMSC_VIS_UNALIGNED_READ (cts.tv_usec, &packet_d.__unaligned_clientstamp[1], int32_t); cts.tv_sec = ntohl (cts.tv_sec); cts.tv_usec = ntohl (cts.tv_usec); sts.tv_sec = time.tv_sec - cts.tv_sec; sts.tv_usec = time.tv_usec - cts.tv_usec; if (sts.tv_usec < 0) { sts.tv_sec--; sts.tv_usec += 1000000; } XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_serverstamp[0], (int32_t)htonl (sts.tv_sec), int32_t); XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_serverstamp[1], (int32_t)htonl (sts.tv_usec), int32_t); sendto (vis->socket, packet, packet_d.size, 0, (struct sockaddr *)&from, sl); /* new debug: printf ("Timings: local %f, remote %f, diff %f\n", tv2ts (&time), net2ts (packet_d.clientstamp), net2ts (packet_d.clientstamp) - tv2ts (&time)); ends */ } else { xmms_log_error ("Received invalid UDP package!"); } } free (packet); return TRUE; }