source: branches/stable/AISC_COM/C/client.c

Last change on this file was 16766, checked in by westram, 7 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.8 KB
Line 
1// ===============================================================
2/*                                                                 */
3//   File      : client.c
4//   Purpose   :
5/*                                                                 */
6//   Institute of Microbiology (Technical University Munich)
7//   http://www.arb-home.de/
8/*                                                                 */
9// ===============================================================
10
11#include <netdb.h>
12#include <netinet/tcp.h>
13#include <sys/stat.h>
14#include <sys/un.h>
15
16#include <unistd.h>
17#include <cstdarg>
18
19#include <arb_cs.h>
20
21#include "client_privat.h"
22#include "client.h"
23
24#include "trace.h"
25
26#define aisc_assert(cond) arb_assert(cond)
27
28// AISC_MKPT_PROMOTE:#include <client_types.h>
29
30#define AISC_MAGIC_NUMBER_FILTER 0xffffff00
31
32static const char *err_connection_problems = "CONNECTION PROBLEMS";
33
34int aisc_core_on_error = 1;
35
36#define CORE()                                                  \
37    do {                                                        \
38        if (aisc_core_on_error) {                               \
39            ARB_SIGSEGV(true);                                  \
40        }                                                       \
41    } while (0)
42
43aisc_com *aisc_client_link;
44
45static int aisc_print_error_to_stderr = 1;
46
47#define ERRBUF_SIZE 300
48static char errbuf[ERRBUF_SIZE];
49
50#define PRTERR(msg) if (aisc_print_error_to_stderr) fprintf(stderr, "%s: %s\n", msg, link->error);
51
52// -----------------------------
53//      bytestring handling
54
55
56static void aisc_c_add_to_bytes_queue(aisc_com *link, char *data, int size) {
57    aisc_bytes_list *bl = (aisc_bytes_list *)calloc(sizeof(*bl), 1);
58#ifndef NDEBUG
59    memset(bl, 0, sizeof(*bl)); // @@@ clear mem needed to avoid (rui's)
60#endif
61    bl->data = data;
62    bl->size = size;
63
64    if (link->aisc_client_bytes_first) {
65        link->aisc_client_bytes_last->next = bl;
66        link->aisc_client_bytes_last = bl;
67    }
68    else {
69        link->aisc_client_bytes_first = bl;
70        link->aisc_client_bytes_last = bl;
71    }
72}
73
74static int aisc_c_send_bytes_queue(aisc_com *link) {
75    int len;
76    aisc_bytes_list *bl, *bl_next;
77    for (bl = link->aisc_client_bytes_first; bl; bl=bl_next) {
78        bl_next = bl->next;
79        len = arb_socket_write(link->socket, bl->data, bl->size);
80        free(bl);
81        if (len<0)return 1;
82    };
83    link->aisc_client_bytes_first = link->aisc_client_bytes_last = NULp;
84    return 0;
85}
86
87// --------------------------
88//      message handling
89
90struct client_msg_queue {
91    client_msg_queue *next;
92    int               message_type;
93    char             *message;
94};
95
96static int aisc_add_message_queue(aisc_com *link, long size) {
97    client_msg_queue *msg    = (client_msg_queue *) calloc(sizeof(client_msg_queue), 1);
98    char             *buffer = (char *)calloc(sizeof(char), (size_t)size);
99    long              len    = arb_socket_read(link->socket, buffer, size);
100
101    if (len != size) {
102        link->error = err_connection_problems;
103        PRTERR("AISC_ERROR");
104        return 1;
105    }
106    msg->message = strdup(buffer+sizeof(long));
107    msg->message_type = (int)*(long *)buffer;
108    free(buffer);
109
110    if (!link->message_queue) {
111        link->message_queue = (int *)msg;
112    }
113    else {
114        client_msg_queue *mp;
115        for (mp = (client_msg_queue *)link->message_queue; mp->next; mp=mp->next) ;
116        mp->next = msg;
117    }
118    return 0;
119}
120
121static int aisc_check_error(aisc_com * link) {
122    int         len;
123    long        magic_number;
124    long        size;
125
126 aisc_check_next :
127
128    link->error = NULp; // @@@ avoid (rui)
129    len = arb_socket_read(link->socket, (char *)(link->aisc_mes_buffer), 2*sizeof(long));
130    if (len != 2*sizeof(long)) {
131        link->error = err_connection_problems;
132        PRTERR("AISC_ERROR");
133        return 1;
134    }
135    if (link->aisc_mes_buffer[0] >= AISC_MESSAGE_BUFFER_LEN) {
136        link->error = err_connection_problems;
137        PRTERR("AISC_ERROR");
138        return 1;
139    }
140    magic_number = link->aisc_mes_buffer[1];
141    if ((unsigned long)(magic_number & AISC_MAGIC_NUMBER_FILTER) != (unsigned long)(link->magic & AISC_MAGIC_NUMBER_FILTER)) {
142        link->error = err_connection_problems;
143        PRTERR("AISC_ERROR");
144        return 1;
145    }
146    size = link->aisc_mes_buffer[0];
147    if (size) {
148        if (magic_number-link->magic == AISC_CCOM_MESSAGE) {
149            if (aisc_add_message_queue(link, size*sizeof(long))) return 1;
150            goto aisc_check_next;
151
152        }
153        len = arb_socket_read(link->socket, (char *)(link->aisc_mes_buffer), size * sizeof(long));
154        if (len != (long)(size*sizeof(long))) {
155            link->error = err_connection_problems;
156            PRTERR("AISC_ERROR");
157            return 1;
158        }
159        switch (magic_number-link->magic) {
160            case AISC_CCOM_OK:
161                return 0;
162            case AISC_CCOM_ERROR: {
163                const char *errmsg = (const char *)(link->aisc_mes_buffer);
164                int         length = strlen(errmsg);
165
166                if ((length+15) < ERRBUF_SIZE) {
167                    strcpy(errbuf, "SERVER_ERROR: ");
168                    strcat(errbuf, errmsg);
169                }
170                else {
171                    fprintf(stderr, "SERVER_ERROR: %s\n", errmsg);
172                    sprintf(errbuf, "SERVER_ERROR: overlong msg dumped to STDERR");
173                }
174                link->error = errbuf;
175                PRTERR("AISC_ERROR");
176                return 1;
177            }
178            default:
179                return 0;
180        }
181    }
182    return 0;
183}
184
185
186
187static long aisc_init_client(aisc_com *link) {
188    int mes_cnt;
189    mes_cnt = 2;
190    link->aisc_mes_buffer[0] = mes_cnt-2;
191    link->aisc_mes_buffer[1] = AISC_INIT+link->magic;
192    if (arb_socket_write(link->socket, (const char *)link->aisc_mes_buffer, mes_cnt * sizeof(long))) {
193        link->error = err_connection_problems;
194        PRTERR("AISC_CONN_ERROR");
195        return 0;
196    }
197    aisc_check_error(link);
198    return link->aisc_mes_buffer[0];
199}
200
201static void aisc_free_link(aisc_com *link) {
202    free(link);
203}
204
205aisc_com *aisc_open(const char *path, AISC_Object& main_obj, long magic, GB_ERROR *error) {
206    aisc_com   *link;
207    const char *err;
208
209    aisc_assert(error && !*error);
210    aisc_assert(!main_obj.exists()); // already initialized
211
212    link = (aisc_com *) calloc(sizeof(aisc_com), 1);
213    link->aisc_client_bytes_first = link->aisc_client_bytes_last = NULp;
214    link->magic = magic;
215    {
216        char *unix_name = NULp;
217        err = arb_open_socket(path, true, &link->socket, &unix_name);
218        aisc_assert(link->socket>=0);
219        free(unix_name);
220    }
221    if (err) {
222        if (*err) {
223            link->error = err;
224            PRTERR("AISC");
225        }
226        if (link->socket) {
227            shutdown(link->socket, SHUT_RDWR);
228            close(link->socket);
229        }
230        *error = link->error;
231        free(link);
232        aisc_assert(!(*error && main_obj.exists()));
233        return NULp;
234    }
235
236    main_obj.init(aisc_init_client(link));
237    if (!main_obj.exists() || link->error) {
238        *error = link->error;
239        main_obj.clear();
240        aisc_free_link(link);
241        aisc_assert(!(*error && main_obj.exists()));
242        return NULp;
243    }
244    aisc_client_link = link;
245    aisc_assert(!*error);
246    return link;
247}
248
249int aisc_close(aisc_com *link, AISC_Object& object) {
250    if (link) {
251        if (link->socket) {
252            link->aisc_mes_buffer[0] = 0;
253            link->aisc_mes_buffer[1] = 0;
254            link->aisc_mes_buffer[2] = 0;
255            arb_socket_write(link->socket, (const char *)link->aisc_mes_buffer, 3 * sizeof(long));
256            shutdown(link->socket, SHUT_RDWR);
257            close(link->socket);
258            link->socket = 0;
259        }
260        aisc_free_link(link);
261    }
262    object.clear();
263    return 0;
264}
265
266int aisc_get(aisc_com *link, int o_type, const AISC_Object& object, ...) {
267    // goes to header: __ATTR__SENTINEL
268    long    *arg_pntr[MAX_AISC_SET_GET];
269    long     arg_types[MAX_AISC_SET_GET];
270    long     mes_cnt;
271    long     arg_cnt;
272    va_list  parg;
273    long     type, o_t;
274    long     attribute, code;
275    long     count;
276    long     i, len;
277    long     size;
278
279    AISC_DUMP_SEP();
280
281    mes_cnt = 2;
282    arg_cnt = 0;
283    count   = 4;
284
285    link->aisc_mes_buffer[mes_cnt++] = object.get();
286    aisc_assert(object.type() == o_type);
287
288    va_start(parg, object);
289    while ((code=va_arg(parg, long))) {
290        attribute       = code & AISC_ATTR_MASK;
291        type            = code & AISC_VAR_TYPE_MASK;
292        o_t             = code & AISC_OBJ_TYPE_MASK;
293
294        if ((o_t != (int)o_type)) {
295            sprintf(errbuf, "ARG NR %li DON'T FIT OBJECT", count);
296            link->error = errbuf;
297            PRTERR("AISC_GET_ERROR");
298            CORE();
299            return      1;
300        };
301
302        if ((attribute > AISC_MAX_ATTR)) {
303            sprintf(errbuf, "ARG %li IS NOT AN ATTRIBUTE_TYPE", count);
304            link->error = errbuf;
305            PRTERR("AISC_GET_ERROR");
306            CORE();
307            return      1;
308        };
309        link->aisc_mes_buffer[mes_cnt++] = code;
310        arg_pntr[arg_cnt] = va_arg(parg, long *);
311        arg_types[arg_cnt++] = type;
312        count += 2;
313        if (arg_cnt>=MAX_AISC_SET_GET) {
314            sprintf(errbuf, "TOO MANY ARGS (>%i)", MAX_AISC_SET_GET);
315            link->error = errbuf;
316            PRTERR("AISC_GET_ERROR");
317            CORE();
318            return      1;
319        }
320    }
321    va_end(parg);
322    if (mes_cnt > 3) {
323        link->aisc_mes_buffer[0] = mes_cnt - 2;
324        link->aisc_mes_buffer[1] = AISC_GET+link->magic;
325        if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), 
326                             (size_t)(mes_cnt * sizeof(long)))) {
327            link->error = err_connection_problems;
328            PRTERR("AISC_GET_ERROR");
329            return 1;
330        }
331
332        if (aisc_check_error(link)) return 1;
333        mes_cnt = 0;
334        for (i=0; i<arg_cnt; i++) {
335            switch (arg_types[i]) {
336                case AISC_TYPE_INT:
337                case AISC_TYPE_COMMON:
338                    AISC_DUMP(aisc_get, int, link->aisc_mes_buffer[mes_cnt]);
339                    arg_pntr[i][0] = link->aisc_mes_buffer[mes_cnt++];
340                    break;
341                case AISC_TYPE_DOUBLE:
342                    AISC_DUMP(aisc_get, double, *(double*)(char*)/*avoid aliasing problems*/&(link->aisc_mes_buffer[mes_cnt]));
343                    ((int*)arg_pntr[i])[0] = (int)(link->aisc_mes_buffer[mes_cnt++]);
344                    ((int*)arg_pntr[i])[1] = (int)(link->aisc_mes_buffer[mes_cnt++]);
345                    break;
346                case AISC_TYPE_STRING: {
347                    char *str       = strdup((char *)(&(link->aisc_mes_buffer[mes_cnt+1])));
348                    AISC_DUMP(aisc_get, charPtr, str);
349                    arg_pntr[i][0]  = (long)str;
350                    mes_cnt        += link->aisc_mes_buffer[mes_cnt] + 1;
351                    break;
352                }
353                case AISC_TYPE_BYTES:
354                    size = arg_pntr[i][1] = link->aisc_mes_buffer[mes_cnt++];
355                    AISC_DUMP(aisc_get, int, size);
356                    if (size) {
357                        arg_pntr[i][0] = (long)calloc(sizeof(char), (size_t)size);
358                        len = arb_socket_read(link->socket, (char *)(arg_pntr[i][0]), size);
359                        if (size!=len) {
360                            link->error = err_connection_problems;
361                            PRTERR("AISC_GET_ERROR");
362                        }
363#if defined(DUMP_COMMUNICATION)
364                        aisc_dump_hex("aisc_get bytestring: ", (char *)(arg_pntr[i][0]), size);
365#endif // DUMP_COMMUNICATION
366                    }
367                    else {
368                        arg_pntr[i][0] = 0;
369                    }
370                    break;
371
372                default:
373                    link->error = "UNKNOWN TYPE";
374                    PRTERR("AISC_GET_ERROR");
375                    CORE();
376                    return 1;
377            }
378        }
379
380    }
381    return 0;
382}
383
384long *aisc_debug_info(aisc_com *link, int o_type, const AISC_Object& object, int attribute) {
385    int mes_cnt;
386    int o_t;
387
388    mes_cnt = 2;
389    o_t     = attribute & AISC_OBJ_TYPE_MASK;
390    if ((o_t != (int)o_type)) {
391        link->error = "ATTRIBUTE DON'T FIT OBJECT";
392        PRTERR("AISC_DEBUG_ERROR");
393        CORE();
394        return NULp;
395    };
396    attribute = attribute&0xffff;
397    if ((attribute > AISC_MAX_ATTR)) {
398        link->error = "CLIENT DEBUG NOT CORRECT TYPE";
399        PRTERR("AISC_DEBUG_ERROR");
400        CORE();
401        return NULp;
402    };
403    aisc_assert(object.type() == o_type);
404    link->aisc_mes_buffer[mes_cnt++] = object.get();
405    link->aisc_mes_buffer[mes_cnt++] = attribute;
406    link->aisc_mes_buffer[0] = mes_cnt - 2;
407    link->aisc_mes_buffer[1] = AISC_DEBUG_INFO+link->magic;
408    if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
409        link->error = err_connection_problems;
410        PRTERR("AISC_GET_ERROR");
411        return NULp;
412    }
413    if (aisc_check_error(link)) return NULp;
414    return &(link->aisc_mes_buffer[0]);
415}
416
417
418inline char *part_of(const char *str, size_t max_len, size_t str_len) {
419    aisc_assert(strlen(str) == str_len);
420    char *part;
421    if (str_len <= max_len) {
422        part = strdup(str);
423    }
424    else {
425        const int DOTS = 3;
426        int       copy = max_len-DOTS;
427
428        part = (char*)malloc(max_len+1);
429        memcpy(part, str, copy);
430        memset(part+copy, '.', DOTS);
431       
432        part[max_len] = 0;
433    }
434    return part;
435}
436
437static int aisc_collect_sets(aisc_com *link, int mes_cnt, va_list parg, int o_type, int count) {
438    int arg_cnt = 0;
439
440    AISC_DUMP_SEP();
441
442    int code;
443    while ((code=va_arg(parg, int))) {
444        int attribute = code & AISC_ATTR_MASK;
445        int type      = code & AISC_VAR_TYPE_MASK;
446        int o_t       = code & AISC_OBJ_TYPE_MASK;
447
448        if (code != AISC_INDEX) {
449            if ((o_t != (int)o_type)) {
450                sprintf(errbuf, "ATTRIBUTE ARG NR %i DON'T FIT OBJECT", count);
451                link->error = errbuf;
452                PRTERR("AISC_SET_ERROR");
453                CORE();
454                return 0;
455            }
456            if ((attribute > AISC_MAX_ATTR)) {
457                sprintf(errbuf, "ARG %i IS NOT AN ATTRIBUTE_TYPE", count);
458                link->error = errbuf;
459                PRTERR("AISC_SET_ERROR");
460                CORE();
461                return 0;
462            }
463        }
464        link->aisc_mes_buffer[mes_cnt++] = code;
465        switch (type) {
466            case AISC_TYPE_INT:
467            case AISC_TYPE_COMMON:
468                link->aisc_mes_buffer[mes_cnt++] = va_arg(parg, long);
469                AISC_DUMP(aisc_collect_sets, int, link->aisc_mes_buffer[mes_cnt-1]);
470                break;
471            case AISC_TYPE_DOUBLE: {
472                double_xfer darg;
473
474                darg.as_double = va_arg(parg, double);
475                AISC_DUMP(aisc_collect_sets, double, darg.as_double);
476
477                link->aisc_mes_buffer[mes_cnt++] = darg.as_int[0];
478                link->aisc_mes_buffer[mes_cnt++] = darg.as_int[1];
479                break;
480            }
481            case AISC_TYPE_STRING: {
482                const char *str = va_arg(parg, const char *);
483                aisc_assert(str);
484                AISC_DUMP(aisc_collect_sets, charPtr, str);
485                size_t len = strlen(str)+1;
486                if (len > AISC_MAX_STRING_LEN) {
487                    char *strpart = part_of(str, AISC_MAX_STRING_LEN-40, len-1);
488                    sprintf(errbuf, "ARG %i: STRING \'%s\' TOO LONG", count+2, strpart);
489                    free(strpart);
490
491                    link->error = errbuf;
492                    PRTERR("AISC_SET_ERROR");
493                    CORE();
494
495                    return 0;
496                }
497                size_t ilen = (len)/sizeof(long) + 1;
498                link->aisc_mes_buffer[mes_cnt++] = ilen;
499                link->aisc_mes_buffer[mes_cnt+ilen-1] = 0; // make sure last sent long is completely initialized ('str' may only use part of it)
500                memcpy((char *)(&(link->aisc_mes_buffer[mes_cnt])), str, len);
501                mes_cnt += ilen;
502                break;
503            }
504            case AISC_TYPE_BYTES: {
505                bytestring *bs;
506                bs = va_arg(parg, bytestring *);
507                AISC_DUMP(aisc_collect_sets, int, bs->size);
508                if (bs->data && bs->size) {
509                    aisc_c_add_to_bytes_queue(link, bs->data, bs->size);
510#if defined(DUMP_COMMUNICATION)
511                    aisc_dump_hex("aisc_collect_sets bytestring: ", bs->data, bs->size);
512#endif // DUMP_COMMUNICATION
513                }
514                link->aisc_mes_buffer[mes_cnt++] = bs->size;              // size
515                break;
516            }
517            default:
518                link->error = "UNKNOWN TYPE";
519                PRTERR("AISC_SET_ERROR");
520                CORE();
521                return 0;
522        }
523
524        count += 2;
525        if ((arg_cnt++) >= MAX_AISC_SET_GET) {
526            sprintf(errbuf, "TOO MANY ARGS (%i>%i)", arg_cnt, MAX_AISC_SET_GET);
527            link->error = errbuf;
528            PRTERR("AISC_SET_ERROR");
529            CORE();
530            return      0;
531        }
532    }
533    return mes_cnt;
534}
535
536 // @@@ DRY aisc_put vs aisc_nput
537 // @@@ the difference between aisc_put and aisc_nput is: aisc_put may return an error from server
538
539int aisc_put(aisc_com *link, int o_type, const AISC_Object& object, ...) { // goes to header: __ATTR__SENTINEL
540    aisc_assert(object.type() == o_type);
541
542    int mes_cnt = 2;
543    link->aisc_mes_buffer[mes_cnt++] = object.get();
544    link->aisc_mes_buffer[mes_cnt++] = o_type;
545
546    va_list parg;
547    va_start(parg, object);
548    if (!(mes_cnt = aisc_collect_sets(link, mes_cnt, parg, o_type, 4))) return 1;
549
550    if (mes_cnt > 3) {
551        link->aisc_mes_buffer[0] = mes_cnt - 2;
552        link->aisc_mes_buffer[1] = AISC_SET+link->magic;
553        if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
554            link->error = err_connection_problems;
555            PRTERR("AISC_SET_ERROR");
556            return 1;
557        }
558        if (aisc_c_send_bytes_queue(link)) return 1;
559        if (aisc_check_error(link)) return 1;
560    }
561    return 0;
562}
563
564int aisc_nput(aisc_com *link, int o_type, const AISC_Object& object, ...) { // goes to header: __ATTR__SENTINEL
565    aisc_assert(object.type() == o_type);
566   
567    int mes_cnt = 2;
568    link->aisc_mes_buffer[mes_cnt++] = object.get();
569    link->aisc_mes_buffer[mes_cnt++] = o_type;
570
571    va_list parg;
572    va_start(parg, object);
573    if (!(mes_cnt = aisc_collect_sets(link, mes_cnt, parg, o_type, 4))) {
574        return 1;
575    }
576
577    if (mes_cnt > 3) {
578        link->aisc_mes_buffer[0] = mes_cnt - 2;
579        link->aisc_mes_buffer[1] = AISC_NSET+link->magic;
580
581        if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
582            link->error = err_connection_problems;
583            PRTERR("AISC_SET_ERROR");
584            return 1;
585        }
586        if (aisc_c_send_bytes_queue(link)) {
587            return 1;
588        }
589    }
590    return 0;
591}
592
593int aisc_create(aisc_com *link, int father_type, const AISC_Object& father,
594                int attribute,  int object_type, AISC_Object& object, ...)
595{
596    // goes to header: __ATTR__SENTINEL
597    // arguments in '...' set elements of CREATED object (not of father)
598    int mes_cnt;
599    va_list parg;
600    mes_cnt = 2;
601    if ((father_type&0xff00ffff)) {
602        link->error = "FATHER_TYPE UNKNOWN";
603        PRTERR("AISC_CREATE_ERROR");
604        CORE();
605        return 1;
606    }
607    if ((object_type&0xff00ffff)) {
608        link->error = "OBJECT_TYPE UNKNOWN";
609        PRTERR("AISC_CREATE_ERROR");
610        CORE();
611        return 1;
612    }
613    aisc_assert(father.type() == father_type);
614    aisc_assert(object.type() == object_type);
615    link->aisc_mes_buffer[mes_cnt++] = father_type;
616    link->aisc_mes_buffer[mes_cnt++] = father.get();
617    link->aisc_mes_buffer[mes_cnt++] = attribute;
618    link->aisc_mes_buffer[mes_cnt++] = object_type;
619    if (father_type != (attribute & AISC_OBJ_TYPE_MASK)) {
620        link->error = "ATTRIBUTE TYPE DON'T FIT OBJECT";
621        PRTERR("AISC_CREATE_ERROR");
622        CORE();
623        return 1;
624    }
625    va_start(parg, object);
626    if (!(mes_cnt = aisc_collect_sets(link, mes_cnt, parg, object_type, 7))) return 1;
627    link->aisc_mes_buffer[0] = mes_cnt - 2;
628    link->aisc_mes_buffer[1] = AISC_CREATE+link->magic;
629    if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
630        link->error = err_connection_problems;
631        PRTERR("AISC_CREATE_ERROR");
632        return 1;
633    }
634    if (aisc_c_send_bytes_queue(link)) return 1;
635    if (aisc_check_error(link)) return 1;
636    object.init(link->aisc_mes_buffer[0]);
637    return 0;
638}
639
640/* --------------------------------------------------------------------------------
641 * Note: it's not possible to define unit tests here - they won't execute
642 * Instead put your tests into ../../SERVERCNTRL/servercntrl.cxx@UNIT_TESTS
643 */
644
645
Note: See TracBrowser for help on using the repository browser.