1919#include "common.h"
2020
2121static gboolean
22- udpwatcher (GIOChannel * src , GIOCondition cond , xmms_visualization_t * vis )
22+ udpwatcher (GIOChannel * src , GIOCondition cond , xmms_vis_server_t * s )
2323{
2424 struct sockaddr_storage from ;
2525 socklen_t sl = sizeof (from );
2626 xmmsc_vis_udp_timing_t packet_d ;
2727 char * packet = packet_init_timing (& packet_d );
28- if ((recvfrom (vis -> socket , packet , packet_d .size , 0 , (struct sockaddr * )& from , & sl )) > 0 ) {
28+ if ((recvfrom (s -> socket , packet , packet_d .size , 0 , (struct sockaddr * )& from , & sl )) > 0 ) {
2929 if (* packet_d .__unaligned_type == 'H' ) {
3030 xmms_vis_client_t * c ;
3131 int32_t id ;
3232
3333 XMMSC_VIS_UNALIGNED_READ (id , packet_d .__unaligned_id , int32_t );
3434 id = ntohl (id );
3535
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 );
36+ g_mutex_lock (& s -> vis -> clientlock );
4337 c = get_client (id );
4438 if (!c || c -> type != VIS_UDP ) {
45- g_mutex_unlock (& vis -> clientlock );
39+ g_mutex_unlock (& s -> vis -> clientlock );
4640 return TRUE;
4741 }
4842 /* save client address according to id */
4943 memcpy (& c -> transport .udp .addr , & from , sizeof (from ));
44+ c -> server = s ;
5045 c -> transport .udp .socket [0 ] = 1 ;
5146 c -> transport .udp .grace = 2000 ;
52- g_mutex_unlock (& vis -> clientlock );
47+ g_mutex_unlock (& s -> vis -> clientlock );
5348 } else if (* packet_d .__unaligned_type == 'T' ) {
5449 struct timeval time ;
5550 xmms_vis_client_t * c ;
@@ -58,15 +53,15 @@ udpwatcher (GIOChannel *src, GIOCondition cond, xmms_visualization_t *vis)
5853 XMMSC_VIS_UNALIGNED_READ (id , packet_d .__unaligned_id , int32_t );
5954 id = ntohl (id );
6055
61- g_mutex_lock (& vis -> clientlock );
56+ g_mutex_lock (& s -> vis -> clientlock );
6257 c = get_client (id );
6358 if (!c || c -> type != VIS_UDP ) {
64- g_mutex_unlock (& vis -> clientlock );
59+ g_mutex_unlock (& s -> vis -> clientlock );
6560 free (packet );
6661 return TRUE;
6762 }
6863 c -> transport .udp .grace = 2000 ;
69- g_mutex_unlock (& vis -> clientlock );
64+ g_mutex_unlock (& s -> vis -> clientlock );
7065
7166 /* give pong */
7267 gettimeofday (& time , NULL );
@@ -90,11 +85,7 @@ udpwatcher (GIOChannel *src, GIOCondition cond, xmms_visualization_t *vis)
9085 XMMSC_VIS_UNALIGNED_WRITE (& packet_d .__unaligned_serverstamp [1 ],
9186 (int32_t )htonl (sts .tv_usec ), int32_t );
9287
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 */
88+ sendto (s -> socket , packet , packet_d .size , 0 , (struct sockaddr * )& from , sl );
9889 } else {
9990 xmms_log_error ("Received invalid UDP package!" );
10091 }
@@ -111,52 +102,93 @@ init_udp (xmms_visualization_t *vis, int32_t id, xmms_error_t *err)
111102 xmms_vis_client_t * c ;
112103
113104 // setup socket if needed
114- if (!xmms_socket_valid (vis -> socket )) {
105+ // TODO: isn't there a race of multiple clients tying to bind()?
106+ if (vis -> serverv == NULL ) {
115107 struct addrinfo hints ;
116108 struct addrinfo * result , * rp ;
117- int s ;
109+ int status ;
110+
111+ int32_t possible_servers = 0 ;
112+ int32_t opened_servers = 0 ;
113+ int32_t i ;
114+ xmms_vis_server_t * servers = NULL ;
118115
119116 memset (& hints , 0 , sizeof (hints ));
120117 hints .ai_family = AF_UNSPEC ;
121118 hints .ai_socktype = SOCK_DGRAM ;
122119 hints .ai_flags = AI_PASSIVE ;
123120 hints .ai_protocol = 0 ;
124121
125- if ((s = getaddrinfo (NULL , G_STRINGIFY (XMMS_DEFAULT_UDP_PORT ), & hints , & result )) != 0 )
122+ if ((status = getaddrinfo (NULL , G_STRINGIFY (XMMS_DEFAULT_UDP_PORT ), & hints , & result )) != 0 )
126123 {
127- xmms_log_error ("Could not setup socket! getaddrinfo: %s" , gai_strerror (s ));
124+ xmms_log_error ("Could not setup socket! getaddrinfo: %s" , gai_strerror (status ));
128125 xmms_error_set (err , XMMS_ERROR_NO_SAUSAGE , "Could not setup socket!" );
129126 return -1 ;
130127 }
131128
132129 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 )) {
130+ possible_servers ++ ;
131+ }
132+ servers = g_new0 (xmms_vis_server_t , possible_servers );
133+ if (servers == NULL ) {
134+ xmms_log_error ("Could not allocate memory!" );
135+ xmms_error_set (err , XMMS_ERROR_NO_SAUSAGE , "Could not allocate memory!" );
136+ freeaddrinfo (result );
137+ return -1 ;
138+ }
139+
140+ for (rp = result ; rp != NULL ; rp = rp -> ai_next ) {
141+ int sock ;
142+ xmms_vis_server_t * s = & servers [opened_servers ];
143+
144+ sock = socket (rp -> ai_family , rp -> ai_socktype , rp -> ai_protocol );
145+ if (!xmms_socket_valid (sock )) {
135146 continue ;
136147 }
137- if (bind (vis -> socket , rp -> ai_addr , rp -> ai_addrlen ) != -1 ) {
138- break ;
139- } else {
140- close (vis -> socket );
148+ if (bind (sock , rp -> ai_addr , rp -> ai_addrlen ) == -1 ) {
149+ /* In case we already bound v4 socket
150+ * and v6 are attempting to set up
151+ * dual-stack v4+v6. Try again v6-only
152+ * mode. */
153+ if (rp -> ai_family == AF_INET6 && errno == EADDRINUSE ) {
154+ int v6only = 1 ;
155+ if (setsockopt (sock , IPPROTO_IPV6 , IPV6_V6ONLY , & v6only , sizeof (v6only )) == -1 ) {
156+ close (socket );
157+ continue ;
158+ }
159+ if (bind (sock , rp -> ai_addr , rp -> ai_addrlen ) == -1 ) {
160+ close (socket );
161+ continue ;
162+ }
163+ } else {
164+ close (socket );
165+ continue ;
166+ }
141167 }
168+ opened_servers ++ ;
169+ s -> socket = sock ;
142170 }
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 !" );
171+ if (opened_servers == 0 ) {
172+ xmms_log_error ("Could not bind any vis sockets !" );
173+ xmms_error_set (err , XMMS_ERROR_NO_SAUSAGE , "Could not bind any vis sockets !" );
146174 freeaddrinfo (result );
147175 return -1 ;
148176 }
149177 freeaddrinfo (result );
150178
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 );
179+ for (i = 0 ; i < opened_servers ; i ++ ) {
180+ xmms_vis_server_t * s = & servers [i ];
181+ /* register into mainloop: */
182+ // TODO: on windows
183+ // vis->socketio = g_io_channel_win32_new_socket (vis->socket);
184+ s -> socketio = g_io_channel_unix_new (s -> socket );
185+ s -> vis = vis ;
186+ g_io_channel_set_encoding (s -> socketio , NULL , NULL );
187+ g_io_channel_set_buffered (s -> socketio , FALSE);
188+ g_io_add_watch (s -> socketio , G_IO_IN , (GIOFunc ) udpwatcher , s );
189+ }
190+ vis -> serverc = opened_servers ;
191+ vis -> serverv = servers ;
160192 }
161193
162194 /* set up client structure */
0 commit comments