source: branches/stable/ARBDB/adcomm.cxx

Last change on this file was 16763, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.1 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : adcomm.cxx                                        //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include <unistd.h>
12
13#include <csignal>
14#include <cerrno>
15
16#include <sys/socket.h>
17
18#include <netinet/in.h>
19#include <netinet/tcp.h>
20
21#include "gb_key.h"
22#include "gb_comm.h"
23#include "gb_localdata.h"
24
25#include <SigHandler.h>
26#include <arb_signal.h>
27#include <arb_file.h>
28
29static GBCM_ServerResult gbcms_talking(int con, long *hs, void *sin);
30
31
32#define FD_SET_TYPE
33
34#define debug_printf(a, b)
35
36#define GBCMS_TRANSACTION_TIMEOUT 60*60             // one hour timeout
37#define MAX_QUEUE_LEN             5
38
39#define GBCM_COMMAND_UNFOLD             (GBTUM_MAGIC_NUMBER)
40#define GBCM_COMMAND_GET_UPDATA         (GBTUM_MAGIC_NUMBER+1)
41#define GBCM_COMMAND_PUT_UPDATE         (GBTUM_MAGIC_NUMBER+2)
42#define GBCM_COMMAND_UPDATED            (GBTUM_MAGIC_NUMBER+3)
43#define GBCM_COMMAND_BEGIN_TRANSACTION  (GBTUM_MAGIC_NUMBER+4)
44#define GBCM_COMMAND_COMMIT_TRANSACTION (GBTUM_MAGIC_NUMBER+5)
45#define GBCM_COMMAND_ABORT_TRANSACTION  (GBTUM_MAGIC_NUMBER+6)
46#define GBCM_COMMAND_INIT_TRANSACTION   (GBTUM_MAGIC_NUMBER+7)
47#define GBCM_COMMAND_FIND               (GBTUM_MAGIC_NUMBER+8)
48#define GBCM_COMMAND_CLOSE              (GBTUM_MAGIC_NUMBER+9)
49#define GBCM_COMMAND_KEY_ALLOC          (GBTUM_MAGIC_NUMBER+11)
50#define GBCM_COMMAND_UNDO               (GBTUM_MAGIC_NUMBER+12)
51#define GBCM_COMMAND_DONT_WAIT          (GBTUM_MAGIC_NUMBER+13)
52
53#define GBCM_COMMAND_SEND               (GBTUM_MAGIC_NUMBER+0x1000)
54#define GBCM_COMMAND_SEND_COUNT         (GBTUM_MAGIC_NUMBER+0x2000)
55#define GBCM_COMMAND_SETDEEP            (GBTUM_MAGIC_NUMBER+0x3000)
56#define GBCM_COMMAND_SETINDEX           (GBTUM_MAGIC_NUMBER+0x4000)
57#define GBCM_COMMAND_PUT_UPDATE_KEYS    (GBTUM_MAGIC_NUMBER+0x5000)
58#define GBCM_COMMAND_PUT_UPDATE_CREATE  (GBTUM_MAGIC_NUMBER+0x6000)
59#define GBCM_COMMAND_PUT_UPDATE_DELETE  (GBTUM_MAGIC_NUMBER+0x7000)
60#define GBCM_COMMAND_PUT_UPDATE_UPDATE  (GBTUM_MAGIC_NUMBER+0x8000)
61#define GBCM_COMMAND_PUT_UPDATE_END     (GBTUM_MAGIC_NUMBER+0x9000)
62#define GBCM_COMMAND_TRANSACTION_RETURN (GBTUM_MAGIC_NUMBER+0x100000)
63#define GBCM_COMMAND_FIND_ERG           (GBTUM_MAGIC_NUMBER+0x108000)
64#define GBCM_COMMAND_KEY_ALLOC_RES      (GBTUM_MAGIC_NUMBER+0x10b000)
65#define GBCM_COMMAND_UNDO_CMD           (GBTUM_MAGIC_NUMBER+0x10a0001)
66
67// --------------------------
68//      error generators
69
70inline GB_ERROR clientserver_error(const char *clientserver, const char *what_failed, int sourceLine) {
71    const char *rev_tag = GB_get_arb_revision_tag();
72    return GBS_global_string("ARBDB %s error: %s (errcode=%s#%i)", clientserver, what_failed, rev_tag, sourceLine);
73}
74
75#define CLIENT_ERROR(reason)        clientserver_error("client", reason, __LINE__)
76#define SERVER_ERROR(reason)        clientserver_error("server", reason, __LINE__)
77#define COMM_ERROR(reason)          clientserver_error("communication", reason, __LINE__)
78
79#define CLIENT_RECEIVE_ERROR() CLIENT_ERROR("receive failed")
80#define SERVER_RECEIVE_ERROR() SERVER_ERROR("receive failed")
81#define COMM_RECEIVE_ERROR()   COMM_ERROR("receive failed")
82
83#define CLIENT_SEND_ERROR() CLIENT_ERROR("send failed")
84#define SERVER_SEND_ERROR() SERVER_ERROR("send failed")
85#define COMM_SEND_ERROR()   COMM_ERROR("send failed")
86
87#define CLIENT_SEND_ERROR_AT_ITEM(gb_item) CLIENT_ERROR(GBS_global_string("send failed (entry='%s')", GB_KEY(gb_item)))
88
89static void dumpError(GB_ERROR error) {
90    fputc('\n', stderr);
91    fputs(error, stderr);
92    fputc('\n', stderr);
93    fflush(stderr);
94}
95
96// ------------------------
97//      some structures
98
99struct gbcms_delete_list {                          // Store all deleted items in a list
100    gbcms_delete_list *next;
101    long               creation_date;
102    long               update_date;
103    GBDATA            *gbd;
104};
105
106struct Socinf {
107    Socinf            *next;
108    int                socket;
109    gbcms_delete_list *dl;                          // point to last deleted item that is sent to this client
110    char              *username;
111};
112
113static void g_bcms_delete_Socinf(Socinf *THIS) {
114    freenull(THIS->username);
115    THIS->next = NULp;
116    free(THIS);
117}
118
119struct gb_server_data {
120    int     hso;
121    char   *unix_name;
122    Socinf *soci;
123    long    nsoc;
124    long    timeout;
125    GBDATA *gb_main;
126    int     wait_for_new_request;
127    bool    inside_remote_action;
128
129    gbcms_delete_list *del_first; // All deleted items, that are yet unknown to at least one client
130    gbcms_delete_list *del_last;
131};
132
133
134
135struct gbcms_create {
136    gbcms_create *next;
137    GBDATA       *server_id;
138    GBDATA       *client_id;
139};
140
141
142// --------------------
143//      Panic save
144
145static GBCONTAINER *gbcms_gb_main;
146
147static void gbcms_sighup(int) {
148    char *panic_file = NULp; // hang-up trigger file
149    char *db_panic   = NULp; // file to save DB to
150    {
151        const char *ap = GB_getenv("ARB_PID");
152        if (!ap) ap    = "";
153
154        FILE *in = GB_fopen_tempfile(GBS_global_string("arb_panic_%s_%s", GB_getenvUSER(), ap), "rt", &panic_file);
155
156        fprintf(stderr,
157                "**** ARB DATABASE SERVER received a HANGUP SIGNAL ****\n"
158                "- Looking for file '%s'\n",
159                panic_file);
160
161        db_panic = GB_read_fp(in);
162        fclose(in);
163    }
164
165    if (!db_panic) {
166        fprintf(stderr,
167                "- Could not read '%s' (Reason: %s)\n"
168                "[maybe retry]\n",
169                panic_file, GB_await_error());
170    }
171    else {
172        char *newline           = strchr(db_panic, '\n');
173        if (newline) newline[0] = 0;
174
175        fprintf(stderr, "- Trying to save DATABASE in ASCII mode into file '%s'\n", db_panic);
176
177        GB_ERROR error = GBCONTAINER_MAIN(gbcms_gb_main)->panic_save(db_panic);
178
179        if (error) fprintf(stderr, "Error while saving '%s': %s\n", db_panic, error);
180        else fprintf(stderr, "- DATABASE saved into '%s' (ASCII)\n", db_panic);
181
182        unlink(panic_file);
183        free(db_panic);
184    }
185}
186
187GB_ERROR GB_MAIN_TYPE::panic_save(const char *db_panic) {
188    const int org_transaction_level = transaction_level;
189
190    transaction_level = 0;
191    GB_ERROR error    = save_as(db_panic, "az"); // attempt zipped first
192    if (error) error  = save_as(db_panic, "a");  // fallback to plain ascii on failure
193    transaction_level = org_transaction_level;
194
195    return error;
196}
197
198GB_ERROR GBCMS_open(const char *path, long timeout, GBDATA *gb_main) {
199    // server open
200
201    GB_MAIN_TYPE *Main  = GB_MAIN(gb_main);
202    GB_ERROR      error = NULp;
203
204    if (Main->server_data) {
205        error = "reopen of server not allowed";
206    }
207    else {
208        gbcmc_comm *comm = gbcmc_open(path);
209        if (comm) {
210            error = GBS_global_string("Socket '%s' already in use", path);
211            gbcmc_close(comm); // ignore result
212        }
213        else {
214            int   socket;
215            char *unix_name = NULp;
216
217            error = gbcm_open_socket(path, false, &socket, &unix_name);
218            if (!error) {
219                ASSERT_RESULT(SigHandler, SIG_DFL,                       INSTALL_SIGHANDLER(SIGHUP, gbcms_sighup, "GBCMS_open"));
220
221                gbcms_gb_main = gb_main->as_container();
222
223                if (listen(socket, MAX_QUEUE_LEN) < 0) {
224                    error = GBS_global_string("could not listen (server; errno=%i)", errno);
225                }
226                else {
227                    gb_server_data *hs = ARB_calloc<gb_server_data>(1);
228
229                    hs->timeout   = timeout;
230                    hs->gb_main   = gb_main;
231                    hs->hso       = socket;
232                    hs->unix_name = unix_name;
233
234                    Main->server_data = hs;
235                }
236            }
237        }
238    }
239
240    if (error) {
241        error = GBS_global_string("ARB_DB_SERVER_ERROR: %s", error);
242        fprintf(stderr, "%s\n", error);
243    }
244    return error;
245}
246
247void GBCMS_shutdown(GBDATA *gbd) {
248    // server close
249
250    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
251    if (Main->server_data) {
252        gb_server_data *hs = Main->server_data;
253        Socinf         *si;
254
255        for (si=hs->soci; si; si=si->next) {
256            shutdown(si->socket, SHUT_RDWR);
257            close(si->socket);
258        }
259        shutdown(hs->hso, SHUT_RDWR);
260
261        if (hs->unix_name) {
262            unlink(hs->unix_name);
263            freenull(hs->unix_name);
264        }
265        close(hs->hso);
266        freenull(Main->server_data);
267    }
268}
269
270template<typename T>
271inline void write_into_comm_buffer(long& buffer, T& t) {
272    STATIC_ASSERT(sizeof(t) <= sizeof(long));
273
274    buffer         = 0; // initialize (avoid to write uninitialized byte to avoid valgrind errors)
275    *(T*)(&buffer) = t;
276}
277
278static __ATTR__USERESULT GB_ERROR gbcm_write_bin(int socket, GBDATA *gbd, long *buffer, long deep, int send_headera) {
279    /* send a database item to client/server
280      *
281      * mode    =1 server
282      *         =0 client
283      * buffer = buffer
284      * deep = 0 -> just send one item   >0 send sub entries too
285      * send_headera = 1 -> if type = GB_DB send flag and key_quark array
286      */
287
288    buffer[0] = GBCM_COMMAND_SEND;
289
290    long i      = 2;
291    buffer[i++] = (long)gbd;
292    buffer[i++] = gbd->index;
293
294    write_into_comm_buffer(buffer[i++], gbd->flags);
295
296    if (gbd->is_container()) {
297        GBCONTAINER *gbc = gbd->as_container();
298        int          end = gbc->d.nheader;
299
300        write_into_comm_buffer(buffer[i++], gbc->flags3);
301
302        buffer[i++] = send_headera ? end : -1;
303        buffer[i++] = deep ? gbc->d.size : -1;
304        buffer[1]   = i;
305
306        if (gbcm_write(socket, (const char *)buffer, i* sizeof(long))) {
307            return COMM_SEND_ERROR();
308        }
309
310        if (send_headera) {
311            gb_header_list  *hdl  = GB_DATA_LIST_HEADER(gbc->d);
312            gb_header_flags *buf2 = (gb_header_flags *)GB_give_buffer2(gbc->d.nheader * sizeof(gb_header_flags));
313
314            for (int index = 0; index < end; index++) {
315                buf2[index] = hdl[index].flags;
316            }
317            if (gbcm_write(socket, (const char *)buf2, end * sizeof(gb_header_flags))) {
318                return COMM_SEND_ERROR();
319            }
320        }
321
322        if (deep) {
323            debug_printf("%i    ", gbc->d.size);
324
325            for (int index = 0; index < end; index++) {
326                GBDATA *gb2 = GBCONTAINER_ELEM(gbc, index);
327                if (gb2) {
328                    debug_printf("%i ", index);
329                    GB_ERROR error = gbcm_write_bin(socket, gb2, (long *)buffer, deep-1, send_headera);
330                    if (error) return error;
331                }
332            }
333            debug_printf("\n", 0);
334        }
335    }
336    else {
337        GBENTRY *gbe = gbd->as_entry();
338        if (gbe->type() < GB_BITS) {
339            buffer[i++] = gbe->info.i;
340            buffer[1] = i;
341            if (gbcm_write(socket, (const char *)buffer, i*sizeof(long))) {
342                return COMM_SEND_ERROR();
343            }
344        }
345        else {
346            long memsize;
347            buffer[i++] = gbe->size();
348            memsize = buffer[i++] = gbe->memsize();
349            buffer[1] = i;
350            if (gbcm_write(socket, (const char *)buffer, i* sizeof(long))) {
351                return COMM_SEND_ERROR();
352            }
353            if (gbcm_write(socket, gbe->data(), memsize)) {
354                return COMM_SEND_ERROR();
355            }
356        }
357    }
358    return NULp;
359}
360
361#define RETURN_SERVER_FAULT_ON_BAD_ADDRESS(ptr)                         \
362    do {                                                                \
363        GB_ERROR error = GBK_test_address((long*)(ptr), GBTUM_MAGIC_NUMBER); \
364        if (error) {                                                    \
365            GB_warningf("%s (%s, #%i)", error, __FILE__, __LINE__);     \
366            return GBCM_SERVER_FAULT;                                   \
367        }                                                               \
368    } while (0)
369
370static GBCM_ServerResult gbcm_read_bin(int socket, GBCONTAINER *gbc, long *buffer, long mode, GBDATA *gb_source, void *cs_main) {
371    /* read an entry into gbc
372     * mode == 1  server reads data
373     * mode == 0  client read all data
374     * mode == -1  client read but do not read subobjects -> folded cont
375     * mode == -2  client dummy read
376     */
377
378    long size = gbcm_read(socket, (char *)buffer, sizeof(long) * 3);
379    if (size != sizeof(long) * 3) {
380        fprintf(stderr, "receive failed header size\n");
381        return GBCM_SERVER_FAULT;
382    }
383    if (buffer[0] != GBCM_COMMAND_SEND) {
384        fprintf(stderr, "receive failed wrong command\n");
385        return GBCM_SERVER_FAULT;
386    }
387
388    long id = buffer[2];
389    long i  = buffer[1];
390    i       = sizeof(long) * (i - 3);
391
392    size = gbcm_read(socket, (char *)buffer, i);
393    if (size != i) {
394        GB_internal_error("receive failed DB_NODE\n");
395        return GBCM_SERVER_FAULT;
396    }
397
398    i              = 0;
399    long index_pos = buffer[i++];
400    if (!gb_source && gbc && index_pos<gbc->d.nheader) {
401        gb_source = GBCONTAINER_ELEM(gbc, index_pos);
402    }
403
404    gb_flag_types flags = *(gb_flag_types *)(&buffer[i++]);
405    GB_TYPES      type  = GB_TYPES(flags.type);
406
407    GBDATA *gb2;
408    if (mode >= -1) {   // real read data
409        if (gb_source) {
410            GB_TYPES stype = gb_source->type();
411            gb2 = gb_source;
412            if (stype != type) {
413                GB_internal_error("Type changed in client: Connection aborted\n");
414                return GBCM_SERVER_FAULT;
415            }
416            if (mode>0) {   // transactions only in server
417                RETURN_SERVER_FAULT_ON_BAD_ADDRESS(gb2);
418            }
419            if (stype != GB_DB) {
420                gb_save_extern_data_in_ts(gb2->as_entry());
421            }
422            gb_touch_entry(gb2, GB_NORMAL_CHANGE);
423        }
424        else {
425            if (mode==-1) goto dont_create_in_a_folded_container;
426            if (type == GB_DB) {
427                gb2 = gb_make_container(gbc, NULp, index_pos, GB_DATA_LIST_HEADER(gbc->d)[index_pos].flags.key_quark);
428            }
429            else {  // @@@ Header Transaction stimmt nicht
430                gb2 = gb_make_entry(gbc, NULp, index_pos, GB_DATA_LIST_HEADER(gbc->d)[index_pos].flags.key_quark, (GB_TYPES)type);
431            }
432            if (mode>0) {   // transaction only in server
433                gb_touch_entry(gb2, GB_CREATED);
434            }
435            else {
436                gb2->server_id = id;
437                GBS_write_numhash(GB_MAIN(gb2)->remote_hash, id, (long) gb2);
438            }
439            if (cs_main) {
440                gbcms_create *cs = ARB_calloc<gbcms_create>(1);
441                cs->next = *((gbcms_create **) cs_main);
442                *((gbcms_create **) cs_main) = cs;
443                cs->server_id = gb2;
444                cs->client_id = (GBDATA *)id;
445            }
446        }
447        gb2->flags = flags;
448        if (type == GB_DB) {
449            gb2->as_container()->flags3 = *((gb_flag_types3 *)&(buffer[i++]));
450        }
451    }
452    else {
453      dont_create_in_a_folded_container :
454        if (type == GB_DB) {
455            // gb_flag_types3 flags3 = *((gb_flag_types3 *)&(buffer[i++]));
456            ++i;
457        }
458        gb2 = NULp;
459    }
460
461    if (type == GB_DB) {
462        long nheader = buffer[i++];
463        long nitems  = buffer[i++];
464
465        if (nheader > 0) {
466            long             realsize = nheader* sizeof(gb_header_flags);
467            gb_header_flags *buffer2  = (gb_header_flags *)GB_give_buffer2(realsize);
468
469            size = gbcm_read(socket, (char *)buffer2, realsize);
470            if (size != realsize) {
471                GB_internal_error("receive failed data\n");
472                return GBCM_SERVER_FAULT;
473            }
474            if (gb2 && mode >= -1) {
475                GBCONTAINER  *gbc2 = gb2->as_container();
476                GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(gbc2);
477
478                gb_create_header_array(gbc2, (int)nheader);
479                if (nheader < gbc2->d.nheader) {
480                    GB_internal_error("Inconsistency Client-Server Cache");
481                }
482                gbc2->d.nheader = (int)nheader;
483                gb_header_list *hdl = GB_DATA_LIST_HEADER(gbc2->d);
484                for (long item = 0; item < nheader; item++) {
485                    GBQUARK old_index = hdl->flags.key_quark;
486                    GBQUARK new_index = buffer2->key_quark;
487                    if (new_index && !old_index) {  // a rename ...
488                        gb_write_index_key(gbc2, item, new_index);
489                    }
490                    if (mode>0) {   // server read data
491
492
493                    }
494                    else {
495                        if (buffer2->changed >= GB_DELETED) {
496                            hdl->flags.set_change(GB_DELETED);
497                        }
498                    }
499                    hdl->flags.flags = buffer2->flags;
500                    hdl++; buffer2++;
501                }
502                if (mode>0) {   // transaction only in server
503                    gb_touch_header(gbc2);
504                }
505                else {
506                    gbc2->header_update_date = Main->clock;
507                }
508            }
509        }
510
511        if (nitems >= 0) {
512            long newmod = mode;
513            if (mode>=0) {
514                if (mode==0 && nitems<=1) {         // only a partial send
515                    gb2->flags2.folded_container = 1;
516                }
517            }
518            else {
519                newmod = -2;
520            }
521            debug_printf("Client %i \n", nheader);
522            for (long item = 0; item < nitems; item++) {
523                debug_printf("  Client reading %i\n", item);
524                long irror = gbcm_read_bin(socket, gb2->as_container(), buffer, newmod, NULp, cs_main);
525                if (irror) {
526                    return GBCM_SERVER_FAULT;
527                }
528            }
529            debug_printf("Client done\n", 0);
530        }
531        else {
532            if ((mode==0) && !gb_source) {      // created GBDATA at client
533                gb2->flags2.folded_container = 1;
534            }
535        }
536    }
537    else {
538        if (mode >= 0) {
539            GBENTRY *ge2 = gb2->as_entry();
540            if (type < GB_BITS) {
541                ge2->info.i = buffer[i++];
542            }
543            else {
544                long  realsize = buffer[i++];
545                long  memsize  = buffer[i++];
546
547                ge2->index_check_out();
548                assert_or_exit(!(ge2->stored_external() && ge2->info.ex.get_data()));
549
550                GBENTRY_memory storage(ge2, realsize, memsize);
551                size = gbcm_read(socket, storage, memsize);
552                if (size != memsize) {
553                    fprintf(stderr, "receive failed data\n");
554                    return GBCM_SERVER_FAULT;
555                }
556            }
557        }
558        else {
559            if (type >= GB_BITS) { // dummy read (e.g. updata in server && not cached in client
560                long memsize;
561                char *buffer2;
562                i++;
563                memsize = buffer[i++];
564                buffer2 = GB_give_buffer2(memsize);
565
566                size = gbcm_read(socket, buffer2, memsize);
567                if (size != memsize) {
568                    GB_internal_error("receive failed data\n");
569                    return GBCM_SERVER_FAULT;
570                }
571            }
572        }
573    }
574
575    return GBCM_SERVER_OK;
576}
577
578
579static void gbcms_shift_delete_list(void *hsi, void *soi) {
580    gb_server_data *hs     = (gb_server_data *)hsi;
581    Socinf         *socinf = (Socinf *)soi;
582
583    if (!hs->del_first) return;
584    while ((!socinf->dl) || (socinf->dl->next)) {
585        if (!socinf->dl) socinf->dl = hs->del_first;
586        else    socinf->dl = socinf->dl->next;
587    }
588}
589
590static GBCM_ServerResult gbcms_write_deleted(int socket, long hsin, long client_clock, long *buffer) {
591    Socinf            *socinf;
592    gb_server_data    *hs;
593    gbcms_delete_list *dl;
594
595    hs = (gb_server_data *)hsin;
596    for (socinf = hs->soci; socinf; socinf=socinf->next) {
597        if (socinf->socket == socket) break;
598    }
599    if (!socinf) return GBCM_SERVER_OK;
600    if (!hs->del_first) return GBCM_SERVER_OK;
601    while (!socinf->dl || (socinf->dl->next)) {
602        if (!socinf->dl) socinf->dl = hs->del_first;
603        else    socinf->dl = socinf->dl->next;
604        if (socinf->dl->creation_date>client_clock) continue;
605        // created and deleted object
606        buffer[0] = GBCM_COMMAND_PUT_UPDATE_DELETE;
607        buffer[1] = (long)socinf->dl->gbd;
608        if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
609    }
610    for (socinf = hs->soci; socinf; socinf=socinf->next) {
611        if (!socinf->dl) return GBCM_SERVER_OK;
612    }
613    while ((dl = hs->del_first)) {
614        for (socinf = hs->soci; socinf; socinf=socinf->next) {
615            if (socinf->dl == dl) return GBCM_SERVER_OK;
616        }
617        hs->del_first = dl->next;
618        gbm_free_mem(dl, sizeof(gbcms_delete_list), GBM_CB_INDEX);
619    }
620    return GBCM_SERVER_OK;
621}
622
623static GBCM_ServerResult gbcms_write_updated(int socket, GBDATA *gbd, long hsin, long client_clock, long *buffer) {
624    if (gbd->update_date()<=client_clock) return GBCM_SERVER_OK;
625    if (gbd->creation_date() > client_clock) {
626        buffer[0] = GBCM_COMMAND_PUT_UPDATE_CREATE;
627        buffer[1] = (long)GB_FATHER(gbd);
628        if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
629
630        GB_ERROR error = gbcm_write_bin(socket, gbd, buffer, 0, 1);
631        if (error) {
632            dumpError(error);
633            return GBCM_SERVER_FAULT;
634        }
635    }
636    else { // send clients first
637        if (gbd->is_container()) {
638            GBCONTAINER *gbc         = gbd->as_container();
639            int          end         = (int)gbc->d.nheader;
640            int          send_header = (gbc->header_update_date > client_clock) ? 1 : 0;
641
642            buffer[0] = GBCM_COMMAND_PUT_UPDATE_UPDATE;
643            buffer[1] = (long)gbd;
644            if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
645
646            GB_ERROR error = gbcm_write_bin(socket, gbd, buffer, 0, send_header);
647            if (error) {
648                dumpError(error);
649                return GBCM_SERVER_FAULT;
650            }
651
652            for (int index = 0; index < end; index++) {
653                GBDATA *gb2 = GBCONTAINER_ELEM(gbc, index);
654                if (gb2 && gbcms_write_updated(socket, gb2, hsin, client_clock, buffer)) {
655                    return GBCM_SERVER_FAULT;
656                }
657            }
658        }
659        else {
660            buffer[0]             = GBCM_COMMAND_PUT_UPDATE_UPDATE;
661            buffer[1]             = (long)gbd;
662            if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
663
664            const int SEND_HEADER = 0;
665            GB_ERROR  error       = gbcm_write_bin(socket, gbd, buffer, 0, SEND_HEADER);
666            if (error) {
667                dumpError(error);
668                return GBCM_SERVER_FAULT;
669            }
670        }
671    }
672
673    return GBCM_SERVER_OK;
674}
675
676static GBCM_ServerResult gbcms_write_keys(int socket, GBDATA *gbd) { // @@@ move into GB_MAIN_TYPE?
677    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
678
679    long buffer[4];
680    buffer[0] = GBCM_COMMAND_PUT_UPDATE_KEYS;
681    buffer[1] = (long)gbd;
682    buffer[2] = Main->keycnt;
683    buffer[3] = Main->first_free_key;
684
685    if (gbcm_write(socket, (const char *)buffer, 4*sizeof(long))) return GBCM_SERVER_FAULT;
686
687    for (int i=1; i<Main->keycnt; i++) {
688        gb_Key &key = Main->keys[i];
689        buffer[0] = key.nref;
690        buffer[1] = key.next_free_key;
691        if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
692        if (gbcm_write_string(socket, key.key)) return GBCM_SERVER_FAULT;
693    }
694    return GBCM_SERVER_OK;
695}
696
697static GBCM_ServerResult gbcms_talking_unfold(int socket, long */*hsin*/, void */*sin*/, GBDATA *gb_in) {
698    // command: GBCM_COMMAND_UNFOLD
699
700    GBCONTAINER *gbc = gb_in->expect_container();
701    GBDATA      *gb2;
702    char        *buffer;
703    long         deep[1];
704    long         index_pos[1];
705    int          index, start, end;
706
707    RETURN_SERVER_FAULT_ON_BAD_ADDRESS(gbc);
708    if (gbc->type() != GB_DB) return GBCM_SERVER_FAULT;
709    if (gbcm_read_two(socket, GBCM_COMMAND_SETDEEP, NULp, deep)) {
710        return GBCM_SERVER_FAULT;
711    }
712    if (gbcm_read_two(socket, GBCM_COMMAND_SETINDEX, NULp, index_pos)) {
713        return GBCM_SERVER_FAULT;
714    }
715
716    gbcm_read_flush();
717    buffer = GB_give_buffer(1014);
718
719    if (index_pos[0]==-2) {
720        GB_ERROR error = gbcm_write_bin(socket, gbc, (long *)buffer, deep[0]+1, 1);
721        if (error) {
722            dumpError(error);
723            return GBCM_SERVER_FAULT;
724        }
725        gbcm_write_flush(socket);
726        return GBCM_SERVER_OK;
727    }
728
729    if (index_pos[0] >= 0) {
730        start  = (int)index_pos[0];
731        end = start + 1;
732        if (gbcm_write_two(socket, GBCM_COMMAND_SEND_COUNT, 1)) {
733            return GBCM_SERVER_FAULT;
734        }
735    }
736    else {
737        start = 0;
738        end = gbc->d.nheader;
739        if (gbcm_write_two(socket, GBCM_COMMAND_SEND_COUNT, gbc->d.size)) {
740            return GBCM_SERVER_FAULT;
741        }
742    }
743    for (index = start; index < end; index++) {
744        if ((gb2 = GBCONTAINER_ELEM(gbc, index))) {
745            GB_ERROR error = gbcm_write_bin(socket, gb2, (long *)buffer, deep[0], 1);
746            if (error) {
747                dumpError(error);
748                return GBCM_SERVER_FAULT;
749            }
750        }
751    }
752
753    gbcm_write_flush(socket);
754    return GBCM_SERVER_OK;
755}
756
757static GBCM_ServerResult gbcms_talking_get_update(int /*socket*/, long */*hsin*/, void */*sin*/, GBDATA */*gbd*/) {
758    return GBCM_SERVER_OK;
759}
760
761static GBCM_ServerResult gbcms_talking_put_update(int socket, long */*hsin*/, void */*sin*/, GBDATA */*gbd*/) {
762    /* Reads
763     * - the date
764     * - and all changed data
765     * from client.
766     *
767     * command: GBCM_COMMAND_PUT_UPDATE
768     */
769    long          irror;
770    GBDATA       *gbd;
771    gbcms_create *cs[1], *cs_main[1];
772    long         *buffer;
773    bool          end;
774
775    cs_main[0] = NULp;
776    buffer     = (long *) GB_give_buffer(1024);
777    end        = false;
778    while (!end) {
779        if (gbcm_read(socket, (char *) buffer, sizeof(long) * 3) != sizeof(long) * 3) {
780            return GBCM_SERVER_FAULT;
781        }
782        gbd = (GBDATA *) buffer[2];
783        RETURN_SERVER_FAULT_ON_BAD_ADDRESS(gbd);
784        switch (buffer[0]) {
785            case GBCM_COMMAND_PUT_UPDATE_CREATE:
786                irror = gbcm_read_bin(socket, gbd->as_container(), buffer, 1, NULp, (void *)cs_main);
787                if (irror) return GBCM_SERVER_FAULT;
788                break;
789            case GBCM_COMMAND_PUT_UPDATE_DELETE:
790                gb_delete_force(gbd);
791                break;
792            case GBCM_COMMAND_PUT_UPDATE_UPDATE:
793                irror = gbcm_read_bin(socket, NULp, buffer, 1, gbd, NULp);
794                if (irror) return GBCM_SERVER_FAULT;
795                break;
796            case GBCM_COMMAND_PUT_UPDATE_END:
797                end = true;
798                break;
799            default:
800                return GBCM_SERVER_FAULT;
801        }
802    }
803    gbcm_read_flush();                        // send all id's of newly created objects
804    for (cs[0] = cs_main[0]; cs[0]; cs[0]=cs_main[0]) {
805        cs_main[0] = cs[0]->next;
806        buffer[0] = (long)cs[0]->client_id;
807        buffer[1] = (long)cs[0]->server_id;
808        if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
809        free(cs[0]);
810    }
811    buffer[0] = 0;
812    if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
813    gbcm_write_flush(socket);
814    return GBCM_SERVER_OK;
815}
816
817static GBCM_ServerResult gbcms_talking_updated(int /*socket*/, long */*hsin*/, void */*sin*/, GBDATA */*gbd*/) {
818    return GBCM_SERVER_OK;
819}
820
821static GBCM_ServerResult gbcms_talking_init_transaction(int socket, long *hsin, void *sin, GBDATA */*gbd*/) {
822    /* begin client transaction
823     * sends clock
824     *
825     * command: GBCM_COMMAND_INIT_TRANSACTION
826     */
827
828    gb_server_data *hs = (gb_server_data *)hsin;
829    Socinf         *si = (Socinf *)sin;
830
831    GBDATA       *gb_main = hs->gb_main;
832    GB_MAIN_TYPE *Main    = GB_MAIN(gb_main);
833    GBDATA       *gbd     = gb_main;
834    char         *user    = gbcm_read_string(socket);
835
836    gbcm_read_flush();
837    if (gbcm_login(gbd->as_container(), user)) {
838        return GBCM_SERVER_FAULT;
839    }
840    si->username = user;
841
842    gb_local->running_client_transaction = ARB_TRANS;
843
844    if (gbcm_write_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, Main->clock)) {
845        return GBCM_SERVER_FAULT;
846    }
847    if (gbcm_write_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, (long)gbd)) {
848        return GBCM_SERVER_FAULT;
849    }
850    if (gbcm_write_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, (long)Main->this_user->userid)) {
851        return GBCM_SERVER_FAULT;
852    }
853    gbcms_write_keys(socket, gbd);
854
855    gbcm_write_flush(socket);
856    // send modified data to client
857
858    GB_begin_transaction(gbd);
859    while (gb_local->running_client_transaction == ARB_TRANS) {
860        fd_set set;
861        FD_ZERO(&set);
862        FD_SET(socket, &set);
863
864        struct timeval timeout;
865        timeout.tv_sec  = GBCMS_TRANSACTION_TIMEOUT;
866        timeout.tv_usec = 100000;
867
868        long anz = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
869
870        if (anz<0) continue;
871        if (anz==0) {
872            GB_export_errorf("ARB_DB ERROR CLIENT TRANSACTION TIMEOUT, CLIENT DISCONNECTED (I waited %lu seconds)", timeout.tv_sec);
873            GB_print_error();
874            gb_local->running_client_transaction = ARB_ABORT;
875            GB_abort_transaction(gbd);
876            return GBCM_SERVER_FAULT;
877        }
878        if (GBCM_SERVER_OK == gbcms_talking(socket, hsin, sin)) continue;
879        gb_local->running_client_transaction = ARB_ABORT;
880        GB_abort_transaction(gbd);
881        return GBCM_SERVER_FAULT;
882    }
883    if (gb_local->running_client_transaction == ARB_COMMIT) {
884        GB_commit_transaction(gbd);
885        gbcms_shift_delete_list(hsin, sin);
886    }
887    else {
888        GB_abort_transaction(gbd);
889    }
890    return GBCM_SERVER_OK;
891}
892
893static GBCM_ServerResult gbcms_talking_begin_transaction(int socket, long *hsin, void *sin, GBDATA *long_client_clock) {
894    /* begin client transaction
895     * sends clock
896     * deleted
897     * created+updated
898     *
899     * command: GBCM_COMMAND_BEGIN_TRANSACTION
900     */
901    long            client_clock = (long)long_client_clock;
902    GBDATA         *gb_main;
903    GBDATA         *gbd;
904    gb_server_data *hs           = (gb_server_data *)hsin;
905    long            anz;
906    long           *buffer;
907    fd_set          set;
908    timeval         timeout;
909
910    gb_main = hs->gb_main;
911    gbd = gb_main;
912    gbcm_read_flush();
913    gb_local->running_client_transaction = ARB_TRANS;
914
915    if (gbcm_write_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, GB_MAIN(gbd)->clock)) {
916        return GBCM_SERVER_FAULT;
917    }
918
919    // send modified data to client
920    buffer = (long *)GB_give_buffer(1024);
921    if (GB_MAIN(gb_main)->key_clock > client_clock) {
922        if (gbcms_write_keys(socket, gbd)) return GBCM_SERVER_FAULT;
923    }
924    if (gbcms_write_deleted(socket,      (long)hs, client_clock, buffer)) return GBCM_SERVER_FAULT;
925    if (gbcms_write_updated(socket, gbd, (long)hs, client_clock, buffer)) return GBCM_SERVER_FAULT;
926    buffer[0] = GBCM_COMMAND_PUT_UPDATE_END;
927    buffer[1] = 0;
928    if (gbcm_write(socket, (const char *)buffer, sizeof(long)*2)) return GBCM_SERVER_FAULT;
929    if (gbcm_write_flush(socket))       return GBCM_SERVER_FAULT;
930
931    GB_begin_transaction(gbd);
932    while (gb_local->running_client_transaction == ARB_TRANS) {
933        FD_ZERO(&set);
934        FD_SET(socket, &set);
935
936        timeout.tv_sec  = GBCMS_TRANSACTION_TIMEOUT;
937        timeout.tv_usec = 0;
938
939        anz = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, NULp, &timeout);
940
941        if (anz<0) continue;
942        if (anz==0) {
943            GB_export_errorf("ARB_DB ERROR CLIENT TRANSACTION TIMEOUT, CLIENT DISCONNECTED (I waited %lu seconds)", timeout.tv_sec);
944            GB_print_error();
945            gb_local->running_client_transaction = ARB_ABORT;
946            GB_abort_transaction(gbd);
947            return GBCM_SERVER_FAULT;
948        }
949        if (GBCM_SERVER_OK == gbcms_talking(socket, hsin, sin)) continue;
950        gb_local->running_client_transaction = ARB_ABORT;
951        GB_abort_transaction(gbd);
952        return GBCM_SERVER_FAULT;
953    }
954    if (gb_local->running_client_transaction == ARB_COMMIT) {
955        GB_commit_transaction(gbd);
956        gbcms_shift_delete_list(hsin, sin);
957    }
958    else {
959        GB_abort_transaction(gbd);
960    }
961    return GBCM_SERVER_OK;
962}
963
964static GBCM_ServerResult commit_or_abort_transaction(int socket, GBDATA *gbd, ARB_TRANS_TYPE commit_or_abort) {
965    RETURN_SERVER_FAULT_ON_BAD_ADDRESS(gbd);
966   
967    gb_local->running_client_transaction = commit_or_abort;
968    gbcm_read_flush();
969
970    if (gbcm_write_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, 0)) return GBCM_SERVER_FAULT;
971    return gbcm_write_flush(socket);
972}
973static GBCM_ServerResult gbcms_talking_commit_transaction(int socket, long */*hsin*/, void */*sin*/, GBDATA *gbd) {
974    // command: GBCM_COMMAND_COMMIT_TRANSACTION
975    return commit_or_abort_transaction(socket, gbd, ARB_COMMIT);
976}
977
978static GBCM_ServerResult gbcms_talking_abort_transaction(int socket, long */*hsin*/, void */*sin*/, GBDATA *gbd) {
979    // command: GBCM_COMMAND_ABORT_TRANSACTION
980    return commit_or_abort_transaction(socket, gbd, ARB_ABORT);
981}
982
983static GBCM_ServerResult gbcms_talking_close(int /*socket*/, long */*hsin*/, void */*sin*/, GBDATA */*gbd*/) {
984    // command: GBCM_COMMAND_CLOSE
985    return GBCM_SERVER_ABORTED;
986}
987
988static GBCM_ServerResult gbcms_talking_undo(int socket, long */*hsin*/, void */*sin*/, GBDATA *gbd) {
989    // command: GBCM_COMMAND_UNDO
990    long      cmd;
991    GB_ERROR  result  = NULp;
992    char     *to_free = NULp;
993    if (gbcm_read_two(socket, GBCM_COMMAND_UNDO_CMD, NULp, &cmd)) {
994        return GBCM_SERVER_FAULT;
995    }
996    gbcm_read_flush();
997    switch (cmd) {
998        case _GBCMC_UNDOCOM_REQUEST_NOUNDO:
999            result = GB_request_undo_type(gbd, GB_UNDO_NONE);
1000            break;
1001        case _GBCMC_UNDOCOM_REQUEST_NOUNDO_KILL:
1002            result = GB_request_undo_type(gbd, GB_UNDO_KILL);
1003            break;
1004        case _GBCMC_UNDOCOM_REQUEST_UNDO:
1005            result = GB_request_undo_type(gbd, GB_UNDO_UNDO);
1006            break;
1007        case _GBCMC_UNDOCOM_INFO_UNDO:
1008            result = to_free = GB_undo_info(gbd, GB_UNDO_UNDO);
1009            break;
1010        case _GBCMC_UNDOCOM_INFO_REDO:
1011            result = to_free = GB_undo_info(gbd, GB_UNDO_REDO);
1012            break;
1013        case _GBCMC_UNDOCOM_UNDO:
1014            result = GB_undo(gbd, GB_UNDO_UNDO);
1015            break;
1016        case _GBCMC_UNDOCOM_REDO:
1017            result = GB_undo(gbd, GB_UNDO_REDO);
1018            break;
1019        default:    result = GB_set_undo_mem(gbd, cmd);
1020    }
1021    if (gbcm_write_string(socket, result)) {
1022        if (to_free) free(to_free);
1023        return GBCM_SERVER_FAULT;
1024    }
1025    if (to_free) free(to_free);
1026    return gbcm_write_flush(socket);
1027}
1028
1029static GBCM_ServerResult gbcms_talking_find(int socket, long */*hsin*/, void */*sin*/, GBDATA * gbd) {
1030    // command: GBCM_COMMAND_FIND
1031   
1032    char     *key;
1033    char     *val1      = NULp;
1034    GB_CASE   case_sens = GB_CASE_UNDEFINED;
1035    long      val2      = 0;
1036    GB_TYPES  type;
1037    void     *buffer[2];
1038
1039    RETURN_SERVER_FAULT_ON_BAD_ADDRESS(gbd);
1040
1041    key  = gbcm_read_string(socket);
1042    type = GB_TYPES(gbcm_read_long(socket));
1043
1044    switch (type) {
1045        case GB_NONE:
1046            break;
1047
1048        case GB_STRING:
1049            val1      = gbcm_read_string(socket);
1050            case_sens = GB_CASE(gbcm_read_long(socket));
1051            break;
1052
1053        case GB_INT:
1054            val2 = gbcm_read_long(socket);
1055            break;
1056
1057        default:
1058            gb_assert(0);
1059            GB_export_errorf("gbcms_talking_find: illegal data type (%i)", type);
1060            GB_print_error();
1061            return GBCM_SERVER_FAULT;
1062    }
1063
1064    {
1065        GB_SEARCH_TYPE gbs = GB_SEARCH_TYPE(gbcm_read_long(socket));
1066        gbcm_read_flush();
1067
1068        if (type == GB_FIND) {
1069            gbd = GB_find(gbd, key, gbs);
1070        }
1071        else if (type == GB_STRING) {
1072            gbd = GB_find_string(gbd, key, val1, case_sens, gbs);
1073            free(val1);
1074        }
1075        else if (type == GB_INT) {
1076            gbd = GB_find_int(gbd, key, val2, gbs);
1077        }
1078        else {
1079            GB_internal_errorf("Searching DBtype %i not implemented", type);
1080        }
1081    }
1082
1083    free(key);
1084
1085    if (gbcm_write_two(socket, GBCM_COMMAND_FIND_ERG, (long) gbd)) {
1086        return GBCM_SERVER_FAULT;
1087    }
1088    if (gbd) {
1089        while (GB_GRANDPA(gbd)) {
1090            buffer[0] = (void *)gbd->index;
1091            buffer[1] = (void *)GB_FATHER(gbd);
1092            gbcm_write(socket, (const char *) buffer, sizeof(long) * 2);
1093            gbd = GB_FATHER(gbd);
1094        }
1095    }
1096    buffer[0] = NULp;
1097    buffer[1] = NULp;
1098    gbcm_write(socket, (const char *) buffer, sizeof(long) * 2);
1099
1100    return gbcm_write_flush(socket);
1101}
1102
1103static GBCM_ServerResult gbcms_talking_key_alloc(int socket, long */*hsin*/, void */*sin*/, GBDATA * gbd) {
1104    // command: GBCM_COMMAND_KEY_ALLOC
1105    // (old maybe wrong comment: "do a query in the server")
1106
1107    char *key;
1108    long  index;
1109
1110    RETURN_SERVER_FAULT_ON_BAD_ADDRESS(gbd);
1111    key = gbcm_read_string(socket);
1112    gbcm_read_flush();
1113
1114    if (key)
1115        index = gb_create_key(GB_MAIN(gbd), key, false);
1116    else
1117        index = 0;
1118
1119    if (key)
1120        free(key);
1121
1122    if (gbcm_write_two(socket, GBCM_COMMAND_KEY_ALLOC_RES, index)) {
1123        return GBCM_SERVER_FAULT;
1124    }
1125    return gbcm_write_flush(socket);
1126}
1127
1128static GBCM_ServerResult gbcms_talking_disable_wait_for_new_request(int /*socket*/, long *hsin, void */*sin*/, GBDATA */*gbd*/) {
1129    gb_server_data *hs = (gb_server_data *) hsin;
1130    hs->wait_for_new_request--;
1131    return GBCM_SERVER_OK_WAIT;
1132}
1133
1134static GBCM_ServerResult gbcms_talking_obsolete(int /*socket*/, long */*hsin*/, void */*sin*/, GBDATA */*gbd*/) {
1135    fputs("Obsolete server function called\n", stderr);
1136    return GBCM_SERVER_FAULT;
1137}
1138
1139// -----------------------
1140//      server talking
1141
1142typedef GBCM_ServerResult (*TalkingFunction)(int socket, long *hsin, void *sin, GBDATA *gbd);
1143
1144static TalkingFunction aisc_talking_functions[] = {
1145    gbcms_talking_unfold,                           // GBCM_COMMAND_UNFOLD
1146    gbcms_talking_get_update,                       // GBCM_COMMAND_GET_UPDATA
1147    gbcms_talking_put_update,                       // GBCM_COMMAND_PUT_UPDATE
1148    gbcms_talking_updated,                          // GBCM_COMMAND_UPDATED
1149    gbcms_talking_begin_transaction,                // GBCM_COMMAND_BEGIN_TRANSACTION
1150    gbcms_talking_commit_transaction,               // GBCM_COMMAND_COMMIT_TRANSACTION
1151    gbcms_talking_abort_transaction,                // GBCM_COMMAND_ABORT_TRANSACTION
1152    gbcms_talking_init_transaction,                 // GBCM_COMMAND_INIT_TRANSACTION
1153    gbcms_talking_find,                             // GBCM_COMMAND_FIND
1154    gbcms_talking_close,                            // GBCM_COMMAND_CLOSE
1155    gbcms_talking_obsolete,
1156    gbcms_talking_key_alloc,                        // GBCM_COMMAND_KEY_ALLOC
1157    gbcms_talking_undo,                             // GBCM_COMMAND_UNDO
1158    gbcms_talking_disable_wait_for_new_request      // GBCM_COMMAND_DONT_WAIT
1159};
1160
1161static GBCM_ServerResult gbcms_talking(int con, long *hs, void *sin) {
1162    gbcm_read_flush();
1163
1164  next_command :
1165
1166    long buf[3];
1167    long len = gbcm_read(con, (char *)buf, sizeof(long) * 3);
1168    if (len == sizeof(long) * 3) {
1169        long magic_number = buf[0];
1170        if ((magic_number & GBTUM_MAGIC_NUMBER_FILTER) != GBTUM_MAGIC_NUMBER) {
1171            gbcm_read_flush();
1172            fprintf(stderr, "Illegal Access\n");
1173            return GBCM_SERVER_FAULT;
1174        }
1175        magic_number &= ~GBTUM_MAGIC_NUMBER_FILTER;
1176        GBCM_ServerResult error = (aisc_talking_functions[magic_number])(con, hs, sin, (GBDATA *)buf[2]);
1177        if (error == GBCM_SERVER_OK_WAIT) {
1178            goto next_command;
1179        }
1180        gbcm_read_flush();
1181        return error ? error : GBCM_SERVER_OK;
1182    }
1183    else {
1184        return GBCM_SERVER_FAULT;
1185    }
1186}
1187
1188bool GBCMS_accept_calls(GBDATA *gbd, bool wait_extra_time) {
1189    // returns true if served
1190
1191    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1192    if (!Main->server_data) return false;
1193    if (Main->get_transaction_level()) return false;
1194
1195    gb_server_data *hs = Main->server_data;
1196    timeval         timeout;
1197
1198    if (wait_extra_time) {
1199        timeout.tv_sec = 0;
1200        timeout.tv_usec = 100000; // 100 ms
1201    }
1202    else {
1203        timeout.tv_sec = (int)(hs->timeout / 1000);
1204        timeout.tv_usec = (hs->timeout % 1000) * 1000;
1205    }
1206    if (wait_extra_time) {
1207        hs->wait_for_new_request = 1;
1208    }
1209    else {
1210        hs->wait_for_new_request = 0;
1211    }
1212
1213    {
1214        fd_set set;
1215        fd_set setex;
1216
1217        FD_ZERO(&set);
1218        FD_ZERO(&setex);
1219        FD_SET(hs->hso, &set);
1220        FD_SET(hs->hso, &setex);
1221
1222        for (Socinf *si=hs->soci; si; si=si->next) {
1223            FD_SET(si->socket, &set);
1224            FD_SET(si->socket, &setex);
1225        }
1226
1227        {
1228            long anz;
1229            if (hs->timeout>=0) {
1230                anz = select(FD_SETSIZE, FD_SET_TYPE & set, NULp, FD_SET_TYPE & setex, &timeout);
1231            }
1232            else {
1233                anz = select(FD_SETSIZE, FD_SET_TYPE & set, NULp, FD_SET_TYPE & setex, NULp);
1234            }
1235
1236            if (anz==-1) return false;
1237            if (!anz) return false; // timed out
1238        }
1239
1240
1241        if (FD_ISSET(hs->hso, &set)) {
1242            int con = accept(hs->hso, NULp, NULp);
1243            if (con>0) {
1244                long optval[1];
1245                Socinf *sptr = ARB_calloc<Socinf>(1);
1246                sptr->next = hs->soci;
1247                sptr->socket = con;
1248                hs->soci=sptr;
1249                hs->nsoc++;
1250                optval[0] = 1;
1251                setsockopt(con, IPPROTO_TCP, TCP_NODELAY, (char *)optval, 4);
1252            }
1253        }
1254        else {
1255            Socinf *si_last = NULp;
1256            Socinf *si_next;
1257
1258            for (Socinf *si=hs->soci; si; si_last=si, si=si_next) {
1259                si_next = si->next;
1260
1261                GBCM_ServerResult error = GBCM_SERVER_OK;
1262                if (FD_ISSET(si->socket, &set)) {
1263                    error = gbcms_talking(si->socket, (long *)hs, (void *)si);
1264                    if (GBCM_SERVER_OK == error) {
1265                        hs->wait_for_new_request ++;
1266                        continue;
1267                    }
1268                } else if (!FD_ISSET(si->socket, &setex)) continue;
1269
1270                // kill socket
1271
1272                if (close(si->socket)) {
1273                    printf("aisc_accept_calls: ");
1274                    printf("couldn't close socket errno = %i!\n", errno);
1275                }
1276
1277                hs->nsoc--;
1278                if (si==hs->soci) { // first one
1279                    hs->soci = si->next;
1280                }
1281                else {
1282                    si_last->next = si->next;
1283                }
1284                if (si->username) {
1285                    gbcm_logout(Main, si->username);
1286                }
1287                g_bcms_delete_Socinf(si);
1288                si = NULp;
1289
1290                if (error != GBCM_SERVER_ABORTED) {
1291                    fprintf(stdout, "ARB_DB_SERVER: a client died abnormally\n");
1292                }
1293                break;
1294            }
1295        }
1296
1297    }
1298    if (hs->wait_for_new_request>0) {
1299        return true;
1300    }
1301    return false;
1302}
1303
1304
1305GB_ERROR gbcm_unfold_client(GBCONTAINER *gbc, long deep, long index_pos) {
1306    // goes to header: __ATTR__USERESULT
1307
1308    /* read data from a server
1309     * deep       = -1   read whole data
1310     * deep       = 0...n    read to deep
1311     * index_pos == -1 read all clients
1312     * index_pos == -2 read all clients + header array
1313     */
1314
1315    GB_ERROR error  = NULp;
1316    int      socket = GBCONTAINER_MAIN(gbc)->c_link->socket;
1317    gbcm_read_flush();
1318
1319    if      (gbcm_write_two  (socket, GBCM_COMMAND_UNFOLD, gbc->server_id)) error = CLIENT_SEND_ERROR();
1320    else if (gbcm_write_two  (socket, GBCM_COMMAND_SETDEEP, deep))          error = CLIENT_SEND_ERROR();
1321    else if (gbcm_write_two  (socket, GBCM_COMMAND_SETINDEX, index_pos))    error = CLIENT_SEND_ERROR();
1322    else if (gbcm_write_flush(socket))                                      error = CLIENT_SEND_ERROR();
1323    else {
1324        long buffer[256];
1325        long irror = 0;
1326        if (index_pos == -2) {
1327            irror = gbcm_read_bin(socket, NULp, buffer, 0, gbc, NULp);
1328        }
1329        else {
1330            long nitems;
1331            if (gbcm_read_two(socket, GBCM_COMMAND_SEND_COUNT, NULp, &nitems)) irror = 1;
1332            else {
1333                for (long item = 0; !irror && item<nitems; item++) {
1334                    irror = gbcm_read_bin(socket, gbc, buffer, 0, NULp, NULp);
1335                }
1336            }
1337        }
1338
1339        if (irror) {
1340            error = CLIENT_ERROR(GBS_global_string("receive error while unfolding '%s'", GB_read_key_pntr(gbc)));
1341        }
1342        else {
1343            gbcm_read_flush();
1344            if (index_pos < 0) {
1345                gbc->flags2.folded_container = 0;
1346            }
1347        }
1348    }
1349
1350    return error;
1351}
1352
1353// -------------------------
1354//      Client functions
1355
1356GB_ERROR gbcmc_begin_sendupdate(GBDATA *gbd) {
1357    // goes to header: __ATTR__USERESULT
1358
1359    if (gbcm_write_two(GB_MAIN(gbd)->c_link->socket, GBCM_COMMAND_PUT_UPDATE, gbd->server_id)) {
1360        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1361    }
1362    return NULp;
1363}
1364
1365GB_ERROR gbcmc_end_sendupdate(GBDATA *gbd) {
1366    // goes to header: __ATTR__USERESULT
1367
1368    GB_MAIN_TYPE *Main   = GB_MAIN(gbd);
1369    int           socket = Main->c_link->socket;
1370    if (gbcm_write_two(socket, GBCM_COMMAND_PUT_UPDATE_END, gbd->server_id)) {
1371        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1372    }
1373
1374    gbcm_write_flush(socket);
1375    while (1) {
1376        long buffer[2];
1377        if (gbcm_read(socket, (char *)&(buffer[0]), sizeof(long)*2) != sizeof(long)*2) {
1378            return CLIENT_RECEIVE_ERROR();
1379        }
1380        gbd = (GBDATA *)buffer[0];
1381        if (!gbd) break;
1382        gbd->server_id = buffer[1];
1383        GBS_write_numhash(Main->remote_hash, gbd->server_id, (long)gbd);
1384    }
1385    gbcm_read_flush();
1386    return NULp;
1387}
1388
1389GB_ERROR gbcmc_sendupdate_create(GBDATA *gbd) {
1390    // goes to header: __ATTR__USERESULT
1391
1392    GBCONTAINER *father = GB_FATHER(gbd);
1393    if (!father) {
1394        return CLIENT_ERROR(GBS_global_string("entry '%s' has no father", GB_KEY(gbd)));
1395    }
1396
1397    int socket = GB_MAIN(father)->c_link->socket;
1398    if (gbcm_write_two(socket, GBCM_COMMAND_PUT_UPDATE_CREATE, father->server_id)) {
1399        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1400    }
1401
1402    long *buffer = (long *)GB_give_buffer(1014);
1403    return gbcm_write_bin(socket, gbd, buffer, -1, 1);
1404}
1405
1406GB_ERROR gbcmc_sendupdate_delete(GBDATA *gbd) {
1407    // goes to header: __ATTR__USERESULT
1408
1409    if (gbcm_write_two(GB_MAIN(gbd)->c_link->socket, GBCM_COMMAND_PUT_UPDATE_DELETE, gbd->server_id)) {
1410        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1411    }
1412    return NULp;
1413}
1414
1415GB_ERROR gbcmc_sendupdate_update(GBDATA *gbd, int send_headera) { // @@@ DRY vs gbcmc_sendupdate_create
1416    // goes to header: __ATTR__USERESULT
1417
1418    GBCONTAINER *father = GB_FATHER(gbd);
1419    if (!father) {
1420        return CLIENT_ERROR(GBS_global_string("entry '%s' has no father", GB_KEY(gbd)));
1421    }
1422
1423    int socket = GB_MAIN(father)->c_link->socket;
1424    if (gbcm_write_two(socket, GBCM_COMMAND_PUT_UPDATE_UPDATE, gbd->server_id)) {
1425        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1426    }
1427
1428    long *buffer = (long *)GB_give_buffer(1016);
1429    return gbcm_write_bin(socket, gbd, buffer, 0, send_headera);
1430}
1431
1432static __ATTR__USERESULT GB_ERROR gbcmc_read_keys(int socket, GBDATA *gbd) { // @@@ move into GB_MAIN_TYPE?
1433    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1434    long          buffer[2];
1435
1436    if (gbcm_read(socket, (char *)buffer, sizeof(long)*2) != sizeof(long)*2) {
1437        return CLIENT_RECEIVE_ERROR();
1438    }
1439
1440    long size            = buffer[0];
1441    Main->first_free_key = buffer[1];
1442    gb_create_key_array(Main, (int)size);
1443
1444    for (int i=1; i<size; i++) {
1445        if (gbcm_read(socket, (char *)buffer, sizeof(long)*2) != sizeof(long)*2) {
1446            return CLIENT_RECEIVE_ERROR();
1447        }
1448
1449        gb_Key &KEY = Main->keys[i];
1450
1451        KEY.nref          = buffer[0];    // to control malloc_index
1452        KEY.next_free_key = buffer[1];    // to control malloc_index
1453
1454        char *key = gbcm_read_string(socket);
1455        if (key) {
1456            if (!key[0]) { // empty key
1457                free(key);
1458                return CLIENT_ERROR("invalid empty key received");
1459            }
1460
1461            GBS_write_hash(Main->key_2_index_hash, key, i);
1462            freeset(KEY.key, key);
1463        }
1464    }
1465    Main->keycnt = (int)size;
1466    return NULp;
1467}
1468
1469GB_ERROR gbcmc_begin_transaction(GBDATA *gbd) {
1470    // goes to header: __ATTR__USERESULT
1471
1472    GB_MAIN_TYPE *Main   = GB_MAIN(gbd);
1473    int           socket = Main->c_link->socket;
1474    long         *buffer = (long *)GB_give_buffer(1026);
1475
1476    if (gbcm_write_two(socket, GBCM_COMMAND_BEGIN_TRANSACTION, Main->clock)) {
1477        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1478    }
1479
1480    if (gbcm_write_flush(socket)) {
1481        return CLIENT_SEND_ERROR();
1482    }
1483
1484    {
1485        long server_clock;
1486        if (gbcm_read_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, NULp, &server_clock)) {
1487            return CLIENT_RECEIVE_ERROR();
1488        }
1489        Main->clock = server_clock;
1490    }
1491
1492    while (1) {
1493        if (gbcm_read(socket, (char *)buffer, sizeof(long)*2) != sizeof(long)*2) {
1494            return CLIENT_RECEIVE_ERROR();
1495        }
1496
1497        long    d   = buffer[1];
1498        GBDATA *gb2 = (GBDATA *)GBS_read_numhash(Main->remote_hash, d);
1499        long    mode;
1500        if (gb2) {
1501            mode = gb2->flags2.folded_container
1502                ? -1                                // read container
1503                : 0;                                // read all
1504        }
1505        else {
1506            mode = -2;                              // read nothing
1507        }
1508
1509        switch (buffer[0]) {
1510            case GBCM_COMMAND_PUT_UPDATE_UPDATE:
1511                if (gbcm_read_bin(socket, NULp, buffer, mode, gb2, NULp)) {
1512                    return CLIENT_RECEIVE_ERROR();
1513                }
1514                if (gb2) {
1515                    gb2->create_extended();
1516                    gb2->touch_update(Main->clock);
1517                }
1518                break;
1519            case GBCM_COMMAND_PUT_UPDATE_CREATE:
1520                if (gbcm_read_bin(socket, GBDATA::as_container(gb2), buffer, mode, NULp, NULp)) {
1521                    return CLIENT_RECEIVE_ERROR();
1522                }
1523                if (gb2) {
1524                    gb2->create_extended();
1525                    gb2->touch_creation_and_update(Main->clock);
1526                }
1527                break;
1528            case GBCM_COMMAND_PUT_UPDATE_DELETE:
1529                if (gb2) gb_delete_entry(gb2);
1530                break;
1531            case GBCM_COMMAND_PUT_UPDATE_KEYS: {
1532                GB_ERROR error = gbcmc_read_keys(socket, gbd);
1533                if (error) return error;
1534                break;
1535            }
1536            case GBCM_COMMAND_PUT_UPDATE_END:
1537                goto endof_gbcmc_begin_transaction;
1538
1539            default:
1540                return CLIENT_RECEIVE_ERROR();
1541        }
1542    }
1543
1544  endof_gbcmc_begin_transaction :
1545    gbcm_read_flush();
1546    return NULp;
1547}
1548
1549GB_ERROR gbcmc_init_transaction(GBCONTAINER *gbc) {
1550    // goes to header: __ATTR__USERESULT
1551
1552    GB_ERROR      error  = NULp;
1553    GB_MAIN_TYPE *Main   = GBCONTAINER_MAIN(gbc);
1554    int           socket = Main->c_link->socket;
1555
1556    if (gbcm_write_two(socket, GBCM_COMMAND_INIT_TRANSACTION, Main->clock)) {
1557        return CLIENT_SEND_ERROR_AT_ITEM(gbc);
1558    }
1559    gbcm_write_string(socket, Main->this_user->username);
1560    if (gbcm_write_flush(socket)) {
1561        return CLIENT_SEND_ERROR();
1562    }
1563
1564    {
1565        long server_clock;
1566        if (gbcm_read_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, NULp, &server_clock)) {
1567            return CLIENT_RECEIVE_ERROR();
1568        }
1569        Main->clock = server_clock;
1570    }
1571
1572    long buffer[4];
1573    if (gbcm_read_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, NULp, buffer)) {
1574        return CLIENT_RECEIVE_ERROR();
1575    }
1576    gbc->server_id = buffer[0];
1577
1578    if (gbcm_read_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, NULp, buffer)) {
1579        return CLIENT_RECEIVE_ERROR();
1580    }
1581    Main->this_user->userid = (int)buffer[0];
1582    Main->this_user->userbit = 1<<((int)buffer[0]);
1583
1584    GBS_write_numhash(Main->remote_hash, gbc->server_id, (long)gbc);
1585
1586    if (gbcm_read(socket, (char *)buffer, 2 * sizeof(long)) != 2 * sizeof(long)) {
1587        return CLIENT_RECEIVE_ERROR();
1588    }
1589    error = gbcmc_read_keys(socket, gbc);
1590    if (error) return error;
1591
1592    gbcm_read_flush();
1593    return NULp;
1594}
1595
1596GB_ERROR gbcmc_commit_transaction(GBDATA *gbd) {
1597    // goes to header: __ATTR__USERESULT
1598
1599    int socket = GB_MAIN(gbd)->c_link->socket;
1600    if (gbcm_write_two(socket, GBCM_COMMAND_COMMIT_TRANSACTION, gbd->server_id)) {
1601        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1602    }
1603
1604    if (gbcm_write_flush(socket)) {
1605        return CLIENT_SEND_ERROR();
1606    }
1607
1608    long dummy;
1609    if (gbcm_read_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, NULp, &dummy)) {
1610        return CLIENT_RECEIVE_ERROR();
1611    }
1612    gbcm_read_flush();
1613    return NULp;
1614}
1615GB_ERROR gbcmc_abort_transaction(GBDATA *gbd) { // @@@ DRY vs gbcmc_commit_transaction
1616    // goes to header: __ATTR__USERESULT
1617
1618    int socket = GB_MAIN(gbd)->c_link->socket;
1619    if (gbcm_write_two(socket, GBCM_COMMAND_ABORT_TRANSACTION, gbd->server_id)) {
1620        return CLIENT_SEND_ERROR_AT_ITEM(gbd);
1621    }
1622
1623    if (gbcm_write_flush(socket)) {
1624        return CLIENT_SEND_ERROR();
1625    }
1626
1627    long dummy;
1628    if (gbcm_read_two(socket, GBCM_COMMAND_TRANSACTION_RETURN, NULp, &dummy)) {
1629        return CLIENT_RECEIVE_ERROR();
1630    }
1631    gbcm_read_flush();
1632    return NULp;
1633}
1634
1635GB_ERROR gbcms_add_to_delete_list(GBDATA *gbd) {
1636    gb_server_data *hs = GB_MAIN(gbd)->server_data;
1637
1638    if (hs && hs->soci) {
1639        gbcms_delete_list *dl = (gbcms_delete_list *)gbm_get_mem(sizeof(gbcms_delete_list), GBM_CB_INDEX);
1640
1641        dl->creation_date = gbd->creation_date();
1642        dl->update_date   = gbd->update_date();
1643        dl->gbd           = gbd;
1644
1645        if (!hs->del_first) {
1646            hs->del_first = hs->del_last = dl;
1647        }
1648        else {
1649            hs->del_last->next = dl;
1650            hs->del_last = dl;
1651        }
1652    }
1653    return NULp;
1654}
1655
1656void GB_set_remote_action(GBDATA *gbd, bool in_action) {
1657    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1658
1659    if (Main->is_server()) { // GB_set_remote_action has no effect in clients
1660        gb_server_data *hs = Main->server_data;
1661        gb_assert(hs); // have no server data (program logic error)
1662        if (hs) {
1663            gb_assert(hs->inside_remote_action != in_action);
1664            hs->inside_remote_action = in_action;
1665        }
1666    }
1667}
1668bool GB_inside_remote_action(GBDATA *gbd) {
1669    GB_MAIN_TYPE *Main   = GB_MAIN(gbd);
1670    bool          inside = false;
1671
1672    gb_assert(Main->is_server()); // GB_inside_remote_action not allowed from clients
1673    if (Main->is_server()) {
1674        gb_server_data *hs = Main->server_data;
1675        if (hs) {
1676            inside = hs->inside_remote_action;
1677        }
1678    }
1679    return inside;
1680}
1681
1682long GB_read_clients(GBDATA *gbd) {
1683    // returns number of clients or
1684    // -1 if not called from server
1685
1686    GB_MAIN_TYPE *Main    = GB_MAIN(gbd);
1687    long          clients = -1;
1688
1689    if (Main->is_server()) {
1690        gb_server_data *hs = Main->server_data;
1691        clients = hs ? hs->nsoc : 0;
1692    }
1693
1694    return clients;
1695}
1696
1697bool GB_is_server(GBDATA *gbd) {
1698    return GB_MAIN(gbd)->is_server();
1699}
1700
1701static __ATTR__USERESULT GB_ERROR gbcmc_unfold_list(int socket, GBDATA * gbd) {
1702    GB_ERROR error = NULp;
1703
1704    long readvar[2];
1705    if (!gbcm_read(socket, (char *) readvar, sizeof(long) * 2)) {
1706        error = CLIENT_RECEIVE_ERROR();
1707    }
1708    else {
1709        GBCONTAINER *gb_client = (GBCONTAINER*)readvar[1];
1710        if (gb_client) {
1711            error = gbcmc_unfold_list(socket, gbd);
1712            if (!error) {
1713                gb_client = (GBCONTAINER *)GBS_read_numhash(GB_MAIN(gbd)->remote_hash, (long) gb_client);
1714                gb_unfold(gb_client, 0, (int)readvar[0]);
1715            }
1716        }
1717    }
1718    return error;
1719}
1720
1721static void invalid_use_in_server(const char *function) {
1722    GB_internal_errorf("ARBDB fatal error: function '%s' may not be called in server", function);
1723}
1724
1725GBDATA *GBCMC_find(GBDATA *gbd, const char *key, GB_TYPES type, const char *str, GB_CASE case_sens, GB_SEARCH_TYPE gbs) {
1726    // perform search in DB server (from DB client)
1727    // returns NULp if not found OR error occurred (use GB_have_error to test)
1728
1729    union {
1730        GBDATA *gbd;
1731        long    l;
1732    } result;
1733    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1734
1735    int socket;
1736    if (Main->is_server()) {
1737        invalid_use_in_server("GBCMC_find");
1738    }
1739
1740    socket = Main->c_link->socket;
1741
1742    if (gbcm_write_two(socket, GBCM_COMMAND_FIND, gbd->server_id)) {
1743        GB_export_error(CLIENT_SEND_ERROR());
1744        return NULp;
1745    }
1746
1747    gbcm_write_string(socket, key);
1748    gbcm_write_long(socket, type);
1749    switch (type) {
1750        case GB_NONE:
1751            break;
1752        case GB_STRING:
1753            gbcm_write_string(socket, str);
1754            gbcm_write_long(socket, case_sens);
1755            break;
1756        case GB_INT:
1757            gbcm_write_long(socket, *(long*)str);
1758            break;
1759        default:
1760            gb_assert(0);
1761            GB_export_errorf("GBCMC_find: Illegal data type (%i)", type);
1762            return NULp;
1763    }
1764
1765    gbcm_write_long(socket, gbs);
1766
1767    if (gbcm_write_flush(socket)) {
1768        GB_export_error(CLIENT_SEND_ERROR());
1769        return NULp;
1770    }
1771    if (gbcm_read_two(socket, GBCM_COMMAND_FIND_ERG, NULp, &result.l)) {
1772        GB_export_error(CLIENT_RECEIVE_ERROR());
1773        return NULp;
1774    }
1775    if (result.gbd) {
1776        GB_ERROR error = gbcmc_unfold_list(socket, gbd);
1777        if (error) {
1778            GB_export_error(error);
1779            return NULp;
1780        }
1781        result.l = GBS_read_numhash(Main->remote_hash, result.l);
1782    }
1783    gbcm_read_flush();
1784    return result.gbd;
1785}
1786
1787
1788long gbcmc_key_alloc(GBDATA *gbd, const char *key) {
1789    /*! allocate a new key quark from client
1790     * returns new key quark for 'key' or 0 (error is exported in that case)
1791     */
1792    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1793    if (Main->is_server()) {
1794        invalid_use_in_server("gbcmc_key_alloc");
1795    }
1796
1797    int      socket = Main->c_link->socket;
1798    GB_ERROR error  = NULp;
1799    long     result = 0;
1800    if (gbcm_write_two(socket, GBCM_COMMAND_KEY_ALLOC, gbd->server_id)) {
1801        error = CLIENT_SEND_ERROR();
1802    }
1803    else {
1804        gbcm_write_string(socket, key);
1805
1806        if (gbcm_write_flush(socket)) {
1807            error = CLIENT_SEND_ERROR();
1808        }
1809        else {
1810            if (gbcm_read_two(socket, GBCM_COMMAND_KEY_ALLOC_RES, NULp, &result)) {
1811                error  = CLIENT_RECEIVE_ERROR();
1812                result = 0;
1813            }
1814            gbcm_read_flush();
1815        }
1816    }
1817    if (error) {
1818        gb_assert(result == 0); // indicates error
1819        GB_export_error(error);
1820    }
1821    return result;
1822}
1823
1824GB_ERROR gbcmc_send_undo_commands(GBDATA *gbd, enum gb_undo_commands command) { // goes to header: __ATTR__USERESULT
1825    // send an undo command
1826
1827    GB_ERROR      error = NULp;
1828    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
1829
1830    if (Main->is_server()) {
1831        invalid_use_in_server("gbcmc_send_undo_commands");
1832    }
1833    else {
1834        int socket = Main->c_link->socket;
1835
1836        if      (gbcm_write_two  (socket, GBCM_COMMAND_UNDO, gbd->server_id)) error = CLIENT_SEND_ERROR();
1837        else if (gbcm_write_two  (socket, GBCM_COMMAND_UNDO_CMD, command))    error = CLIENT_SEND_ERROR();
1838        else if (gbcm_write_flush(socket))                                    error = CLIENT_SEND_ERROR();
1839        else {
1840            error = gbcm_read_string(socket);
1841            gbcm_read_flush();
1842        }
1843    }
1844    return error;
1845}
1846
1847char *gbcmc_send_undo_info_commands(GBDATA *gbd, enum gb_undo_commands command) {
1848    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1849    if (Main->is_server()) {
1850        invalid_use_in_server("gbcmc_send_undo_info_commands");
1851    }
1852
1853    int socket = Main->c_link->socket;
1854    if (gbcm_write_two(socket, GBCM_COMMAND_UNDO, gbd->server_id) ||
1855        gbcm_write_two(socket, GBCM_COMMAND_UNDO_CMD, command) ||
1856        gbcm_write_flush(socket))
1857    {
1858        GB_export_error(CLIENT_SEND_ERROR());
1859        return NULp;
1860    }
1861
1862    char *result = gbcm_read_string(socket);
1863    gbcm_read_flush();
1864    return result;
1865}
1866
1867GB_ERROR GB_tell_server_dont_wait(GBDATA *gbd) {
1868    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1869    if (Main->is_server()) return NULp;
1870
1871    int socket = Main->c_link->socket;
1872    if (gbcm_write_two(socket, GBCM_COMMAND_DONT_WAIT, gbd->server_id)) {
1873        return CLIENT_SEND_ERROR();
1874    }
1875
1876    return NULp;
1877}
1878
1879// ---------------------
1880//      Login/Logout
1881
1882
1883GB_ERROR gbcm_login(GBCONTAINER *gb_main, const char *loginname) {
1884    // goes to header: __ATTR__USERESULT
1885
1886     // look for any free user and set this_user
1887    int i;
1888    GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(gb_main);
1889
1890    for (i = 0; i<GB_MAX_USERS; i++) {
1891        gb_user *user = Main->users[i];
1892        if (user && strcmp(loginname, user->username) == 0) {
1893            Main->this_user = user;
1894            user->nusers++;
1895            return NULp;
1896        }
1897    }
1898    for (i = 0; i<GB_MAX_USERS; i++) {
1899        gb_user*& user = Main->users[i];
1900        if (!user) {
1901            ARB_calloc(user, 1);
1902
1903            user->username = ARB_strdup(loginname);
1904            user->userid   = i;
1905            user->userbit  = 1<<i;
1906            user->nusers   = 1;
1907
1908            Main->this_user = user;
1909
1910            return NULp;
1911        }
1912    }
1913    return GBS_global_string("Too many users in this database (user='%s')", loginname);
1914}
1915
1916GBCM_ServerResult gbcmc_close(gbcmc_comm * link) {
1917    if (link->socket) {
1918        if (gbcm_write_two(link->socket, GBCM_COMMAND_CLOSE, 0)) {
1919            GB_export_error(CLIENT_SEND_ERROR());
1920            return GBCM_SERVER_FAULT;
1921        }
1922        if (gbcm_write_flush(link->socket)) {
1923            GB_export_error(CLIENT_SEND_ERROR());
1924            return GBCM_SERVER_FAULT;
1925        }
1926        close(link->socket);
1927        link->socket = 0;
1928    }
1929    free(link->unix_name);
1930    free(link);
1931    return GBCM_SERVER_OK;
1932}
1933
1934GB_ERROR gbcm_logout(GB_MAIN_TYPE *Main, const char *loginname) {
1935    // if 'loginname' is NULp, the first logged-in user will be logged out
1936
1937    if (!loginname) {
1938        loginname = Main->users[0]->username;
1939        gb_assert(loginname);
1940    }
1941
1942    for (long i = 0; i<GB_MAX_USERS; i++) {
1943        gb_user*& user = Main->users[i];
1944        if (user && strcmp(loginname, user->username) == 0) {
1945            user->nusers--;
1946            if (user->nusers<=0) { // kill user and his projects
1947                if (i) fprintf(stdout, "User '%s' has logged out\n", loginname);
1948                free(user->username);
1949                freenull(user);
1950            }
1951            return NULp;
1952        }
1953    }
1954    return GB_export_errorf("User '%s' not logged in", loginname);
1955}
1956
1957GB_ERROR GB_install_pid(int mode) {
1958    /* tell the arb_clean script what programs are running.
1959     * mode == 1 -> install
1960     * mode == 0 -> never install
1961     */
1962
1963    static long lastpid = -1;
1964    GB_ERROR    error   = NULp;
1965
1966    if (mode == 0) {
1967        gb_assert(lastpid == -1); // you have to call GB_install_pid(0) before opening any database!
1968        lastpid = -25;            // mark as "never install"
1969    }
1970
1971    if (lastpid != -25) {
1972        long pid = getpid();
1973
1974        if (pid != lastpid) {   // don't install pid multiple times
1975            char *pidfile_name;
1976            {
1977                const char *user    = GB_getenvUSER();
1978                const char *arb_pid = GB_getenv("ARB_PID"); // normally the pid of the 'arb' shell script
1979
1980                gb_assert(user);
1981                if (!arb_pid) arb_pid = "";
1982
1983                pidfile_name = GBS_global_string_copy("arb_pids_%s_%s", user, arb_pid);
1984            }
1985
1986            char *pid_fullname;
1987            FILE *pidfile = GB_fopen_tempfile(pidfile_name, "at", &pid_fullname);
1988
1989            if (!pidfile) {
1990                error = GBS_global_string("GB_install_pid: %s", GB_await_error());
1991            }
1992            else {
1993                fprintf(pidfile, "%li ", pid);
1994                lastpid = pid; // remember installed pid
1995                fclose(pidfile);
1996            }
1997
1998            // ensure pid file is private, otherwise someone could inject PIDs which will be killed later
1999            gb_assert(GB_is_privatefile(pid_fullname, false));
2000
2001            free(pid_fullname);
2002            free(pidfile_name);
2003        }
2004    }
2005
2006    return error;
2007}
2008
Note: See TracBrowser for help on using the repository browser.