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

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