Main Page   Compound List   File List   Compound Members   File Members  

control.c

00001 /* DICElib (DIstributed CAVE Engine library) 
00002  * Copyright (c) 2001 Bruno Barberi Gnecco <brunobg@lsi.usp.br>
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to
00006  * deal in the Software without restriction, including without limitation the
00007  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00008  * sell copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies of the Software, its documentation and marketing & publicity
00013  * materials, and acknowledgment shall be given in the documentation, materials
00014  * and software packages that this Software was used.
00015  *
00016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00019  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
00020  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00022  */
00023 
00024 #include "_dicelib.h"
00025 #include <string.h>
00026 #include <errno.h>
00027 #ifndef WINDOWS
00028 #include <signal.h>
00029 #include <sys/time.h>
00030 #include <sys/types.h>
00031 #include <unistd.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <netinet/tcp.h>
00035 #include <arpa/inet.h>
00036 #include <netdb.h>
00037 #else
00038 #include <winsock.h>
00039 #endif
00040 
00041 static int                      syncnum = 0;    /* # of clients that sent SYNC */
00042 static int                      readynum = 0;   /* # of clients that sent READY */
00043 static int                      fdmax;          /* maximum socket number */
00044 static fd_set                   clients;        /* list of sockets */
00045 static int                      *hierarchy;
00046 int                             packetfrom;     /* socket to the received socket */
00047 
00048 #define FUNCTION                "dice_broadcast"
00049 
00059 int dice_broadcast ( dice_packet *packet, int except ) {
00060         int                     i;
00061 
00062         _dice_debug(3, dice_printf(FUNCTION, "(%p, %d)\n", packet, except);)
00063         for ( i = 0; i <= fdmax; i++ ) {
00064                 if ( FD_ISSET(i, &clients) && i != except )
00065                          if ( dice_packet_send(packet, i) == -1 )
00066                                 return -1;
00067         }
00068         return 0;
00069 }
00070 
00074 void dice_control_byebye ( int signum ) {
00075         dice_packet             packet;
00076         int                     i;
00077 
00078         _dice_debug(3, dice_printf("dice_control_byebye", "(%d)\n", signum);)
00079         if ( signum == SIGTERM )
00080                 _dice_debug(3, dice_printf(NULL, "Control: got SIGTERM\n");)
00081 
00082         /* broadcast a goodbye packet */
00083         packet.packtype = GOODBYE;
00084         dice_broadcast(&packet, (signum == -1 ? readynum : -1));
00085 
00086 #ifdef USE_ASYNC
00087         dice_async_end();
00088 #endif
00089         dice_sync_end();
00090         if ( dice_data.clients ) {
00091                 for ( i = 0; i < dice_data.clientnum; i++ ) {
00092                         dice_free(dice_data.clients[i].address);
00093                         dice_free(dice_data.clients[i].path);
00094                         dice_free(dice_data.clients[i].function);
00095                 }
00096 /*              dice_free(dice_data.clients); segfaults, why?*/
00097         }
00098         dice_free(dice_data.color[0]);
00099         dice_free(dice_data.color[1]);
00100         dice_free(hierarchy);
00101 /*      dice_type_free_all(); segfaults, why? */
00102 
00103 #ifndef WINDOWS
00104         signal(SIGTERM, SIG_DFL);
00105 #endif
00106         exit(0);
00107 }
00108 
00109 
00119 int dice_control_hierarchy ( int a, int b ) {
00120         int                             i;
00121         
00122         if ( a == b )
00123                 return 1;
00124         for ( i = 0; i < dice_data.clientnum; i++ ) {
00125                 if ( hierarchy[i] == a )
00126                         return 0;
00127                 else if ( hierarchy[i] == b ) 
00128                         return 1;
00129         }
00130         return -1;
00131 }
00132 
00133 
00134 #undef FUNCTION
00135 #define FUNCTION                "dice_control_process"
00136 
00149 int dice_control_process ( dice_packet *packet, int from ) {
00150         dice_packet                     p;
00151         _dice_debug(3, dice_printf(FUNCTION, "(%p, %d); type %s\n", packet, from,
00152                         dice_packet_name(packet->packtype));)
00153 
00154         switch ( packet->packtype ) {
00155           case INVALID:
00156                 return 0;
00157           case SYNC:
00158                 /* get the updates */
00159                 p = dice_packet_get(from);
00160                 packetfrom = from;
00161                 while ( p.packtype == VARIABLE_SYNC ||
00162                         p.packtype == VARIABLE_FREE_SYNC ) {
00163 
00164                         if ( dice_data.original_only && hierarchy[0] != from )
00165                                 continue;
00166 
00167                         if ( p.packtype == VARIABLE_SYNC ) {
00168                                 if ( DICE_sync_update(p.variable.name, 
00169                                                 p.variable.value) == -2 )
00170                                         DICE_sync_new(p.variable.name, 
00171                                                 p.variable.type, 
00172                                                 p.variable.value );
00173                         }
00174                         else 
00175                                 DICE_sync_delete(p.variable.name);
00176                         free(p.variable.name);
00177                         free(p.variable.type);
00178                         p = dice_packet_get(from);
00179                 }
00180                 if ( p.packtype != READY ) {
00181                         _dice_debug(1, dice_printf(FUNCTION, "did not get READY, got %s instead\n",
00182                                         dice_packet_name(p.packtype));)
00183                         return -1;
00184                 }
00185 
00186                 syncnum++;
00187                 if ( syncnum == dice_data.clientnum ) { 
00188                         /* everybody sent a SYNC and is waiting. */
00189                         dice_sync_update_send();
00190 
00191                         p.packtype = SYNC;
00192                         dice_broadcast(&p, -1);
00193                         syncnum = 0;
00194                 }
00195                 return 0;
00196           case VARIABLE_ASYNC:
00197           case VARIABLE_FREE_ASYNC:
00198 #ifdef USE_ASYNC
00199                 if ( dice_data.original_only && hierarchy[0] != from ) {
00200                         DICE_async_update(packet->variable.name, packet->variable.value);
00201                         dice_broadcast(packet, from);
00202                 }
00203 #endif
00204                 return 0;
00205           case VARIABLE_SYNC:
00206           case VARIABLE_FREE_SYNC:
00207                 _dice_debug(1, dice_printf(FUNCTION, "got a lonely %s!\n", 
00208                                 dice_packet_name(p.packtype));)
00209                 return -1;
00210           case READY:
00211                 readynum++;
00212                 if ( readynum == dice_data.clientnum ) {
00213                         p.packtype = CONTINUE;
00214                         dice_broadcast(&p, -1);
00215                         readynum = 0;
00216                 }
00217                 return 0;
00218           case CONTINUE:
00219                 _dice_debug(1, dice_printf(FUNCTION, "Control should never get CONTINUE!\n");)
00220                 return -1;
00221           case GOODBYE:
00222                 /* if a client said bye, quit all of them */
00223                 readynum = from; /* except the one that sent the packet */
00224                 dice_control_byebye(-1);
00225                 return 0;
00226           case HELLO:
00227                 _dice_debug(1, dice_printf(FUNCTION, "Control should never get HELLO!\n");)
00228                 return -1;
00229         }
00230         return -1;
00231 }
00232 
00233 #undef FUNCTION
00234 #define FUNCTION                "dice_control_loop"
00235 
00244 int dice_control_loop ( int argc, char **argv ) {
00245         struct sockaddr_in      myaddr, remote;
00246         int                     sockfd, i;
00247         fd_set                  fdtemp;
00248         dice_packet             packet;
00249 
00250         _dice_debug(3, dice_printf(FUNCTION, "()\n");)
00251 
00252 #ifndef WINDOWS
00253         /* first of all, handle SIGTERM */
00254         signal(SIGTERM, dice_control_byebye);
00255 #endif
00256 
00257         FD_ZERO(&clients);
00258         FD_ZERO(&fdtemp);
00259 
00260         hierarchy = (int *)malloc(dice_data.clientnum*sizeof(int));
00261         if ( !hierarchy ) {
00262                 _dice_debug(1, dice_printf(FUNCTION, "hierarchy: %s\n", strerror(errno));)
00263                 return -1;
00264         }
00265 
00266         /* Opening socket */
00267         if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
00268                 _dice_debug(1, dice_printf(FUNCTION, "%s\n", strerror(errno));)
00269                 return -1;
00270         }
00271 
00272         /* non blocking ? 
00273         fcntl(sockfd, F_SETFL, O_NOBLOCK); */
00274 
00275         /* get rid of "address already in use" messages */
00276         i = 1;
00277         setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(int));
00278         
00279         /* TCP NODELAY */
00280         i = 1;
00281         setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(int));
00282 
00283         /* Fill out the struct sockaddr_in structure */
00284         myaddr.sin_port = htons(dice_data.port);
00285         myaddr.sin_family = AF_INET;
00286         myaddr.sin_addr.s_addr = INADDR_ANY; /* Use my IP address */
00287         memset((void *)&myaddr.sin_zero, 0, 8);
00288 
00289         /* Bind to the port */
00290         if ( bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0 ) {
00291                 _dice_debug(1, dice_printf(FUNCTION, ": %s\n", strerror(errno));)
00292                 return -1;
00293         }
00294 
00295         /* Limit connections */
00296         if ( listen(sockfd, dice_data.max_connections) < 0 ) {
00297                 _dice_debug(1, dice_printf(FUNCTION, "%s\n", strerror(errno));)
00298                 return -1;
00299         }
00300 
00301         /* accept connections from everybody. todo: timeout. */
00302         _dice_debug(3, dice_printf(FUNCTION, "waiting for %d clients.\n", dice_data.clientnum);)
00303         for ( i = 0; i < dice_data.clientnum; i++ ) {
00304                 int len = sizeof(remote), fdnew, pid;
00305 
00306                 /* distribute around the network */
00307                 if ( dice_data.spawn != NONE ) {
00308                         _dice_debug(3, dice_printf(FUNCTION, "Spawning %s...\n",
00309                                         dice_data.clients[i].address);)
00310 
00311                         argv[0] = dice_data.clients[i].address;
00312                         argv[1] = ( dice_data.clients[i].path == NULL ?
00313                                 defaultpath : dice_data.clients[i].path );
00314                         argv[3] = dice_data.controlname;
00315                         pid = fork();
00316                         if ( pid == 0 ) { /* child */
00317                                 switch ( dice_data.spawn ) {
00318                                   case RSH:
00319                                         execvp("rsh", argv);
00320                                         break;
00321                                   case SSH:
00322                                         execvp("ssh", argv);
00323                                         break;
00324                                   case BPROC:
00325                                         _dice_debug(1, dice_printf(FUNCTION, 
00326                                                         "BPROC not implemented yet");)
00327                                         /* execvp("bproc", argv); */
00328                                         break;
00329                                   default:
00330                                         break;
00331                                 }
00332                                 _dice_debug(1, dice_printf(FUNCTION, "exec: %s\n",
00333                                                 strerror(errno));)
00334                                 _exit(1);
00335                         }
00336                         if ( pid < 0 ) {
00337                                 _dice_debug(1, dice_printf(FUNCTION, "fork: %s\n",
00338                                                 strerror(errno));)
00339                                 exit(1); /*todo: should be nicer */
00340                         }
00341 
00342                 }
00343 
00344                 /* now wait for connection. todo: timeout. perhaps catching SIGCHILD? */
00345                 if ( (fdnew = accept(sockfd, (struct sockaddr *)&remote, &len)) == -1 ) {
00346                         _dice_debug(1, dice_printf(FUNCTION, 
00347                                 "error connecting: %s\n", strerror(errno));)
00348                 }
00349                 else {
00350                         struct hostent          *host;
00351                         int                     len2 = sizeof(remote.sin_addr);
00352                         char                    *name;
00353 
00354                         FD_SET(fdnew, &clients);
00355                         if ( fdnew > fdmax )
00356                                 fdmax = fdnew;
00357 
00358                         /* hierarchy is done here! */
00359                         hierarchy[i] = fdnew;
00360                         
00361                         /* Get client name */
00362                         len2 = sizeof(remote.sin_addr);
00363                         name = inet_ntoa(remote.sin_addr);
00364                         host = gethostbyaddr((char *)&remote.sin_addr, len2, AF_INET);
00365                         if ( !host ) {
00366                                 _dice_debug(1, dice_printf(FUNCTION, 
00367                                         "couldn't get host name for %s: %s\n"
00368                                         "This may lead to problems in hierarchy.\n", 
00369                                         inet_ntoa(remote.sin_addr), strerror(errno));)
00370                                 continue;
00371                         } 
00372                         _dice_debug(2, dice_printf(FUNCTION, 
00373                                 "Connection from socket %d by %s(%s)\n", fdnew,
00374                                 host->h_name, inet_ntoa(remote.sin_addr));)
00375                                         
00376                         /* and send a HELLO packet */
00377                         packet.packtype = HELLO;
00378                         packet.hello.id = (unsigned long)i;
00379                         packet.hello.function = dice_data.clients[i].function;
00380                         dice_packet_send(&packet, fdnew);
00381                 }
00382         }
00383 
00384         _dice_debug(2, dice_printf(FUNCTION, "All connected");)
00385 
00386         while ( 1 ) {
00387                 fdtemp = clients; /* copy */
00388                 if ( select(fdmax+1, &fdtemp, NULL, NULL, NULL) == -1 ) {
00389                         _dice_debug(1, dice_printf(FUNCTION, "%s\n", strerror(errno));)
00390                 }
00391 
00392                 for ( i = 0; i <= fdmax; i++ ) {
00393                         if ( FD_ISSET(i, &fdtemp) && i != sockfd ) { /* no more connections */
00394                                 /* handle */
00395                                 packet = dice_packet_get(i);
00396                                 dice_control_process(&packet, i);
00397                         }
00398                 }
00399         }
00400         return -1; /* so the compiler won't complain */
00401 }

Generated at Sun Dec 9 16:13:18 2001 for dicelib by doxygen1.2.9.1 written by Dimitri van Heesch, © 1997-2001