]> git.sesse.net Git - vlc/blob - src/input/input_vlan.c
Fin du remplacement des pthread + ajout du frame rate dans display.c.
[vlc] / src / input / input_vlan.c
1 /*******************************************************************************
2  * input_vlan.c: vlan input method
3  * (c)1999 VideoLAN
4  *******************************************************************************
5  * ?? 
6  *******************************************************************************/
7
8 /* ???????????????????????????????????????????????????????????????????????????
9  * This works (well, it should :), but should have a good place in horror museum:
10  * - the vlan-capable interfaces are retrieved from a names list, instead
11  *   of being read from the system
12  * - the vlan server sucks, and therefore the vlan clients sucks:
13  *      - it is unable to process several operations between a login and a logout
14  *        A lot of requests could be grouped if it could.
15  *      - it is incoherent concerning it's messages (and what it needs to perform
16  *        an operation
17  *      - it is totally unable to handle several mac adresses on a single switch
18  *        port (and therefore bridged/hubbed machines)
19  * - however, the API is ok, should be able to handle all futures evolutions, 
20  *   including vlan-conscient cards.
21  *
22  * So there is a lot to do in this file, but not before having reprogrammed the
23  * vlan server !
24  * What would be a good interface to the vlan server ? Here are some ideas:
25  *      ( later ! )
26  * ??????????????????????????????????????????????????????????????????????????? */
27
28 /*******************************************************************************
29  * Preamble
30  *******************************************************************************/
31 #include <errno.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <arpa/inet.h>
37 #include <net/if.h>
38 #include <netinet/in.h>
39 #include <sys/ioctl.h>
40 #include <sys/soundcard.h>
41 #include <sys/uio.h>
42 #include <X11/Xlib.h>
43 #include <X11/extensions/XShm.h>
44
45 #include "config.h"
46 #include "common.h"
47 #include "mtime.h"
48 #include "vlc_thread.h"
49 #include "netutils.h"
50
51 #include "input.h"
52 #include "input_vlan.h"
53
54 #include "audio_output.h"
55
56 #include "video.h"
57 #include "video_output.h"
58
59 #include "xconsole.h"
60 #include "interface.h"
61 #include "intf_msg.h"
62
63 #include "pgm_data.h"
64
65 /*
66  * Constants
67  */
68
69 /* List of vlan-capable interfaces names */
70 static const char *psz_ifaces_names[] = { "eth0", "eth1", "eth2", "eth3", "eth4", "eth5", NULL };
71    
72 /*
73  * Local prototypes
74  */
75 static int  IfaceInfo               ( input_vlan_iface_t *p_iface );
76 static int  IfaceDependance         ( input_vlan_method_t *p_method, int i_iface );
77 static int  ServerLogin             ( input_vlan_server_t *p_server );
78 static void ServerLogout            ( input_vlan_server_t *p_server );
79 static int  ServerRequestChange     ( input_vlan_server_t *p_server,
80                                       input_vlan_iface_t *p_iface, int i_vlan );
81 static int  ServerRequestInfo       ( input_vlan_server_t *p_server,
82                                       input_vlan_iface_t *p_iface );
83
84 /*******************************************************************************
85  * input_VlanMethodInit: initialize global vlan method data
86  *******************************************************************************
87  * Initialize vlan input method global data. This function should be called
88  * once before any input thread is created or any call to other input_Vlan*()
89  * function is attempted.
90  *******************************************************************************/
91 int input_VlanMethodInit( input_vlan_method_t *p_method, char *psz_server, int i_port )
92 {
93     int                     i_index;                /* interface/servers index */
94     input_vlan_iface_t *    p_iface;                             /* interfaces */
95
96     /* Build vlan server descriptor */
97     if( BuildInetAddr( &p_method->server.sa_in, psz_server, i_port ) )
98     {
99         return( -1 );        
100     }    
101
102     /* Allocate interfaces array */
103     for( i_index = 0; psz_ifaces_names[i_index] != NULL; i_index++ )
104     {
105         ;        
106     }    
107     p_iface = malloc( sizeof(input_vlan_iface_t) * i_index );
108     if( p_iface == NULL )
109     {        
110         return( ENOMEM );
111     }   
112
113     /* Initialize interfaces array */
114     for( i_index = p_method->i_ifaces = 0; psz_ifaces_names[i_index] != NULL; i_index++ )
115     {
116         /* Retrieve interface name */
117         p_iface[p_method->i_ifaces].psz_name = (char *) psz_ifaces_names[i_index];
118
119         /* Test if interface is vlan-capable */
120         if( !IfaceInfo( &p_iface[p_method->i_ifaces] ) )
121         {
122             /* If interface passed first step, login to vlan server */
123             if( !ServerLogin( &p_method->server ) )
124             {
125                 /* Request informations from server about the interface - if the interface
126                  * pass this last test, it is vlan-capable and can be added to the list of
127                  * interfaces. */
128                 if( !ServerRequestInfo( &p_method->server, &p_iface[p_method->i_ifaces]) )
129                 {
130                     /* Check if interface is dependant */
131                     if( !IfaceDependance( p_method, p_method->i_ifaces ) )
132                     {                        
133                         /* Interface is master: initialize properties */
134                         p_iface[p_method->i_ifaces].i_default_vlan = p_iface[p_method->i_ifaces].i_vlan;
135                         p_iface[p_method->i_ifaces].i_refcount = 0;
136                         intf_DbgMsg("input debug: added vlan-capable interface %s (%s)\n", 
137                                     p_iface[p_method->i_ifaces].psz_name, 
138                                     p_iface[p_method->i_ifaces].psz_mac);
139                     }          
140 #ifdef DEBUG
141                     else
142                     {
143                         /* Interface is slave */
144                         intf_DbgMsg("input debug: added vlan-capable interface %s (%s), depends from %s\n",
145                                     p_iface[p_method->i_ifaces].psz_name, 
146                                     p_iface[p_method->i_ifaces].psz_mac,
147                                     p_iface[p_iface[p_method->i_ifaces].i_master].psz_name );
148                     }
149 #endif
150                     /* Increment size counter */            
151                     p_method->i_ifaces++;
152                 }
153                 /* Logout from server */
154                 ServerLogout( &p_method->server );    
155             }
156         }
157     }
158
159     /* If number of vlan-capable interfaces is null, then desactivate vlans */
160     if( p_method->i_ifaces == 0 )
161     {
162         free( p_iface );        
163         return( -1 );        
164     }
165     
166     /* Reallocate interfaces array to save memory */
167     p_method->p_iface = realloc( p_iface, sizeof(input_vlan_iface_t) * p_method->i_ifaces );
168     if( p_method->p_iface == NULL )
169     {        
170         /* Realloc failed, but the previous pointer is still valid */
171         p_method->p_iface = p_iface;
172     }      
173
174     /* Initialize lock */
175     vlc_mutex_init( &p_method->lock );
176
177     intf_Msg("input: vlans input method installed\n", p_method->i_ifaces);
178     return( 0 );    
179 }
180
181 /*******************************************************************************
182  * input_VlanMethodFree: free global vlan method data
183  *******************************************************************************
184  * Free resources allocated by input_VlanMethodInit. This function should be
185  * called at the end of the program.
186  *******************************************************************************/
187 void input_VlanMethodFree( input_vlan_method_t *p_method )
188 {
189     int i_index;                                     /* server/interface index */
190
191     /* Leave all remaining vlans */
192     for( i_index = 0; i_index < p_method->i_ifaces; i_index++ )
193     {
194 #ifdef DEBUG
195         /* Check if interface is still locked */
196         if( p_method->p_iface[i_index].i_refcount )
197         {
198             intf_DbgMsg("input debug: interface %s is still vlan-locked\n", 
199                         p_method->p_iface[i_index].psz_name);
200             p_method->p_iface[i_index].i_refcount = 0;
201         }        
202 #endif
203         /* Join default (starting) vlan */
204         input_VlanJoin( VLAN_ID( i_index, p_method->p_iface[i_index].i_default_vlan ) );        
205     }    
206
207     /* Free interfaces array */
208     free( p_method->p_iface );    
209
210     intf_DbgMsg("input debug: vlan method terminated\n");
211 }
212
213 /*******************************************************************************
214  * input_VlanId: get a vlan_id for a given interface
215  *******************************************************************************
216  * Get a vlan_id given a network interface and a vlan number. If psz_iface is
217  * NULL, then the default network interface will be used. A negative value
218  * will be returned in case of error.
219  *******************************************************************************/
220 int input_VlanId( char *psz_iface, int i_vlan )
221 {
222     input_vlan_method_t *   p_method;                    /* method global data */
223     int                     i_index;                        /* interface index */
224
225     p_method = &p_program_data->input_vlan_method;
226
227     /* If psz_iface is NULL, use first (default) interface (if there is one) */
228     if( psz_iface == NULL )
229     {           
230         return( p_method->i_ifaces ? VLAN_ID( 0, i_vlan ) : -1 );    
231     }
232         
233     /* Browse all interfaces */
234     for( i_index = 0; i_index < p_program_data->input_vlan_method.i_ifaces ; i_index++ )
235     {
236         /* If interface has been found, return */
237         if( !strcmp( p_program_data->input_vlan_method.p_iface[i_index].psz_name, psz_iface ) )
238         {
239             return( VLAN_ID( i_index, i_vlan ) );
240         }        
241     }    
242     
243     return( -1 );
244 }
245
246 /*******************************************************************************
247  * input_VlanJoin: join a vlan
248  *******************************************************************************
249  * This function will try to join a vlan. If the relevant interface is already
250  * on the good vlan, nothing will be done. Else, and if possible (if the 
251  * interface is not locked), the vlan server will be contacted and a change will
252  * be requested. The function will block until the change is effective. Note
253  * that once a vlan is no more used, it's interface should be unlocked using
254  * input_VlanLeave().
255  * Non 0 will be returned in case of error.
256  *******************************************************************************/
257 int input_VlanJoin( int i_vlan_id )
258 {    
259     input_vlan_method_t *   p_method;                    /* method global data */
260     input_vlan_iface_t *    p_iface;                   /* interface (shortcut) */
261     int                     i_err;                          /* error indicator */
262
263     /* Initialize shortcuts, and use master if interface is dependant */
264     i_err = 0;    
265     p_method = &p_program_data->input_vlan_method;
266     p_iface = &p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ];
267     if( p_iface->i_master >= 0 )
268     {
269         p_iface = &p_method->p_iface[ p_iface->i_master ];     
270     }
271     
272     /* Get lock */
273     vlc_mutex_lock( &p_method->lock );
274     
275     /* If the interface is in the wished vlan, increase lock counter */
276     if( p_iface->i_vlan != VLAN_ID_VLAN( i_vlan_id ) )
277     {
278         p_iface->i_refcount++;         
279     }
280     /* If not, if it is not locked, the vlan can be changed */
281     else if( !p_iface->i_refcount )
282     {        
283         /* Login to server */
284         if( (i_err = !ServerLogin( &p_method->server )) )
285         {
286
287             /* Request vlan change */
288             if( (i_err = !ServerRequestChange( &p_method->server, 
289                                                p_iface, VLAN_ID_VLAN( i_vlan_id ) ) ) )
290             {
291                 p_iface->i_refcount++;   
292             }            
293             /* Logout */
294             ServerLogout( &p_method->server );
295         }
296     }
297     /* Else, the vlan is locked and can't be changed */
298     else
299     {
300         i_err = 1;
301     }                    
302
303     /* Release lock (if this point is reached, the function succeeded) */
304     vlc_mutex_unlock( &p_method->lock );       
305     return( i_err );    
306 }
307
308 /*******************************************************************************
309  * input_VlanLeave: leave a vlan
310  *******************************************************************************
311  * This function tells the vlan library that the designed interface is no more
312  * locked and than vlan changes can occur.
313  *******************************************************************************/
314 void input_VlanLeave( int i_vlan_id )
315 {
316     input_vlan_method_t *   p_method;                    /* method global data */
317     input_vlan_iface_t *    p_iface;                   /* interface (shortcut) */
318     int                     i_err;                          /* error indicator */
319
320     /* Initialize shortcuts, and use master if interface is dependant */
321     i_err = 0;    
322     p_method = &p_program_data->input_vlan_method;
323     p_iface = &p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ];
324     if( p_iface->i_master >= 0 )
325     {
326         p_iface = &p_method->p_iface[ p_iface->i_master ];     
327     }
328     
329     /* Get lock */
330     vlc_mutex_lock( &p_method->lock );
331
332     /* Decrease reference counter */
333     p_method->p_iface[ VLAN_ID_IFACE( i_vlan_id ) ].i_refcount--;    
334
335     /* Release lock */
336     vlc_mutex_unlock( &p_method->lock );   
337 }
338
339 /*******************************************************************************
340  * input_VlanRequest: request vlan number for a given interface
341  *******************************************************************************
342  * Request the vlan number (and not id) of a given network interface. A 
343  * connection to the server can eventually occur, event if it not the case in
344  * current implementation. A negative number can be returned on error.
345  *******************************************************************************/
346 int input_VlanRequest( char *psz_iface )
347 {
348     input_vlan_method_t *   p_method;                    /* method global data */
349     int                     i_index;                        /* interface index */
350     
351     p_method = &p_program_data->input_vlan_method;
352
353     /* If psz_iface is NULL, use first (default) interface (if there is one) - 
354      * note that interface 0 can't be dependant, so dependance does not need
355      * to be tested */
356     if( psz_iface == NULL )
357     {           
358         return( p_method->i_ifaces ? p_method->p_iface[0].i_vlan : -1 );    
359     }
360         
361     /* Browse all interfaces */
362     for( i_index = 0; i_index < p_method->i_ifaces ; i_index++ )
363     {
364         /* If interface has been found, return vlan */
365         if( !strcmp( p_method->p_iface[i_index].psz_name, psz_iface ) )
366         {
367             /* If interface is dependant, use master, else return own vlan */
368             return( (p_method->p_iface[i_index].i_master >= 0) ?
369                     p_method->p_iface[p_method->p_iface[i_index].i_master].i_vlan :
370                     p_method->p_iface[i_index].i_vlan );
371         }        
372     }    
373
374     /* If not found, return an error */
375     return( -1 );    
376 }
377
378 /*******************************************************************************
379  * input_VlanSynchronize: resynchronize with vlan server
380  *******************************************************************************
381  * Resynchronize with the vlan server. Vlans for all interfaces are requested
382  * and changed if required. This call may take a lot of time, and is intended
383  * for emergency situations.
384  *******************************************************************************/
385 int input_VlanSynchronize( void )
386 {
387     input_vlan_method_t *   p_method;                    /* method global data */
388     input_vlan_iface_t *    p_iface;                   /* interface (shortcut) */
389     int                     i_index;                        /* interface index */
390     int                     i_vlan;              /* vlan for current interface */
391     
392     /* Get lock */
393     p_method = &p_program_data->input_vlan_method;
394     vlc_mutex_lock( &p_method->lock );
395
396     for( i_index = 0; i_index < p_method->i_ifaces; i_index++ )
397     {        
398         p_iface = &p_method->p_iface[ i_index ];
399         
400         /* Ignore dependant interfaces and interfaces for wich login failed */
401         if( (p_iface->i_master < 0) && !ServerLogin( &p_method->server ) )
402         {            
403             /* Request interface informations */
404             i_vlan = p_iface->i_vlan;
405             if( !ServerRequestInfo( &p_method->server, p_iface ) )
406             {
407                 /* If synchronization has been lost, then try to resynchronize -
408                  * this part is ugly because of the vlan server bug requiring a 
409                  * logout between two requests */
410                 if( p_iface->i_vlan != i_vlan )
411                 {
412                     intf_Msg("input: lost vlan synchronization for interface %s\n", 
413                              p_iface->psz_name );                    
414                     ServerLogout( &p_method->server );
415                     if( !ServerLogin( &p_method->server ) )
416                     {
417                         if( !ServerRequestChange( &p_method->server, p_iface, i_vlan ) )
418                         {
419                             intf_Msg("input: retrieved vlan synchronization for interface %s\n", 
420                                      p_iface->psz_name );          
421                         }                        
422                     }
423                     /* Note that when this login fails, then the next logout will
424                      * also fail... but I don't want to spend time finding a 
425                      * clean way to avoid this if the vlan server bug is fixed */
426                 }                                
427             }            
428             /* Logout */
429             ServerLogout( &p_method->server );            
430         }        
431     }    
432
433     /* Release lock */
434     vlc_mutex_unlock( &p_method->lock );   
435     return( 0 );    
436 }
437
438 /* following functions are local */
439
440 /*******************************************************************************
441  * IfaceInfo: read info about an interface
442  *******************************************************************************
443  * This function reads informations about a network interface. It should return
444  * 0 and updated interface informations for vlan capable interfaces, and non 0
445  * if interface is not vlan-capable or informations request failed.
446  *******************************************************************************/
447 static int IfaceInfo( input_vlan_iface_t *p_iface )
448 {
449     int             i_socket;
450     struct ifreq    device;
451
452     /* Copy interface name */
453     strcpy(device.ifr_name, p_iface->psz_name);
454
455     /* Open a datagram socket */
456     i_socket = socket(AF_INET, SOCK_DGRAM, 0);
457     if(i_socket < 0)
458     {
459         intf_ErrMsg("input error: unable to open socket on %s: %s\n", 
460                     p_iface->psz_name, strerror(errno));
461         return( -1 );        
462     }
463
464     /* Read IP address */
465     if(ioctl(i_socket, SIOCGIFDSTADDR, &device) < 0)
466     {
467         intf_ErrMsg("input error: can not read IP address for %s: %s\n", 
468                     p_iface->psz_name, strerror(errno));
469         return( -1 );
470     }
471     memcpy( &p_iface->sa_in, &device.ifr_hwaddr, sizeof(struct sockaddr_in));
472
473     /* Read MAC address */
474     if(ioctl(i_socket, SIOCGIFHWADDR, &device) < 0)
475     {
476         intf_ErrMsg("input error: can not read MAC address for %s: %s\n",
477                     p_iface->psz_name, strerror(errno));
478         return( -1 );
479     }
480
481     /* Translate MAC address to ASCII standard */
482     sprintf(p_iface->psz_mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
483             device.ifr_hwaddr.sa_data[0]&0xff,
484             device.ifr_hwaddr.sa_data[1]&0xff,
485             device.ifr_hwaddr.sa_data[2]&0xff,
486             device.ifr_hwaddr.sa_data[3]&0xff,
487             device.ifr_hwaddr.sa_data[4]&0xff,
488             device.ifr_hwaddr.sa_data[5]&0xff);
489
490     return( 0 );
491 }
492
493 /*******************************************************************************
494  * IfaceDependance: check interface dependance
495  *******************************************************************************
496  * Check if an interface designed by it's index is dependant from another one.
497  * All the interfaces from 0 to i_index excluded are tested. If a 'master'  
498  * interface is found, then the 'i_master' field is set to a positive value.
499  * Non 0 is returned if the interface is dependant.
500  *******************************************************************************/
501 static int IfaceDependance( input_vlan_method_t *p_method, int i_iface )
502 {
503     int i_index;                                            /* interface index */
504     
505     for( i_index = 0; i_index < i_iface; i_index++ )
506     {
507         /* Two interface are dependant if they are on the same switch and
508          * port */
509         if( ( p_method->p_iface[i_index].i_switch == p_method->p_iface[i_iface].i_switch )
510             && ( p_method->p_iface[i_index].i_port == p_method->p_iface[i_iface].i_port ) )
511         {
512             /* Interface is slave */
513             p_method->p_iface[i_iface].i_master = i_index;
514             return( 1 );            
515         }        
516     }
517
518     /* Interface is master */
519     p_method->p_iface[i_iface].i_master = -1;    
520     return( 0 );    
521 }
522
523 /*******************************************************************************
524  * ServerLogin: login to a vlan server
525  *******************************************************************************
526  * Initiate login sequence to a vlan server: open a socket, bind it and send
527  * login sequence. If the login fails for any reason, non 0 is returned.
528  *******************************************************************************/
529 static int ServerLogin( input_vlan_server_t *p_server )
530 {
531     struct sockaddr_in  sa_client;                           /* client address */
532     char                psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];/* server message */
533     int                 i_bytes;                       /* number of bytes read */    
534
535     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
536
537     /* Initialize local socket */
538     BuildInetAddr( &sa_client, NULL, 0 );
539     p_server->i_socket = socket(AF_INET, SOCK_STREAM, 0);
540     if( p_server->i_socket < 0 )
541     {
542         /* Error: return an error */
543         intf_ErrMsg("input error: can not open socket (%s)\n", strerror(errno));
544         return( errno );
545     }
546            
547     /* Bind the server socket to client */
548     if( bind( p_server->i_socket, (struct sockaddr *) &sa_client, sizeof(sa_client)) < 0)
549     {
550         /* Error: close socket and return an error */
551         intf_ErrMsg("input error: can not bind socket (%s)\n", strerror(errno));        
552         close( p_server->i_socket );
553         return( errno );
554     }
555
556     /* Try to connect to the VLANserver */
557     if( connect( p_server->i_socket, (struct sockaddr *) &p_server->sa_in, 
558                  sizeof(p_server->sa_in)) < 0)
559     {
560         /* Error: close socket and return an error */
561         intf_ErrMsg("input error: unable to connect to the VLAN server (%s)\n", 
562                     strerror(errno));
563         close( p_server->i_socket );
564         return( errno );        
565     }
566
567     /* Send login message */
568     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d %s %s %s\n", 
569              VLAN_LOGIN_REQUEST, VLAN_CLIENT_VERSION, 
570              p_server->psz_login, p_server->psz_passwd );
571     if( send(p_server->i_socket, psz_msg, sizeof(char) * strlen( psz_msg ), 0) < 0)
572     {
573         intf_ErrMsg("input error: unable to login to the VLANserver: %s", 
574                     strerror(errno));
575         close( p_server->i_socket );
576         return( errno );        
577     }
578
579     /* Listen to response */
580     i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
581     if( i_bytes < 0 )
582     {        
583         intf_ErrMsg("input error: no response from VLANserver: %s\n",
584                     strerror(errno));
585         ServerLogout( p_server );
586         return( -1 );
587     }
588
589     /* Parse answer to login request */
590     psz_msg[ i_bytes ] = '\0';                         /* terminate string */    
591     if( atoi(psz_msg) == VLAN_LOGIN_REJECTED )
592     {
593         intf_ErrMsg("input error: login rejected by VLANserver: %s\n", psz_msg);
594         ServerLogout( p_server );
595         return( -1 );        
596     }
597     else if( atoi(psz_msg) != VLAN_LOGIN_ANSWER )
598     {
599         intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
600         ServerLogout( p_server );
601         return( -1 );        
602     }
603     
604     intf_DbgMsg("input debug: VLANserver login ok.\n");    
605     return 0;
606 }
607
608 /*******************************************************************************
609  * ServerLogout: logout from a vlan server
610  *******************************************************************************
611  * Logout from a vlan server. This function sends the logout message to the
612  * server and close the socket.
613  *******************************************************************************/
614 static void ServerLogout( input_vlan_server_t *p_server )
615 {
616     char    psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];            /* server message */
617
618     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
619
620     /* Send logout */
621     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d\n", VLAN_LOGOUT);
622     if( send(p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
623     {
624         intf_ErrMsg("input error: can't send logout message to VLANserver: %s\n", 
625                     strerror(errno));
626     }
627   
628     /* Close socket */
629     if( close(p_server->i_socket) < 0)
630     {
631         intf_ErrMsg("input error: unable to close socket: %s\n", strerror(errno));
632     }
633
634     intf_DbgMsg("input debug: VLANserver logout ok\n");    
635 }
636
637 /*******************************************************************************
638  * ServerRequestChange: request vlan change from a server
639  *******************************************************************************
640  * Request vlan change from a vlan server. The client must be logged in. If the
641  * change succeeded, the interface structure is updated. Note that only masters
642  * should be sent to this function.
643  *******************************************************************************/
644 static int ServerRequestChange( input_vlan_server_t *p_server, 
645                                 input_vlan_iface_t *p_iface, int i_vlan )
646 {
647     char    psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];            /* server message */
648     int     i_bytes;                                   /* number of bytes read */
649           
650     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
651
652     /* Send request */
653     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d %s %s %d %d", 
654              VLAN_CHANGE_REQUEST, p_iface->psz_mac, 
655              inet_ntoa(p_iface->sa_in.sin_addr), i_vlan, p_iface->i_vlan);
656     if( send( p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
657     {
658         intf_ErrMsg("input error: unable to send request to VLANserver: %s\n", 
659                     strerror(errno));        
660         return( -1 );
661     }
662
663     /* Listen to response */
664     i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
665     if( i_bytes < 0 )
666     {        
667         intf_ErrMsg("input error: no response from VLANserver: %s",
668                     strerror(errno));
669         return( -1 );
670     }
671
672     /* Parse answer to vlan request */
673     psz_msg[ i_bytes ] = '\0';                         /* terminate string */    
674     if( atoi( psz_msg ) == VLAN_CHANGE_REJECTED )
675     {
676         intf_ErrMsg("input error: change request rejected by VLANserver: %s\n", psz_msg );
677         return( -1 );      
678     }
679     else if( atoi( psz_msg ) != VLAN_CHANGE_ANSWER )
680     {
681         intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
682         return( -1 );                
683     }
684
685     /* ?? send packet for the switch to learn mac again */
686
687     /* Update interface and return */
688     intf_DbgMsg("input debug: interface %s moved to vlan %d\n", 
689                 p_iface->psz_name, i_vlan );   
690     p_iface->i_vlan = i_vlan;    
691     return( 0 ); 
692 }
693
694 /*******************************************************************************
695  * ServerRequestInfo: ask current vlan to server
696  *******************************************************************************
697  * Request current vlan from a vlan server. The client must be logged in. This
698  * function updates the p_iface structure or returns non 0. Note that only
699  * masters should be sent to this function.
700  *******************************************************************************/
701 static int ServerRequestInfo( input_vlan_server_t *p_server, 
702                               input_vlan_iface_t *p_iface )
703 {
704     char    psz_msg[VLAN_SERVER_MSG_LENGTH  + 1];            /* server message */
705     int     i_bytes;                                   /* number of bytes read */
706     int     i_switch;                                         /* switch number */
707     int     i_port;                                             /* port number */
708     int     i_vlan;                                             /* vlan number */
709     int     i_sharers;                 /* number of mac addresses on this port */    
710           
711     psz_msg[VLAN_SERVER_MSG_LENGTH] = '\0';       /* make sure the string ends */
712
713     /* Send request */
714     snprintf(psz_msg, VLAN_SERVER_MSG_LENGTH, "%d", VLAN_INFO_REQUEST);
715     if( send( p_server->i_socket, psz_msg, sizeof(char) * strlen(psz_msg), 0) < 0)
716     {
717         intf_ErrMsg("input error: unable to send request to VLANserver: %s\n", 
718                     strerror(errno));        
719         return( -1 );
720     }
721
722     /* Listen to response */
723     i_bytes = recv(p_server->i_socket, psz_msg, VLAN_SERVER_MSG_LENGTH, 0);
724     if( i_bytes < 0 )
725     {        
726         intf_ErrMsg("input error: no response from VLANserver: %s",
727                     strerror(errno));
728         return( -1 );
729     }
730
731     /* Parse answer to vlan request */
732     psz_msg[ i_bytes ] = '\0';                         /* terminate string */    
733     if( atoi( psz_msg ) == VLAN_INFO_REJECTED )
734     {
735         intf_ErrMsg("input error: info request rejected by VLANserver: %s\n", psz_msg );
736         return( -1 );      
737     }
738     else if( atoi( psz_msg ) != VLAN_INFO_ANSWER )
739     {
740         intf_ErrMsg("input error: unexpected answer from VLAN server: %s\n", psz_msg);
741         return( -1 );                
742     }
743     else if( sscanf(psz_msg, "%*d %d %d %d %d", &i_switch, &i_port, &i_vlan, &i_sharers) != 4 )
744     {
745         intf_ErrMsg("input error: invalid answer from VLAN server: %s\n", psz_msg);
746         return( -1 );                        
747     }
748
749     /* Update interface and return */
750     intf_DbgMsg("input debug: interface %s is on switch %d, port %d, vlan %d, %d sharers\n", 
751                 p_iface->psz_name, i_switch, i_port, i_vlan, i_sharers);    
752     p_iface->i_switch = i_switch;    
753     p_iface->i_port = i_port;    
754     p_iface->i_vlan = i_vlan;    
755     p_iface->i_sharers = i_sharers;    
756     return( 0 );    
757 }
758
759
760
761