Main Page   Compound List   File List   Compound Members   File Members  

sync.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 "hash.h"
00026 #include <string.h>
00027 #include <signal.h>
00028 #include <fcntl.h>
00029 
00030 
00031 static HashTable dice_sync_var;
00032 extern int packetfrom;
00033 
00034 /*
00035  * List to store operations
00036  */
00037 struct dice_sync_var_item {
00038         struct dice_sync                *ds;
00039         struct dice_sync_var_item       *next;
00040 };
00041 
00042 static struct dice_sync_var_item *sync_head, *sync_last;
00043 
00044 #define dice_sync_add_to_list(ds)       \
00045         item = (struct dice_sync_var_item *)malloc(sizeof(struct dice_sync_var_item)); \
00046         if ( !item ) { \
00047                 _dice_debug(1, dice_printf(FUNCTION, "NULL malloc 2\n");) \
00048                 free(ds); \
00049                 return -1; \
00050         } \
00051         item->ds = ds; \
00052         item->next = NULL; \
00053         if ( !sync_head ) \
00054                 sync_head = item; \
00055         if ( sync_last ) \
00056                 sync_last->next = item; \
00057         sync_last = item;
00058 
00062 enum dice_variable_state {
00063         UPTODATE,                               
00064         CHANGED,                                
00065         CREATED,                                
00066         DELETED                                 
00067 };
00068 
00072 struct dice_sync {
00073         char                    *name;          
00074         char                    *type;          
00075         void                    *value;         
00076         void                    *nextvalue;     
00077         enum dice_variable_state        state;  
00079         /* server only */
00080         int                     owner;          
00081         int                     changedby;      
00082 };
00083 
00088 void dice_sync_free ( void *data ) {
00089         struct dice_sync        *ds;
00090         if ( !data )
00091                 return;
00092 
00093         ds = data;
00094         dice_free(ds->name);
00095         DICE_type_free(ds->type, ds->value);
00096 //      DICE_type_free(ds->type, ds->nextvalue);
00097         dice_free(ds->type);
00098         free(ds);
00099 }
00100 
00104 int dice_sync_init ( void ) {
00105         if ( hash_init(&dice_sync_var, 128, NULL) == -1 )
00106                 return -1;
00107         sync_head = NULL;
00108         sync_last = NULL;
00109         return 0;
00110 }
00111 
00115 void dice_sync_end ( void ) {
00116         struct dice_sync_var_item               *item, *tmp;
00117         if ( sync_head )
00118                 for ( item = sync_head; item != NULL; ) {
00119                         if ( item->ds->state == CREATED )
00120                                 free(item->ds);
00121                         tmp = item->next;
00122                         free(item);
00123                         item = tmp;
00124                 }
00125         hash_free(&dice_sync_var, dice_sync_free);
00126 }
00127 
00128 #define FUNCTION                "dice_sync_update_send"
00129 
00134 void dice_sync_update_send ( void ) {
00135         struct dice_sync_var_item       *item, *tmp;
00136         dice_packet                     packet;
00137 
00138         _dice_debug(3, dice_printf(FUNCTION, "()\n");)
00139 
00140         for ( item = sync_head; item != NULL; item = item->next ) {
00141                 switch ( item->ds->state ) {
00142                   case CREATED:
00143                   case CHANGED:
00144                         packet.packtype = VARIABLE_SYNC;
00145                         packet.variable.name = item->ds->name;
00146                         packet.variable.type = item->ds->type;
00147                         packet.variable.value = (item->ds->state == CREATED ?
00148                                         item->ds->value : item->ds->nextvalue );
00149                         if ( dice_is_server() ) {
00150                                 dice_broadcast(&packet, -1);
00151                                 item->ds->state = UPTODATE;
00152                         }
00153                         else
00154                                 dice_packet_send(&packet, dice_data.controlsock);
00155                         break;
00156                   case DELETED:
00157                         packet.packtype = VARIABLE_FREE_SYNC;
00158                         packet.variable_free.name = item->ds->name;
00159                         if ( dice_is_server() )
00160                                 dice_broadcast(&packet, -1);
00161                         else
00162                                 dice_packet_send(&packet, dice_data.controlsock);
00163                         break;
00164                   case UPTODATE:
00165                         break;
00166                 }
00167         }
00168 
00169         /* garbage collection */
00170         for ( item = sync_head; item != NULL; ) {
00171                 if ( item->ds->state == CREATED ) {
00172                         dice_free(item->ds->name);
00173                         dice_free(item->ds->type);
00174                         free(item->ds);
00175                 }
00176                 else {
00177                         item->ds->nextvalue = NULL;
00178                         if ( dice_is_server() )
00179                                 item->ds->changedby = -1;
00180                 }
00181                 tmp = item;
00182                 item = item->next;
00183                 free(tmp);
00184         }
00185         sync_head = sync_last = NULL;
00186 }
00187 
00188 #undef FUNCTION
00189 #define FUNCTION                "dice_sync_new"
00190 
00203 int dice_sync_new ( char *name, char *type, void *value, 
00204                                 enum dice_variable_state state ) {
00205         struct dice_sync                *ds;
00206         struct dice_sync_var_item       *item;
00207         int                             exists = 0;
00208 
00209         _dice_debug(3, dice_printf(FUNCTION, "(%s,%s,%p)\n",
00210                         name, type, value);)
00211 
00212         if ( !name ) {
00213                 _dice_debug(1, dice_printf(FUNCTION, "Invalid name\n");)
00214                 return -1;
00215         }
00216         
00217         if ( !dice_type_is_valid(type) ) {
00218 #if 0
00219                 if ( DICE_type_register(type) == -1 ) {
00220                         _dice_debug(1, dice_printf(FUNCTION, "Couldn't register type.\n");)
00221                         return -1;
00222                 }
00223 #endif
00224                 _dice_debug(1, dice_printf(FUNCTION, "Invalid type %s.\n", type);)
00225                 return -1;
00226         }
00227         for ( item = sync_head; item != NULL; item = item->next )
00228                 if ( strcmp(item->ds->name, name) == 0 ) {
00229                         exists = 1;
00230                         break;
00231                 }
00232 
00233         if ( (ds = hash_data(&dice_sync_var, name)) != NULL || exists ) {
00234                 _dice_debug(2, dice_printf(FUNCTION, "Variable exists\n");)
00235                 return -2;
00236         }
00237         
00238         ds = (struct dice_sync *)malloc(sizeof(struct dice_sync));
00239         if ( !ds ) {
00240                 _dice_debug(1, dice_printf(FUNCTION, "NULL malloc\n");)
00241                 return -1;
00242         }
00243 
00244         ds->name = strdup(name);
00245         if ( !ds->name ) {
00246                 _dice_debug(1, dice_printf(FUNCTION, "NULL strdup\n");)
00247                 return -1;
00248         }
00249         ds->type = strdup(type);
00250         if ( !ds->type ) {
00251                 _dice_debug(1, dice_printf(FUNCTION, "NULL strdup2\n");)
00252                 return -1;
00253         }
00254         ds->value = value;
00255         ds->nextvalue = NULL;
00256 
00257         if ( state == CREATED ) {
00258                 ds->state = CREATED;
00259                 dice_sync_add_to_list(ds);
00260                 if ( dice_is_server() ) {
00261                         ds->owner = ds->changedby = packetfrom;
00262                         hash_insert(&dice_sync_var, ds->name, ds);
00263                 }
00264         }
00265         else if ( state == UPTODATE ) {
00266                 ds->nextvalue = NULL;
00267                 ds->state = UPTODATE;
00268                 hash_insert(&dice_sync_var, ds->name, ds);
00269         } else {
00270                 _dice_debug(1, dice_printf(FUNCTION, "Wrong state!\n");)
00271                 /* clean */
00272                 return -1;
00273         }
00274 
00275         return 0;
00276 }
00277 
00278 #undef FUNCTION
00279 #define FUNCTION                "dice_sync_delete"
00280 
00288 void dice_sync_delete ( char *name ) {
00289         struct dice_sync                *ds;
00290 
00291         _dice_debug(3, dice_printf(FUNCTION, "(%s)\n", name);)
00292 
00293         if ( !name ) {
00294                 _dice_debug(2, dice_printf(FUNCTION, "NULL name.\n");)
00295                 return;
00296         }
00297         ds = hash_del(&dice_sync_var, name);
00298         if ( !ds ) {
00299                 _dice_debug(2, dice_printf(FUNCTION, "variable not found.\n");)
00300                 return;
00301         }
00302 
00303         dice_sync_free((void *)ds);
00304 }
00305 
00306 #undef FUNCTION
00307 #define FUNCTION                "dice_sync_update"
00308 
00316 void dice_sync_update ( char *name, char *type, void *value ) {
00317         struct dice_sync                *ds;
00318 
00319         _dice_debug(3, dice_printf(FUNCTION, "(%s)\n", name);)
00320 
00321         if ( !name || !dice_type_is_valid(type)) {
00322                 _dice_debug(2, dice_printf(FUNCTION, "NULL name or invalid type.\n");)
00323                 return;
00324         }
00325         ds = (struct dice_sync *)hash_data(&dice_sync_var, name);
00326         if ( !ds ) {
00327                 dice_sync_new(name, type, value, UPTODATE);
00328                 return;
00329         }
00330 
00331         DICE_type_free(type, ds->value);
00332         if ( ds->nextvalue )
00333                 DICE_type_free(type, ds->nextvalue); 
00334         ds->nextvalue = NULL;
00335         ds->value = value;
00336         ds->state = UPTODATE;
00337         return;
00338 }
00339 
00340 /*
00341  * Public functions
00342  */
00343 
00344 #undef FUNCTION
00345 #define FUNCTION                "DICE_sync_new"
00346 
00360 int DICE_sync_new ( char *name, char *type, void *value ) {
00361         if ( !dice_is_server() && dice_data.original_only == 1 && 
00362                         dice_data.id != 0 )
00363                 return -3;
00364         return dice_sync_new(name, type, value, CREATED);
00365 }
00366 
00367 #undef FUNCTION
00368 #define FUNCTION                "DICE_sync_delete"
00369 
00381 int DICE_sync_delete ( char *name ) {
00382         struct dice_sync                *ds;
00383         struct dice_sync_var_item       *item;
00384 
00385         _dice_debug(3, dice_printf(FUNCTION, "(%s)\n", name);)
00386 
00387         if ( dice_data.original_only == 1 && dice_data.id != 0 )
00388                 return -3;
00389 
00390         if ( !name ) {
00391                 _dice_debug(2, dice_printf(FUNCTION, "NULL name.\n");)
00392                 return -1;
00393         }
00394         ds = (struct dice_sync *)hash_data(&dice_sync_var, name);
00395         if ( !ds ) {
00396                 _dice_debug(2, dice_printf(FUNCTION, "variable not found.\n");)
00397                 return -2;
00398         }
00399 
00400         /* check hierarchy */
00401         if ( dice_is_server() ) {
00402                 switch ( dice_control_hierarchy(ds->changedby == -1 ? 
00403                                 ds->owner : ds->changedby, packetfrom) ) {
00404                   case 0: /* not superior */
00405                         return -3;
00406                   case 1: /* superior */
00407                         ds->changedby = packetfrom;
00408                         break;
00409                   case -1:
00410                           /* error*/
00411                         break;
00412                 }
00413         }
00414 
00415         /* check if already set for deletion */
00416         for ( item = sync_head; item != NULL; item = item->next )
00417                 if ( strcmp(item->ds->name, name) == 0 ) {
00418                         _dice_debug(2, dice_printf(FUNCTION, 
00419                                         "variable %s already deleted.\n",
00420                                         item->ds->name);)
00421                         return 0;
00422                 }
00423 
00424         ds->state = DELETED;
00425         dice_sync_add_to_list(ds);
00426 
00427         return 0;
00428 }
00429 
00430 #undef FUNCTION
00431 #define FUNCTION                "DICE_sync_update"
00432 
00445 int DICE_sync_update ( char *name, void *value ) {
00446         struct dice_sync                *ds;
00447         struct dice_sync_var_item       *item;
00448 
00449         _dice_debug(3, dice_printf(FUNCTION,"(%s,%p)\n",
00450                         name, value);)
00451 
00452         if ( dice_data.original_only == 1 && dice_data.id != 0 )
00453                 return -3;
00454 
00455         if ( !name ) {
00456                 _dice_debug(1, dice_printf(FUNCTION, "NULL name.\n");)
00457                 return -1;
00458         }
00459         ds = hash_data(&dice_sync_var, name);
00460         if ( !ds ) {
00461                 if ( !dice_is_server() )
00462                         _dice_debug(1, dice_printf(FUNCTION, 
00463                                 "Data %s doesn't exist.\n", name);)
00464                 return -2;
00465         }
00466 
00467         /* check hierarchy */
00468         if ( dice_is_server() ) {
00469 _dice_debug(3, dice_printf(FUNCTION,"Owned by %d, changed by %d, from %d\n",
00470                 ds->owner, ds->changedby, packetfrom);)
00471                 switch ( dice_control_hierarchy(ds->changedby == -1 ? 
00472                                 ds->owner : ds->changedby, packetfrom) ) {
00473                   case 0: 
00474                         _dice_debug(3, dice_printf(FUNCTION,"Less hierarchy\n");)
00475                         return -3;
00476                   case 1: /* superior */
00477                         ds->changedby = packetfrom;
00478                         break;
00479                   case -1:
00480                           /* error*/
00481                         break;
00482                 }
00483         }
00484 
00485         ds->nextvalue = value;
00486         ds->state = CHANGED;
00487 
00488         /* avoid sending two updates for the same variable */
00489         for ( item = sync_head; item != NULL; item = item->next )
00490                 if ( strcmp(item->ds->name, name) == 0 )
00491                         return 0;
00492 
00493         dice_sync_add_to_list(ds);
00494 
00495         return 0;
00496 }
00497 
00498 #undef FUNCTION
00499 #define FUNCTION                "DICE_sync"
00500 
00515 int DICE_sync ( void ) {
00516         dice_packet                     packet;
00517 #ifdef USE_ASYNC
00518         struct sigaction                action, ignore;
00519         int                             flags;
00520 #endif
00521 
00522         _dice_debug(3, dice_printf(FUNCTION, "()\n");)
00523 
00524 #ifdef USE_ASYNC
00525         /* ignore all SIGIO while we are syncing */
00526         ignore.sa_handler = SIG_IGN;
00527         sigemptyset(&ignore.sa_mask);
00528         sigaction(SIGIO, &ignore, &action);
00529         flags = fcntl(dice_data.controlsock, F_GETFL, 0);
00530         if ( flags == -1 ) {
00531                 /*error */
00532         }
00533         fcntl(dice_data.controlsock, F_SETFL, flags &(~O_ASYNC));
00534 #endif
00535 
00536         /* send SYNC */
00537         packet.packtype = SYNC;
00538         dice_packet_send(&packet, dice_data.controlsock);
00539 
00540         /* async variables may have been sent meanwhile 
00541         packet = dice_packet_get(dice_data.controlsock);
00542         while ( packet.packtype == VARIABLE_ASYNC ) {
00543                 DICE_async_update(packet.variable.name, packet.variable.value);
00544                 packet = dice_packet_get(dice_data.controlsock);
00545         } */
00546 
00547         /* send VARIABLEs, send READY */
00548         dice_sync_update_send();
00549         packet.packtype = READY;
00550         dice_packet_send(&packet, dice_data.controlsock);
00551 
00552         /* wait for packets; get VARIABLEs, get SYNC */
00553         packet = dice_packet_get(dice_data.controlsock);
00554         while ( packet.packtype == VARIABLE_SYNC ||
00555                 packet.packtype == VARIABLE_FREE_SYNC ) {
00556                 if ( packet.packtype == VARIABLE_SYNC )
00557                         dice_sync_update(packet.variable.name, packet.variable.type,
00558                                 packet.variable.value);
00559 /* todo: free memory here */
00560                 else
00561                         dice_sync_delete(packet.variable.name);
00562                 packet = dice_packet_get(dice_data.controlsock);
00563         }
00564         if ( packet.packtype != SYNC ) {
00565 #ifndef USE_ASYNC
00566                 if ( packet.packtype == GOODBYE ) {
00567                         _dice_debug(1, dice_printf(FUNCTION, 
00568                                 "got a goodbye, quitting.\n");)
00569                         exit(0);
00570                 }
00571 #endif
00572                 _dice_debug(1, dice_printf(FUNCTION, 
00573                                 "expecting SYNC, got %s\n", 
00574                                 dice_packet_name(packet.packtype));)
00575 #ifdef USE_ASYNC
00576                 sigaction(SIGIO, &action, NULL);
00577                 fcntl(dice_data.controlsock, F_SETFL, flags);
00578 #endif
00579                 return -1;
00580         }
00581 
00582         /* send READY */
00583         packet.packtype = READY;
00584         dice_packet_send(&packet, dice_data.controlsock);
00585 
00586         /* wait CONTINUE */
00587         packet = dice_packet_get(dice_data.controlsock);
00588         if ( packet.packtype != CONTINUE ) {
00589                 _dice_debug(1, dice_printf(FUNCTION,
00590                                 "expecting CONTINUE, got %s", 
00591                                 dice_packet_name(packet.packtype));)
00592 #ifdef USE_ASYNC
00593                 sigaction(SIGIO, &action, NULL);
00594                 fcntl(dice_data.controlsock, F_SETFL, flags);
00595 #endif
00596                 return -1;
00597         }
00598 #ifdef USE_ASYNC
00599         /* restore signal handler */
00600         sigaction(SIGIO, &action, NULL);
00601         fcntl(dice_data.controlsock, F_SETFL, flags);
00602 #endif
00603         return 0;
00604 }
00605 
00606 #undef FUNCTION
00607 #define FUNCTION                "DICE_sync_get"
00608 
00618 void *DICE_sync_get ( char *name ) {
00619         struct dice_sync                *ds;
00620 
00621         _dice_debug(3, dice_printf(FUNCTION, "(%s)\n",
00622                         name);)
00623 
00624         if ( !name ) {
00625                 _dice_debug(1, dice_printf(FUNCTION, "NULL name.\n");)
00626                 return NULL;
00627         }
00628         ds = hash_data(&dice_sync_var, name);
00629         if ( !ds ) {
00630                 _dice_debug(1, dice_printf(FUNCTION, "variable not found.\n");)
00631                 return NULL;
00632         }
00633         return ds->value;
00634 }
00635 
00636 #undef FUNCTION
00637 #define FUNCTION                "DICE_sync_get_next"
00638 
00647 void *DICE_sync_get_next ( char *name ) {
00648         struct dice_sync                *ds;
00649 
00650         _dice_debug(3, dice_printf("DICE_sync_get_next(%s)\n",
00651                         name);)
00652 
00653         if ( !name ) {
00654                 _dice_debug(1, dice_printf(FUNCTION, "NULL name.\n");)
00655                 return NULL;
00656         }
00657         ds = hash_data(&dice_sync_var, name);
00658         if ( !ds ) {
00659                 _dice_debug(1, dice_printf(FUNCTION, "variable not found.\n");)
00660                 return NULL;
00661         }
00662 
00663         return ds->nextvalue;
00664 }

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