source: tags/ms_r16q2/AISC_COM/C/client.c

Last change on this file was 14496, checked in by westram, 8 years ago
  • aisc_collect_sets
    • fix locals
    • avoid uninitialized bytes behind aisc_string by initializing last long
  • describe wrong parameter types as possible cause of valgrind reports
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 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        char *unix_name = 0;
208        err = arb_open_socket(path, true, &link->socket, &unix_name);
209        aisc_assert(link->socket>=0);
210        free(unix_name);
211    }
212    if (err) {
213        if (*err) {
214            link->error = err;
215            PRTERR("AISC");
216        }
217        if (link->socket) {
218            shutdown(link->socket, SHUT_RDWR);
219            close(link->socket);
220        }
221        *error = link->error;
222        free(link);
223        aisc_assert(!(*error && main_obj.exists()));
224        return 0;
225    }
226
227    main_obj.init(aisc_init_client(link));
228    if (!main_obj.exists() || link->error) {
229        *error = link->error;
230        main_obj.clear();
231        aisc_free_link(link);
232        aisc_assert(!(*error && main_obj.exists()));
233        return 0;
234    }
235    aisc_client_link = link;
236    aisc_assert(!*error);
237    return link;
238}
239
240int aisc_close(aisc_com *link, AISC_Object& object) {
241    if (link) {
242        if (link->socket) {
243            link->aisc_mes_buffer[0] = 0;
244            link->aisc_mes_buffer[1] = 0;
245            link->aisc_mes_buffer[2] = 0;
246            arb_socket_write(link->socket, (const char *)link->aisc_mes_buffer, 3 * sizeof(long));
247            shutdown(link->socket, SHUT_RDWR);
248            close(link->socket);
249            link->socket = 0;
250        }
251        aisc_free_link(link);
252    }
253    object.clear();
254    return 0;
255}
256
257int aisc_get(aisc_com *link, int o_type, const AISC_Object& object, ...)
258{
259    // goes to header: __ATTR__SENTINEL
260    long    *arg_pntr[MAX_AISC_SET_GET];
261    long     arg_types[MAX_AISC_SET_GET];
262    long     mes_cnt;
263    long     arg_cnt;
264    va_list  parg;
265    long     type, o_t;
266    long     attribute, code;
267    long     count;
268    long     i, len;
269    long     size;
270
271    AISC_DUMP_SEP();
272
273    mes_cnt = 2;
274    arg_cnt = 0;
275    count   = 4;
276
277    link->aisc_mes_buffer[mes_cnt++] = object.get();
278    aisc_assert(object.type() == o_type);
279
280    va_start(parg, object);
281    while ((code=va_arg(parg, long))) {
282        attribute       = code & AISC_ATTR_MASK;
283        type            = code & AISC_VAR_TYPE_MASK;
284        o_t             = code & AISC_OBJ_TYPE_MASK;
285
286        if ((o_t != (int)o_type)) {
287            sprintf(errbuf, "ARG NR %li DON'T FIT OBJECT", count);
288            link->error = errbuf;
289            PRTERR("AISC_GET_ERROR");
290            CORE();
291            return      1;
292        };
293
294        if ((attribute > AISC_MAX_ATTR)) {
295            sprintf(errbuf, "ARG %li IS NOT AN ATTRIBUTE_TYPE", count);
296            link->error = errbuf;
297            PRTERR("AISC_GET_ERROR");
298            CORE();
299            return      1;
300        };
301        link->aisc_mes_buffer[mes_cnt++] = code;
302        arg_pntr[arg_cnt] = va_arg(parg, long *);
303        arg_types[arg_cnt++] = type;
304        count += 2;
305        if (arg_cnt>=MAX_AISC_SET_GET) {
306            sprintf(errbuf, "TOO MANY ARGS (>%i)", MAX_AISC_SET_GET);
307            link->error = errbuf;
308            PRTERR("AISC_GET_ERROR");
309            CORE();
310            return      1;
311        }
312    }
313    va_end(parg);
314    if (mes_cnt > 3) {
315        link->aisc_mes_buffer[0] = mes_cnt - 2;
316        link->aisc_mes_buffer[1] = AISC_GET+link->magic;
317        if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), 
318                             (size_t)(mes_cnt * sizeof(long)))) {
319            link->error = err_connection_problems;
320            PRTERR("AISC_GET_ERROR");
321            return 1;
322        }
323
324        if (aisc_check_error(link)) return 1;
325        mes_cnt = 0;
326        for (i=0; i<arg_cnt; i++) {
327            switch (arg_types[i]) {
328                case AISC_TYPE_INT:
329                case AISC_TYPE_COMMON:
330                    AISC_DUMP(aisc_get, int, link->aisc_mes_buffer[mes_cnt]);
331                    arg_pntr[i][0] = link->aisc_mes_buffer[mes_cnt++];
332                    break;
333                case AISC_TYPE_DOUBLE:
334                    AISC_DUMP(aisc_get, double, *(double*)(char*)/*avoid aliasing problems*/&(link->aisc_mes_buffer[mes_cnt]));
335                    ((int*)arg_pntr[i])[0] = (int)(link->aisc_mes_buffer[mes_cnt++]);
336                    ((int*)arg_pntr[i])[1] = (int)(link->aisc_mes_buffer[mes_cnt++]);
337                    break;
338                case AISC_TYPE_STRING: {
339                    char *str       = strdup((char *)(&(link->aisc_mes_buffer[mes_cnt+1])));
340                    AISC_DUMP(aisc_get, charPtr, str);
341                    arg_pntr[i][0]  = (long)str;
342                    mes_cnt        += link->aisc_mes_buffer[mes_cnt] + 1;
343                    break;
344                }
345                case AISC_TYPE_BYTES:
346                    size = arg_pntr[i][1] = link->aisc_mes_buffer[mes_cnt++];
347                    AISC_DUMP(aisc_get, int, size);
348                    if (size) {
349                        arg_pntr[i][0] = (long)calloc(sizeof(char), (size_t)size);
350                        len = arb_socket_read(link->socket, (char *)(arg_pntr[i][0]), size);
351                        if (size!=len) {
352                            link->error = err_connection_problems;
353                            PRTERR("AISC_GET_ERROR");
354                        }
355#if defined(DUMP_COMMUNICATION)
356                        aisc_dump_hex("aisc_get bytestring: ", (char *)(arg_pntr[i][0]), size);
357#endif // DUMP_COMMUNICATION
358                    }
359                    else {
360                        arg_pntr[i][0] = 0;
361                    }
362                    break;
363
364                default:
365                    link->error = "UNKNOWN TYPE";
366                    PRTERR("AISC_GET_ERROR");
367                    CORE();
368                    return 1;
369            }
370        }
371
372    }
373    return 0;
374}
375
376long *aisc_debug_info(aisc_com *link, int o_type, const AISC_Object& object, int attribute)
377{
378    int mes_cnt;
379    int o_t;
380
381    mes_cnt = 2;
382    o_t     = attribute & AISC_OBJ_TYPE_MASK;
383    if ((o_t != (int)o_type)) {
384        link->error = "ATTRIBUTE DON'T FIT OBJECT";
385        PRTERR("AISC_DEBUG_ERROR");
386        CORE();
387        return 0;
388    };
389    attribute = attribute&0xffff;
390    if ((attribute > AISC_MAX_ATTR)) {
391        link->error = "CLIENT DEBUG NOT CORRECT TYPE";
392        PRTERR("AISC_DEBUG_ERROR");
393        CORE();
394        return 0;
395    };
396    aisc_assert(object.type() == o_type);
397    link->aisc_mes_buffer[mes_cnt++] = object.get();
398    link->aisc_mes_buffer[mes_cnt++] = attribute;
399    link->aisc_mes_buffer[0] = mes_cnt - 2;
400    link->aisc_mes_buffer[1] = AISC_DEBUG_INFO+link->magic;
401    if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
402        link->error = err_connection_problems;
403        PRTERR("AISC_GET_ERROR");
404        return 0;
405    }
406    if (aisc_check_error(link)) return 0;
407    return &(link->aisc_mes_buffer[0]);
408}
409
410
411inline char *part_of(const char *str, size_t max_len, size_t str_len) {
412    aisc_assert(strlen(str) == str_len);
413    char *part;
414    if (str_len <= max_len) {
415        part = strdup(str);
416    }
417    else {
418        const int DOTS = 3;
419        int       copy = max_len-DOTS;
420
421        part = (char*)malloc(max_len+1);
422        memcpy(part, str, copy);
423        memset(part+copy, '.', DOTS);
424       
425        part[max_len] = 0;
426    }
427    return part;
428}
429
430static int aisc_collect_sets(aisc_com *link, int mes_cnt, va_list parg, int o_type, int count) {
431    int arg_cnt = 0;
432
433    AISC_DUMP_SEP();
434
435    int code;
436    while ((code=va_arg(parg, int))) {
437        int attribute = code & AISC_ATTR_MASK;
438        int type      = code & AISC_VAR_TYPE_MASK;
439        int o_t       = code & AISC_OBJ_TYPE_MASK;
440
441        if (code != AISC_INDEX) {
442            if ((o_t != (int)o_type)) {
443                sprintf(errbuf, "ATTRIBUTE ARG NR %i DON'T FIT OBJECT", count);
444                link->error = errbuf;
445                PRTERR("AISC_SET_ERROR");
446                CORE();
447                return 0;
448            }
449            if ((attribute > AISC_MAX_ATTR)) {
450                sprintf(errbuf, "ARG %i IS NOT AN ATTRIBUTE_TYPE", count);
451                link->error = errbuf;
452                PRTERR("AISC_SET_ERROR");
453                CORE();
454                return 0;
455            }
456        }
457        link->aisc_mes_buffer[mes_cnt++] = code;
458        switch (type) {
459            case AISC_TYPE_INT:
460            case AISC_TYPE_COMMON:
461                link->aisc_mes_buffer[mes_cnt++] = va_arg(parg, long);
462                AISC_DUMP(aisc_collect_sets, int, link->aisc_mes_buffer[mes_cnt-1]);
463                break;
464            case AISC_TYPE_DOUBLE: {
465                double_xfer darg;
466
467                darg.as_double = va_arg(parg, double);
468                AISC_DUMP(aisc_collect_sets, double, darg.as_double);
469
470                link->aisc_mes_buffer[mes_cnt++] = darg.as_int[0];
471                link->aisc_mes_buffer[mes_cnt++] = darg.as_int[1];
472                break;
473            }
474            case AISC_TYPE_STRING: {
475                const char *str = va_arg(parg, const char *);
476                aisc_assert(str);
477                AISC_DUMP(aisc_collect_sets, charPtr, str);
478                size_t len = strlen(str)+1;
479                if (len > AISC_MAX_STRING_LEN) {
480                    char *strpart = part_of(str, AISC_MAX_STRING_LEN-40, len-1);
481                    sprintf(errbuf, "ARG %i: STRING \'%s\' TOO LONG", count+2, strpart);
482                    free(strpart);
483
484                    link->error = errbuf;
485                    PRTERR("AISC_SET_ERROR");
486                    CORE();
487
488                    return 0;
489                }
490                size_t ilen = (len)/sizeof(long) + 1;
491                link->aisc_mes_buffer[mes_cnt++] = ilen;
492                link->aisc_mes_buffer[mes_cnt+ilen-1] = 0; // make sure last sent long is completely initialized ('str' may only use part of it)
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>%i)", arg_cnt, 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
575        if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
576            link->error = err_connection_problems;
577            PRTERR("AISC_SET_ERROR");
578            return 1;
579        }
580        if (aisc_c_send_bytes_queue(link)) {
581            return 1;
582        }
583    }
584    return 0;
585}
586
587int aisc_create(aisc_com *link, int father_type, const AISC_Object& father,
588                int attribute,  int object_type, AISC_Object& object, ...)
589{
590    // goes to header: __ATTR__SENTINEL
591    // arguments in '...' set elements of CREATED object (not of father)
592    int mes_cnt;
593    va_list parg;
594    mes_cnt = 2;
595    if ((father_type&0xff00ffff)) {
596        link->error = "FATHER_TYPE UNKNOWN";
597        PRTERR("AISC_CREATE_ERROR");
598        CORE();
599        return 1;
600    }
601    if ((object_type&0xff00ffff)) {
602        link->error = "OBJECT_TYPE UNKNOWN";
603        PRTERR("AISC_CREATE_ERROR");
604        CORE();
605        return 1;
606    }
607    aisc_assert(father.type() == father_type);
608    aisc_assert(object.type() == object_type);
609    link->aisc_mes_buffer[mes_cnt++] = father_type;
610    link->aisc_mes_buffer[mes_cnt++] = father.get();
611    link->aisc_mes_buffer[mes_cnt++] = attribute;
612    link->aisc_mes_buffer[mes_cnt++] = object_type;
613    if (father_type != (attribute & AISC_OBJ_TYPE_MASK)) {
614        link->error = "ATTRIBUTE TYPE DON'T FIT OBJECT";
615        PRTERR("AISC_CREATE_ERROR");
616        CORE();
617        return 1;
618    }
619    va_start(parg, object);
620    if (!(mes_cnt = aisc_collect_sets(link, mes_cnt, parg, object_type, 7))) return 1;
621    link->aisc_mes_buffer[0] = mes_cnt - 2;
622    link->aisc_mes_buffer[1] = AISC_CREATE+link->magic;
623    if (arb_socket_write(link->socket, (const char *)(link->aisc_mes_buffer), mes_cnt * sizeof(long))) {
624        link->error = err_connection_problems;
625        PRTERR("AISC_CREATE_ERROR");
626        return 1;
627    }
628    if (aisc_c_send_bytes_queue(link)) return 1;
629    if (aisc_check_error(link)) return 1;
630    object.init(link->aisc_mes_buffer[0]);
631    return 0;
632}
633
634/* --------------------------------------------------------------------------------
635 * Note: it's not possible to define unit tests here - they won't execute
636 * Instead put your tests into ../../SERVERCNTRL/servercntrl.cxx@UNIT_TESTS
637 */
638
639
Note: See TracBrowser for help on using the repository browser.