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

Last change on this file was 12591, checked in by epruesse, 10 years ago

AISC now uses arb_open_socket, arb_socket_write and …_read.

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