#include #include #include #include #include #include #include #include #include #include #include #include #include #include "trace.h" #define FD_SET_TYPE #if defined(DEBUG) // #define SERVER_TERMINATE_ON_CONNECTION_CLOSE #endif // DEBUG #include #include #include #include #include // AISC_MKPT_PROMOTE:#include #include "server.h" #include #include #include // AISC_MKPT_PROMOTE:#ifndef _STDIO_H // AISC_MKPT_PROMOTE:#include // AISC_MKPT_PROMOTE:#endif using namespace AISC_NAMESPACE; // AISC_NAMESPACE has to be defined via CLI #define aisc_assert(cond) arb_assert(cond) #define AISC_SERVER_OK 1 #define AISC_SERVER_FAULT 0 #define MAX_QUEUE_LEN 5 #define AISC_MAGIC_NUMBER_FILTER 0xffffff00 // ------------------------- // some structures #ifdef __cplusplus extern "C" { #endif struct Socinf { Socinf *next; int socket; aisc_destroy_callback destroy_callback; long destroy_clientdata; int lasttime; }; #ifdef __cplusplus } #endif struct pollfd; struct Hs_struct : virtual Noncopyable { int hso; Socinf *soci; struct pollfd *fds; unsigned long nfds; int nsoc; int timeout; int fork; char *unix_name; Hs_struct() : hso(0), soci(NULp), fds(NULp), nfds(0), nsoc(0), timeout(0), fork(0), unix_name(NULp) {} ~Hs_struct() { freenull(unix_name); } }; struct aisc_bytes_list { char *data; int size; aisc_bytes_list *next; }; static aisc_bytes_list *aisc_server_bytes_first; static aisc_bytes_list *aisc_server_bytes_last; extern char *aisc_object_names[]; extern char **aisc_attribute_names_list[]; extern aisc_talking_func_long *aisc_talking_functions_get[]; extern aisc_talking_func_long *aisc_talking_functions_set[]; extern aisc_talking_func_longp *aisc_talking_functions_copy[]; extern aisc_talking_func_longp *aisc_talking_functions_find[]; extern aisc_talking_func_longp *aisc_talking_functions_create[]; extern aisc_talking_func_long aisc_talking_functions_delete[]; const char *aisc_server_error; const int ERRORBUFSIZE = 256; static char error_buf[ERRORBUFSIZE]; static int aisc_server_con; static Hs_struct *aisc_server_hs; // ----------------------- // error handling void aisc_server_errorf(const char *templat, ...) { // goes to header: __ATTR__FORMAT(1) va_list parg; va_start(parg, templat); int printed = vsprintf(error_buf, templat, parg); if (printed >= ERRORBUFSIZE) { fprintf(stderr, "Fatal: buffer overflow in aisc_server_errorf\n" "Error was: "); vfprintf(stderr, templat, parg); fputs("\nTerminating..\n", stderr); fflush(stderr); exit(EXIT_FAILURE); } va_end(parg); aisc_server_error = error_buf; } // ----------------------------- // valid memory tester static bool sigsegv_occurred = false; static bool catch_sigsegv = 0; static jmp_buf return_after_segv; static const char *test_address_valid(void *address, long key) { /* tests whether 'address' is a valid readable address * if 'key' != 0 -> check if 'address' contains 'key' * * returns NULp or error string */ static char buf[256]; char *result = buf; sigsegv_occurred = false; catch_sigsegv = true; // ---------------------------------------- // start of critical section // (need volatile for modified local auto variables, see man longjump) volatile long i = 0; volatile int trapped = sigsetjmp(return_after_segv, 1); if (trapped == 0) { // normal execution i = *(long *)address; // here a SIGSEGV may happen. Execution will continue in else-branch } else { // return after SEGV aisc_assert(trapped == 666); // oops - SEGV did not occur in mem access above! aisc_assert(sigsegv_occurred); // oops - wrong handler installed ? } // end of critical section // ---------------------------------------- catch_sigsegv = false; if (sigsegv_occurred) { sprintf(buf, "AISC memory manager error: can't access memory at address %p", address); } else { if (key && i != key) { sprintf(buf, "AISC memory manager error: object at address %p has wrong type (found: 0x%lx, expected: 0x%lx)", address, i, key); } else { result = NULp; // ok, address (and key) valid } } return result; } static SigHandler old_sigsegv_handler; __ATTR__NORETURN static void aisc_server_sigsegv(int sig) { sigsegv_occurred = true; if (catch_sigsegv) { siglongjmp(return_after_segv, 666); // never returns } // unexpected SEGV UNINSTALL_SIGHANDLER(SIGSEGV, aisc_server_sigsegv, old_sigsegv_handler, "aisc_server_sigsegv"); old_sigsegv_handler(sig); aisc_assert(0); // oops - old handler returned abort(); } // ---------------------------------------------- // object+attr_names for error messages const char *aisc_get_object_names(long i) { if ((i<0) || (i>=AISC_MAX_OBJECT) || (!aisc_object_names[i])) { return ""; } return aisc_object_names[i]; } static const char *aisc_get_object_attribute(long i, long j) { if ((i<0) || (i>=AISC_MAX_OBJECT) || (!aisc_attribute_names_list[i])) { return ""; } if ((j<0) || (j>=AISC_MAX_ATTR) || (!aisc_attribute_names_list[i][j])) { return ""; } return aisc_attribute_names_list[i][j]; } Hs_struct *open_aisc_server(const char *path, int timeout, int fork) { Hs_struct *hs = new Hs_struct; if (hs) { hs->timeout = timeout; hs->fork = fork; static int so; const char *err = arb_open_socket(path, false, &so, &hs->unix_name); if (err) { if (*err) printf("Error in open_aisc_server: %s\n", err); shutdown(so, SHUT_RDWR); close(so); delete hs; hs = NULp; } else { // install signal handlers fprintf(stderr, "Installing signal handler from open_aisc_server\n"); fflush(stderr); old_sigsegv_handler = INSTALL_SIGHANDLER(SIGSEGV, aisc_server_sigsegv, "open_aisc_server"); aisc_server_bytes_first = NULp; aisc_server_bytes_last = NULp; // simply take first address if (listen(so, MAX_QUEUE_LEN) < 0) { printf("Error in open_aisc_server: could not listen (errno=%i)\n", errno); delete hs; hs = NULp; } else { hs->hso = so; } } } return hs; } static void aisc_s_add_to_bytes_queue(char *data, int size) { aisc_bytes_list *bl; bl = (aisc_bytes_list *)calloc(sizeof(aisc_bytes_list), 1); bl->data = data; bl->size = size; if (aisc_server_bytes_first) { aisc_server_bytes_last->next = bl; aisc_server_bytes_last = bl; } else { aisc_server_bytes_first = bl; aisc_server_bytes_last = bl; } } static int aisc_s_send_bytes_queue(int socket) { aisc_bytes_list *bl, *bl_next; for (bl = aisc_server_bytes_first; bl; bl=bl_next) { bl_next = bl->next; if (arb_socket_write(socket, (char *)bl->data, bl->size)) return 1; free(bl); }; aisc_server_bytes_first = aisc_server_bytes_last = NULp; return 0; } static long aisc_talking_get(long *in_buf, int size, long *out_buf, int) { // handles AISC_GET aisc_server_error = NULp; long in_pos = 0; long out_pos = 0; long object = in_buf[in_pos++]; long object_type = (in_buf[in_pos] & AISC_OBJ_TYPE_MASK); if (object_type > (AISC_MAX_OBJECT*0x10000)) { aisc_server_error = "UNKNOWN OBJECT"; object = 0; } else { aisc_server_error = test_address_valid((void *)object, object_type); } object_type = object_type >> (16); AISC_DUMP_SEP(); AISC_DUMP(aisc_talking_get, int, object_type); long attribute = 0; long erg = 0; while (!aisc_server_error && (in_pos < size)) { long code = in_buf[in_pos]; long type = (code & AISC_VAR_TYPE_MASK); attribute = (code & AISC_ATTR_MASK); aisc_talking_func_long *functions = aisc_talking_functions_get[object_type]; if (!functions) { aisc_server_error = "OBJECT HAS NO ATTRIBUTES"; attribute = 0; break; } if (attribute > AISC_MAX_ATTR) { sprintf(error_buf, "ATTRIBUTE %lx OUT of RANGE", attribute); aisc_server_error = error_buf; attribute = 0; break; } aisc_talking_func_long function = functions[attribute]; if (!function) { sprintf(error_buf, "DON'T KNOW ATTRIBUTE %li", attribute); aisc_server_error = error_buf; break; } AISC_DUMP(aisc_talking_get, int, attribute); AISC_DUMP(aisc_talking_get, int, type); double_xfer derg; STATIC_ASSERT(sizeof(derg.as_double) <= sizeof(derg.as_int)); if (type == AISC_TYPE_DOUBLE) { aisc_talking_func_double dfunction = AISC_CASTSIG(aisc_talking_func_double, function); derg.as_double = dfunction(object); } else { erg = function(object); } if (aisc_server_error) { break; } switch (type) { case AISC_TYPE_INT: case AISC_TYPE_COMMON: AISC_DUMP(aisc_talking_get, int, erg); out_buf[out_pos++] = erg; break; case AISC_TYPE_DOUBLE: AISC_DUMP(aisc_talking_get, double, derg.as_double); out_buf[out_pos++] = derg.as_int[0]; out_buf[out_pos++] = derg.as_int[1]; break; case AISC_TYPE_STRING: { if (!erg) erg = (long) "(null)"; long len = strlen((char *)erg); if (len > AISC_MAX_STRING_LEN) { erg = (long) "(string too long)"; len = strlen((char *)erg); } AISC_DUMP(aisc_talking_get, charPtr, (char*)erg); len += 1; len /= sizeof(long); len++; out_buf[out_pos++] = len; strcpy((char *)&out_buf[out_pos], (char *)erg); out_pos += len; break; } case AISC_TYPE_BYTES: { bytestring *bs = (bytestring *)erg; AISC_DUMP(aisc_talking_get, int, bs->size); #if defined(DUMP_COMMUNICATION) aisc_dump_hex("aisc_talking_get bytestring: ", bs->data, bs->size); #endif // DUMP_COMMUNICATION if (bs->data && bs->size) { aisc_s_add_to_bytes_queue(bs->data, bs->size); } out_buf[out_pos++] = bs->size; // size break; } default: aisc_server_error = "UNKNOWN TYPE"; break; } in_pos++; } if (aisc_server_error) { sprintf((char *) out_buf, "AISC_GET_SERVER_ERROR %s: OBJECT:%s ATTRIBUTE:%s", aisc_server_error, aisc_get_object_names(object_type), aisc_get_object_attribute(object_type, attribute)); return -((strlen((char *)out_buf) + 1) / sizeof(long) + 1); } return out_pos; } static int aisc_server_index = -1; static void aisc_talking_set_index(int */*obj*/, int i) { aisc_server_index = i; } int aisc_talking_get_index(int u, int o) { if (aisc_server_index==-1) { aisc_server_error = "AISC_SERVER_ERROR MISSING AN AISC_INDEX"; return -1; } if ((aisc_server_index=o)) { sprintf(error_buf, "AISC_SET_SERVER_ERROR: INDEX %i IS OUT OF RANGE [%i,%i]", aisc_server_index, u, o); aisc_server_error = error_buf; } AISC_DUMP(aisc_talking_get_index, int, aisc_server_index); return aisc_server_index; } static long aisc_talking_sets(long *in_buf, int size, long *out_buf, long *object, int object_type) { int blen, bsize; long in_pos, out_pos; long code, attribute, type; aisc_talking_func_long function; aisc_talking_func_long *functions; in_pos = out_pos = 0; aisc_server_index = -1; aisc_server_error = NULp; object_type = (object_type & AISC_OBJ_TYPE_MASK); attribute = 0; if (object_type > (AISC_MAX_OBJECT*0x10000)) { object_type = 0; aisc_server_error = "UNKNOWN OBJECT"; } else { aisc_server_error = test_address_valid((void *)object, object_type); } object_type = object_type>>(16); functions = aisc_talking_functions_set[object_type]; if (!functions) { sprintf(error_buf, "OBJECT %x HAS NO ATTRIBUTES", object_type); aisc_server_error = error_buf; } AISC_DUMP_SEP(); AISC_DUMP(aisc_talking_sets, int, object_type); while (!aisc_server_error && (in_pos AISC_MAX_ATTR) { sprintf(error_buf, "ATTRIBUTE %li DOESN'T EXIST", attribute); aisc_server_error = error_buf; attribute = 0; break; } if (code == AISC_INDEX) { function = AISC_CASTSIG(aisc_talking_func_long, aisc_talking_set_index); } else { function = functions[attribute]; } if (!function) { sprintf(error_buf, "ATTRIBUTE %li DOESN'T EXIST", attribute); aisc_server_error = error_buf; break; } AISC_DUMP(aisc_talking_sets, int, attribute); AISC_DUMP(aisc_talking_sets, int, type); switch (type) { case AISC_TYPE_INT: case AISC_TYPE_COMMON: AISC_DUMP(aisc_talking_sets, long, in_buf[in_pos]); function((long)object, in_buf[in_pos++]); break; case AISC_TYPE_DOUBLE: { double_xfer derg; derg.as_int[0] = in_buf[in_pos++]; derg.as_int[1] = in_buf[in_pos++]; AISC_DUMP(aisc_talking_sets, double, derg.as_double); function((long)object, derg.as_double); break; } case AISC_TYPE_STRING: { char *str = strdup((char *)&(in_buf[in_pos+1])); AISC_DUMP(aisc_talking_sets, charPtr, str); function((long)object, str); in_pos += in_buf[in_pos]+1; break; } case AISC_TYPE_BYTES: bsize = (int)in_buf[in_pos++]; AISC_DUMP(aisc_talking_sets, int, bsize); if (bsize) { long *ptr = (long*)calloc(sizeof(char), bsize); blen = arb_socket_read(aisc_server_con, (char *)ptr, bsize); if (bsize!=blen) { aisc_server_error = "CONNECTION PROBLEMS IN BYTESTRING"; free(ptr); } else { bytestring bs; bs.data = (char *)ptr; bs.size = bsize; #if defined(DUMP_COMMUNICATION) aisc_dump_hex("aisc_talking_sets bytestring: ", (char*)ptr, bsize); #endif // DUMP_COMMUNICATION function((long)object, &bs); } } else { function((long)object, 0); } break; default: aisc_server_error = "UNKNOWN TYPE"; break; } } if (aisc_server_error) { sprintf((char *) out_buf, "AISC_SET_SERVER_ERROR %s: OBJECT:%s ATTRIBUTE:%s", aisc_server_error, aisc_get_object_names(object_type), aisc_get_object_attribute(object_type, attribute)); return -((strlen((char *)out_buf) + 1) / sizeof(long) + 1); } return 0; } static long aisc_talking_set(long *in_buf, int size, long *out_buf, int) { // handles AISC_SET aisc_server_error = NULp; int in_pos = 0; long object = in_buf[in_pos++]; int object_type = ((int)in_buf[in_pos++]) & AISC_OBJ_TYPE_MASK; return aisc_talking_sets(&(in_buf[in_pos]), size-in_pos, out_buf, (long *)object, object_type); } static long aisc_talking_nset(long *in_buf, int size, long *out_buf, int) { // handles AISC_NSET aisc_server_error = NULp; int in_pos = 0; long object = in_buf[in_pos++]; int object_type = (int)(in_buf[in_pos++] & AISC_OBJ_TYPE_MASK); aisc_talking_sets(&(in_buf[in_pos]), size-in_pos, out_buf, (long *)object, object_type); return AISC_NO_ANSWER; } static struct aisc_static_set_mem { long *ibuf, *obuf; int size, type; } md; long aisc_make_sets(long *obj) { if (md.size>0) { return aisc_talking_sets(md.ibuf, md.size, md.obuf, obj, md.type); } else { return 0; } } static long aisc_talking_create(long *in_buf, int size, long *out_buf, int) { // handles AISC_CREATE aisc_server_error = NULp; int in_pos = 0; long father_type = in_buf[in_pos++]; long father = in_buf[in_pos++]; long *erg = NULp; for (int i=0; i<1; i++) { if ((father_type&0xff00ffff) || (((unsigned int)father_type& 0xff0000) >= (AISC_MAX_OBJECT*0x10000))) { aisc_server_error = "AISC_CREATE_SERVER_ERROR: FATHER UNKNOWN"; break; } aisc_server_error = test_address_valid((void *)father, father_type); if (aisc_server_error) break; father_type = father_type>>16; aisc_talking_func_longp *functions = aisc_talking_functions_create[father_type]; long code = in_buf[in_pos++]; long attribute = code & AISC_ATTR_MASK; long object_type = in_buf[in_pos++]; if (!functions) { sprintf(error_buf, "AISC_CREATE_SERVER_ERROR: FATHER %s DOESN'T HAVE TARGET-ATTRIBUTE %s", aisc_get_object_names(father_type), aisc_get_object_attribute(father_type, attribute)); aisc_server_error = error_buf; break; } if (attribute > AISC_MAX_ATTR) { aisc_server_error = "AISC_CREATE_SERVER_ERROR: UNKNOWN ATTRIBUTE"; break; } aisc_talking_func_longp function = functions[attribute]; if (!function) { sprintf(error_buf, "AISC_CREATE_SERVER_ERROR: FATHER %s FATHER DOESN'T HAVE TARGET-ATTRIBUTE %s", aisc_get_object_names(father_type), aisc_get_object_attribute(father_type, attribute)); aisc_server_error = error_buf; break; } md.ibuf = &(in_buf[in_pos]); md.obuf = out_buf; md.size = size - in_pos; md.type = (int)object_type; erg = function(father); } if (aisc_server_error) { sprintf((char *) out_buf, "%s", aisc_server_error); return -((strlen(aisc_server_error) + 1) / sizeof(long) + 1); } else { out_buf[0] = (long)erg; return 1; } } static long aisc_talking_copy(long *in_buf, int size, long *out_buf, int /*max_size*/) { // handles AISC_COPY aisc_server_error = NULp; int in_pos = 0; long object = in_buf[in_pos++]; int father_type = (int)in_buf[in_pos++]; long father = in_buf[in_pos++]; long *erg = NULp; for (int i=0; i<1; i++) { if ((father_type&0xff00ffff) || (((unsigned int)father_type& 0xff0000) >= (AISC_MAX_OBJECT*0x10000))) { aisc_server_error = "AISC_COPY_SERVER_ERROR: FATHER UNKNOWN"; break; } aisc_server_error = test_address_valid((void *)father, father_type); if (aisc_server_error) break; father_type = father_type>>16; aisc_talking_func_longp *functions = aisc_talking_functions_copy[father_type]; if (!functions) { aisc_server_error = "AISC_COPY_SERVER_ERROR: FATHER DOESN'T HAVE TARGET-ATTRIBUTES"; break; } int code = (int)in_buf[in_pos++]; int object_type = (int)in_buf[in_pos++]; int attribute = code & AISC_ATTR_MASK; if (attribute > AISC_MAX_ATTR) { aisc_server_error = "AISC_COPY_SERVER_ERROR: UNKNOWN ATTRIBUTE"; break; } aisc_talking_func_longp function = functions[attribute]; if (!function) { sprintf(error_buf, "AISC_COPY_SERVER_ERROR: FATHER %s DOESN'T HAVE TARGET-ATTRIBUTE %s", aisc_get_object_names(father_type), aisc_get_object_attribute(father_type, attribute)); aisc_server_error = error_buf; break; } aisc_server_error = test_address_valid((void *)object, object_type); if (aisc_server_error) break; md.ibuf = &(in_buf[in_pos]); md.obuf = out_buf; md.size = size - in_pos; md.type = object_type; erg = function(father, object); } if (aisc_server_error) { sprintf((char *) out_buf, "%s", aisc_server_error); return -((strlen(aisc_server_error) + 1) / sizeof(long) + 1); } else { out_buf[0] = (long)erg; return 1; } } static long aisc_talking_find(long *in_buf, int /*size*/, long *out_buf, int /*max_size*/) { // handles AISC_FIND aisc_server_error = NULp; int in_pos = 0; long father_type = in_buf[in_pos++]; long father = in_buf[in_pos++]; long *erg = NULp; for (int i = 0; i < 1; i++) { if ((father_type & 0xff00ffff) || (((unsigned int) father_type & 0xff0000) >= (AISC_MAX_OBJECT*0x10000))) { aisc_server_error = "AISC_FIND_SERVER_ERROR: FATHER UNKNOWN"; break; } aisc_server_error = test_address_valid((void *)father, father_type); if (aisc_server_error) break; father_type = father_type>>16; aisc_talking_func_longp *functions = aisc_talking_functions_find[father_type]; long code = in_buf[in_pos++]; long attribute = code & AISC_ATTR_MASK; if (!functions) { aisc_server_error = "AISC_FIND_SERVER_ERROR: FATHER DON'T KNOW ATTRIBUTES FOR SEARCH"; break; } if (attribute > AISC_MAX_ATTR) { aisc_server_error = "AISC_FIND_SERVER_ERROR: UNKNOWN ATTRIBUTE"; break; } aisc_talking_func_longp function = functions[attribute]; if (!function) { sprintf(error_buf, "AISC_FIND_SERVER_ERROR: FATHER %s DON'T KNOW ATTRIBUTE %s FOR SEARCH", aisc_get_object_names(father_type), aisc_get_object_attribute(father_type, attribute)); aisc_server_error = error_buf; break; } if (in_buf[in_pos++]<=0) { aisc_server_error = " AISC_FIND_SERVER_ERROR: CANNOT FIND EMPTY IDENT"; break; } erg = function(father, &(in_buf[in_pos])); } if (aisc_server_error) { sprintf((char *) out_buf, "%s", aisc_server_error); return -((strlen(aisc_server_error) + 1) / sizeof(long) + 1); } else { out_buf[0] = (long) erg; return 1; } } extern int *aisc_main; static long aisc_talking_init(long */*in_buf*/, int /*size*/, long *out_buf, int /*max_size*/) { // handles AISC_INIT aisc_server_error = NULp; out_buf[0] = (long)aisc_main; return 1; } static long aisc_fork_server(long */*in_buf*/, int /*size*/, long */*out_buf*/, int /*max_size*/) { // handles AISC_FORK_SERVER pid_t pid = fork(); return pid<0 ? 0 : pid; // return OK(=0) when fork does not work } static long aisc_talking_delete(long *in_buf, int /*size*/, long *out_buf, int /*max_size*/) { // handles AISC_DELETE int in_pos, out_pos; long object_type; aisc_talking_func_long function; int i; long object; in_pos = out_pos = 0; aisc_server_error = NULp; object_type = in_buf[in_pos++]; object_type = (object_type & AISC_OBJ_TYPE_MASK); object = in_buf[in_pos++]; for (i = 0; i < 1; i++) { if (object_type > (AISC_MAX_OBJECT*0x10000)) { aisc_server_error = "AISC_GET_SERVER_ERROR: UNKNOWN OBJECT"; } else { aisc_server_error = test_address_valid((void *)object, object_type); } if (aisc_server_error) break; object_type = object_type >> (16); function = aisc_talking_functions_delete[object_type]; if (!function) { sprintf(error_buf, "AISC_SET_SERVER_ERROR: OBJECT %s cannot be deleted", aisc_object_names[object_type]); aisc_server_error = error_buf; break; } else { function(object); } } if (aisc_server_error) { sprintf((char *) out_buf, "%s", aisc_server_error); return -((strlen(aisc_server_error) + 1) / sizeof(long) + 1); } return 0; } static long aisc_talking_debug_info(long *in_buf, int /*size*/, long *out_buf, int /*max_size*/) { // handles AISC_DEBUG_INFO int in_pos, out_pos; long object_type, attribute; aisc_talking_func_long *functionsg; aisc_talking_func_long *functionss; aisc_talking_func_longp *functions; int i; long *object; in_pos = out_pos = 0; aisc_server_error = NULp; for (i=0; i<256; i++) out_buf[i] = 0; for (i = 0; i < 1; i++) { object = (long *)in_buf[in_pos++]; attribute = in_buf[in_pos++]; aisc_server_error = test_address_valid((void *)object, 0); if (aisc_server_error) break; object_type = *object; if ((object_type > (AISC_MAX_OBJECT*0x10000)) || (object_type&0xff00ffff) || (object_type<0x00010000)) { aisc_server_error = "AISC_DEBUGINFO_SERVER_ERROR: UNKNOWN OBJECT"; break; } attribute &= AISC_ATTR_MASK; object_type = object_type>>16; if (!aisc_talking_functions_delete[object_type]) { out_buf[0] = 1; }; if (!(functionsg=aisc_talking_functions_get[object_type])) { out_buf[1] = 2; } else { if (!functionsg[attribute]) out_buf[1] = 1; }; if (!(functionss=aisc_talking_functions_set[object_type])) { out_buf[2] = 2; } else { if (!functionss[attribute]) out_buf[2] = 1; }; if (!(functions=aisc_talking_functions_find[object_type])) { out_buf[3] = 2; } else { if (!functions[attribute]) out_buf[3] = 1; }; if (!(functions=aisc_talking_functions_create[object_type])) { out_buf[4] = 2; } else { if (!functions[attribute]) out_buf[4] = 1; }; if (!(functions=aisc_talking_functions_copy[object_type])) { out_buf[5] = 2; } else { if (!functions[attribute]) out_buf[5] = 1; }; } if (aisc_server_error) { sprintf((char *) out_buf, "%s", aisc_server_error); return -((strlen(aisc_server_error) + 1) / sizeof(long) + 1); } else { return 20; } } int aisc_broadcast(Hs_struct *hs, int message_type, const char *message) { Socinf *si; int size = message ? strlen(message) : 0; int sizeL = (size+1+sizeof(long)-1) / sizeof(long); // number of longs needed to safely store string long *out_buf = (long *)calloc(sizeL+3, sizeof(long)); if (!message) { out_buf[3] = 0; } else { char *strStart = (char*)(out_buf+3); int pad = sizeL*sizeof(long)-(size+1); aisc_assert(pad >= 0); memcpy(strStart, message, size+1); if (pad) memset(strStart+size+1, 0, pad); // avoid to send uninitialized bytes } aisc_assert(sizeL >= 1); out_buf[0] = sizeL+1; out_buf[1] = AISC_CCOM_MESSAGE; out_buf[2] = message_type; for (si=hs->soci; si; si=si->next) { arb_socket_write(si->socket, (char *)out_buf, (sizeL + 3) * sizeof(long)); } free(out_buf); return 0; } #ifdef __cplusplus extern "C" { #endif typedef long (*aisc_talking_function_type)(long*, int, long*, int); #ifdef __cplusplus } #endif static aisc_talking_function_type aisc_talking_functions[] = { aisc_talking_get, // AISC_GET aisc_talking_set, // AISC_SET aisc_talking_nset, // AISC_NSET aisc_talking_create, // AISC_CREATE aisc_talking_find, // AISC_FIND aisc_talking_copy, // AISC_COPY aisc_talking_delete, // AISC_DELETE aisc_talking_init, // AISC_INIT aisc_talking_debug_info, // AISC_DEBUG_INFO aisc_fork_server // AISC_FORK_SERVER }; static int aisc_talking(int con) { static long buf[AISC_MESSAGE_BUFFER_LEN]; static long out_buf[AISC_MESSAGE_BUFFER_LEN]; unsigned long len; static long size; long magic_number; len = arb_socket_read(con, (char *)buf, 2* sizeof(long)); if (len == 2*sizeof(long)) { aisc_server_con = con; if (buf[0] >= AISC_MESSAGE_BUFFER_LEN) return AISC_SERVER_FAULT; magic_number = buf[1]; if ((unsigned long)(magic_number & AISC_MAGIC_NUMBER_FILTER) != (unsigned long)(AISC_MAGIC_NUMBER & AISC_MAGIC_NUMBER_FILTER)) { return AISC_SERVER_FAULT; } size = buf[0]; { long expect = size*sizeof(long); aisc_assert(expect >= 0); aisc_assert(expect <= INT_MAX); len = arb_socket_read(con, (char *)buf, (int)expect); aisc_assert(len <= LONG_MAX); if ((long)len != expect) { printf(" ERROR in AISC_SERVER: Expected to get %li bytes from client (got %lu)\n", expect, len); return AISC_SERVER_OK; } } magic_number &= ~AISC_MAGIC_NUMBER_FILTER; size = (aisc_talking_functions[magic_number]) (buf, (int)size, out_buf + 2, AISC_MESSAGE_BUFFER_LEN - 2); if (size >= 0) { out_buf[1] = AISC_CCOM_OK; } else { if (size == (long)AISC_NO_ANSWER) { return AISC_SERVER_OK; } out_buf[1] = AISC_CCOM_ERROR; size *= -1; } out_buf[0] = size; if (arb_socket_write(con, (char *)out_buf, (int)(size + 2) * sizeof(long))) { return AISC_SERVER_FAULT; } if (aisc_server_bytes_first) { if (aisc_s_send_bytes_queue(con)) { return AISC_SERVER_FAULT; } } return AISC_SERVER_OK; } else { return AISC_SERVER_FAULT; } } Hs_struct *aisc_accept_calls(Hs_struct *hs) { int con; int anz, i; Socinf *si, *si_last = NULp, *sinext, *sptr; fd_set set, setex; struct timeval timeout; if (!hs) { fprintf(stderr, "AISC_SERVER_ERROR socket error (==0)\n"); } timeout.tv_sec = hs->timeout / 1000; timeout.tv_usec = (hs->timeout % 1000) * 1000; aisc_server_hs = hs; while (hs) { FD_ZERO(&set); FD_ZERO(&setex); FD_SET(hs->hso, &set); FD_SET(hs->hso, &setex); for (si=hs->soci, i=1; si; si=si->next, i++) { FD_SET(si->socket, &set); FD_SET(si->socket, &setex); } if (hs->timeout >= 0) { anz = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, FD_SET_TYPE &setex, &timeout); } else { anz = select(FD_SETSIZE, FD_SET_TYPE &set, NULp, FD_SET_TYPE &setex, NULp); } if (anz==-1) { printf("ERROR: poll in aisc_accept_calls\n"); return NULp; } if (!anz) { // timed out return hs; } // an event has occurred if ((timeout.tv_usec>=0)&&(timeout.tv_usec<100000)) timeout.tv_usec = 100000; if (FD_ISSET(hs->hso, &set)) { con = accept(hs->hso, NULp, NULp); if (hs->fork) { long id = fork(); if (!id) { return hs; } } if (con>0) { static int optval; sptr = (Socinf *)calloc(sizeof(Socinf), 1); if (!sptr) return NULp; sptr->next = hs->soci; sptr->socket = con; hs->soci=sptr; hs->nsoc++; optval = 1; setsockopt(con, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, 4); } } else { si_last = NULp; for (si=hs->soci; si; si_last=si, si=sinext) { sinext = si->next; if (FD_ISSET(si->socket, &set)) { if (AISC_SERVER_OK == aisc_talking(si->socket)) continue; } else if (!FD_ISSET(si->socket, &setex)) continue; if (close(si->socket) != 0) { printf("aisc_accept_calls: "); printf("couldn't close socket!\n"); } hs->nsoc--; if (si == hs->soci) { // first one hs->soci = si->next; } else { si_last->next = si->next; } if (si->destroy_callback) { si->destroy_callback(si->destroy_clientdata); } free(si); #ifdef SERVER_TERMINATE_ON_CONNECTION_CLOSE if (hs->nsoc == 0) { // no clients left if (hs->fork) exit(EXIT_SUCCESS); // child exits return hs; // parent exits } break; #else // normal behavior if (hs->nsoc == 0 && hs->fork) exit(EXIT_SUCCESS); break; #endif } } } // while main loop return hs; } void aisc_server_shutdown(Hs_struct*& hs) { Socinf *si; for (si=hs->soci; si; si=si->next) { shutdown(si->socket, SHUT_RDWR); close(si->socket); } shutdown(hs->hso, SHUT_RDWR); close(hs->hso); if (hs->unix_name) unlink(hs->unix_name); delete hs; hs = NULp; } // --------------------------- // special functions int aisc_add_destroy_callback(aisc_destroy_callback callback, long clientdata) { // call from server function Socinf *si; int socket = aisc_server_con; Hs_struct *hs = aisc_server_hs; if (!hs) return socket; for (si = hs->soci; si; si = si->next) { if (si->socket == socket) { if (si->destroy_callback) { fputs("Error: destroy_callback already bound (did you open two connections in client?)\n", stderr); fputs("Note: calling bound and installing new destroy_callback\n", stderr); si->destroy_callback(si->destroy_clientdata); } si->destroy_callback = callback; si->destroy_clientdata = clientdata; } } return socket; } void aisc_remove_destroy_callback() { // call from server function Socinf *si; int socket = aisc_server_con; Hs_struct *hs = aisc_server_hs; if (!hs) return; for (si = hs->soci; si; si = si->next) { if (si->socket == socket) { si->destroy_callback = NULp; si->destroy_clientdata = 0; } } } int aisc_server_save_token(FILE *fd, const char *buffer, int maxsize) { putc('{',fd); const char *p = buffer; while (maxsize-->0) { int c = *(p++); if (!c) break; if (c=='}' || c == '\\') putc('\\',fd); putc(c,fd); } putc('}',fd); return 0; } int aisc_server_load_token(FILE *fd, char *buffer, int maxsize) { int in_brackets = 0; char *p = buffer; int result = EOF; while (maxsize-- > 0) { int c = getc(fd); if (c==EOF) break; if (in_brackets) { if (c=='\\') { c = getc(fd); *(p++) = c; } else if (c!='}') { *(p++) = c; } else { result = 0; break; } } else if (c=='{') { if (p!=buffer) { *(p++) = '{'; *p=0; return 0; } else { in_brackets = 1; } } else if (c==' ' || c=='\n') { if (p!=buffer) { result = 0; break; } } else if (c=='}') { *(p++) = '}'; result = 0; break; } else { *(p++) = c; } } *p = 0; return result; // read error maxsize reached }