/* Read a request from a connection socket and parses its information into a * req_t struct. * Initally based on csapp echo() p.911 * Allocates memory for request hdrs * returns -1 on failure, 1 if the content is local, and 0 if the content is * remote */ int process_request(int fd, req_t* req){ size_t n; char buf[MAXLINE]; rio_t rio; req->domain = NULL; req->path = NULL; req->hdrs = NULL; //Parse domain and path information Rio_readinitb(&rio, fd); if((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0){ if(parse_req(buf, req) == -1) return -1; } else return -1; //parse header information while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0){ if(strcmp(buf, "\r\n") == 0) break; if(req->hdrs != NULL){ n = strlen(req->hdrs) + strlen(buf) + 1; req->hdrs = Realloc(req->hdrs,strlen(req->hdrs)+ n); strcat(req->hdrs, handle_hdr(buf)); } else { req->hdrs = Malloc(n+1); strcpy(req->hdrs, handle_hdr(buf)); } } return 0; }
static void main_loop(int fd) { int ret_code; char cmd_string[JSONRPC_MAX_STRING_LEN] = {0}; fd_set fds; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); jrpc_req_pkg_t req; json_t *rsp = NULL; int func_id = 0; int reg_connection = -1; char *rsp_str = malloc(JSONRPC_MAX_STRING_LEN); if (rsp_str == NULL) goto err; for (;;) { FD_ZERO(&fds); FD_SET(fd, &fds); ret_code = select(fd + 1, &fds, NULL, NULL, NULL); if (ret_code < 0) continue; memset(cmd_string, 0, sizeof(cmd_string)); ret_code = recvfrom(fd, cmd_string, sizeof(cmd_string), 0, (struct sockaddr *)&addr, &addrlen); if (ret_code < 0) continue; rsp = json_object(); if (rsp == NULL) goto err; rmm_log(INFO, "receive: %s.\n", cmd_string); parse_req(cmd_string, &req, &func_id); ret_code = process_req(func_id, &req, rsp); jrpc_req_pkg_free(&req); if (ret_code < 0) { continue; } memset(rsp_str, 0, JSONRPC_MAX_STRING_LEN); ret_code = jrpc_create_result_rsp_string(req.id, JSONRPC_ID_TYPE_NORMAL, rsp, JSON_OBJECT, rsp_str); if (ret_code < 0) continue; rmm_log(INFO, "send: %s.\n", rsp_str); sendto(fd, rsp_str, strnlen_s(rsp_str, JSONRPC_MAX_STRING_LEN)+1, 0, (struct sockaddr *)&addr, addrlen); } free(rsp_str); err: close(fd); return; }
int main(int argc, char **argv) { unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */ int c; /* * Initialize setup struct. This step is required, and initializes * internal fields in the struct. * * All the "public" fields are named exactly the way as the USB * standard describes them, namely: * * setup.bmRequestType: bitmask, bit 7 is direction * bits 6/5 is request type * (standard, class, vendor) * bits 4..0 is recipient * (device, interface, endpoint, * other) * setup.bRequest: the request itself (see get_req() for standard * requests, or specific value) * setup.wValue: a 16-bit value * setup.wIndex: another 16-bit value * setup.wLength: length of associated data transfer, direction * depends on bit 7 of bmRequestType */ LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup); while ((c = getopt(argc, argv, "i:p:v:")) != -1) switch (c) { case 'i': intr_ep = strtol(optarg, NULL, 0); break; case 'p': pid = strtol(optarg, NULL, 0); break; case 'v': vid = strtol(optarg, NULL, 0); break; default: usage(); break; } argc -= optind; argv += optind; if (vid != UINT_MAX || pid != UINT_MAX) { if (intr_ep != 0 && (intr_ep & 0x80) == 0) { fprintf(stderr, "Interrupt endpoint must be of type IN\n"); usage(); } if (argc > 0) { do_request = true; int rv = parse_req(argc, argv); if (rv < 0) return EX_USAGE; argc = rv; if (argc > 0) { for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--) { unsigned n = strtoul(argv[out_len], 0, 0); if (n > 255) fprintf(stderr, "Warning: data #%d 0x%0x > 0xff, truncating\n", out_len, n); out_buf[out_len] = (uint8_t)n; } out_len++; if (argc > 0) fprintf(stderr, "Data count exceeds maximum of %d, ignoring %d elements\n", BUFLEN, optind); } } } struct libusb20_backend *be; struct libusb20_device *dev; if ((be = libusb20_be_alloc_default()) == NULL) { perror("libusb20_be_alloc()"); return 1; } dev = NULL; while ((dev = libusb20_be_device_foreach(be, dev)) != NULL) { struct LIBUSB20_DEVICE_DESC_DECODED *ddp = libusb20_dev_get_device_desc(dev); printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n", libusb20_dev_get_desc(dev), ddp->idVendor, ddp->idProduct); if (ddp->idVendor == vid && ddp->idProduct == pid) doit(dev); } libusb20_be_free(be); return 0; }
END_TEST /* * request */ START_TEST(test_quit) { #define QUIT "quit" #define SERIALIZED "*1\r\n$4\r\n" QUIT "\r\n" #define INVALID "*2\r\n$4\r\n" QUIT "\r\n$3\r\nnow\r\n" int ret; struct element *el; test_reset(); req->type = REQ_QUIT; el = array_push(req->token); el->type = ELEM_BULK; el->bstr = (struct bstring){sizeof(QUIT) - 1, QUIT}; ret = compose_req(&buf, req); ck_assert_int_eq(ret, sizeof(SERIALIZED) - 1); ck_assert_int_eq(cc_bcmp(buf->rpos, SERIALIZED, ret), 0); el->type = ELEM_UNKNOWN; /* this effectively resets *el */ request_reset(req); ck_assert_int_eq(parse_req(req, buf), PARSE_OK); ck_assert_int_eq(req->type, REQ_QUIT); ck_assert_int_eq(req->token->nelem, 1); el = array_first(req->token); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(cc_bcmp(el->bstr.data, QUIT, sizeof(QUIT) - 1), 0); /* invalid number of arguments */ test_reset(); buf_write(buf, INVALID, sizeof(INVALID) - 1); ck_assert_int_eq(parse_req(req, buf), PARSE_EINVALID); #undef INVALID #undef SERIALIZED #undef QUIT } END_TEST START_TEST(test_ping) { #define PING "ping" #define VAL "hello" #define S_PING "*1\r\n$4\r\n" PING "\r\n" #define S_ECHO "*2\r\n$4\r\n" PING "\r\n$5\r\nhello\r\n" int ret; struct element *el; test_reset(); /* simple ping */ buf_write(buf, S_PING, sizeof(S_PING) - 1); ck_assert_int_eq(parse_req(req, buf), PARSE_OK); ck_assert_int_eq(req->type, REQ_PING); /* ping as echo */ test_reset(); req->type = REQ_PING; el = array_push(req->token); el->type = ELEM_BULK; el->bstr = (struct bstring){sizeof(PING) - 1, PING}; el = array_push(req->token); el->type = ELEM_BULK; el->bstr = (struct bstring){sizeof(VAL) - 1, VAL}; ret = compose_req(&buf, req); ck_assert_int_eq(ret, sizeof(S_ECHO) - 1); ck_assert_int_eq(cc_bcmp(buf->rpos, S_ECHO, ret), 0); el->type = ELEM_UNKNOWN; /* resets *el */ request_reset(req); ck_assert_int_eq(parse_req(req, buf), PARSE_OK); ck_assert_int_eq(req->type, REQ_PING); ck_assert_int_eq(req->token->nelem, 2); el = array_first(req->token); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(cc_bcmp(el->bstr.data, PING, sizeof(PING) - 1), 0); el = array_get(req->token, 1); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(cc_bcmp(el->bstr.data, VAL, sizeof(VAL) - 1), 0); #undef S_ECHO #undef ECHO #undef S_PING #undef QUIT } END_TEST START_TEST(test_unfin_req) { char *token[4] = { "*2\r\n", "*2\r\n$3\r\n", "*2\r\n$3\r\nfoo\r\n", "*2\r\n$3\r\nfoo\r\n$3\r\n", }; for (int i = 0; i < 4; i++) { char *pos; size_t len; len = strlen(token[i]); buf_reset(buf); buf_write(buf, token[i], len); pos = buf->rpos; ck_assert_int_eq(parse_req(req, buf), PARSE_EUNFIN); ck_assert(buf->rpos == pos); } } END_TEST /* * response */ START_TEST(test_ok) { #define OK "OK" #define SERIALIZED "+" OK "\r\n" int ret; struct element *el; test_reset(); rsp->type = ELEM_STR; el = array_push(rsp->token); el->type = ELEM_STR; el->bstr = (struct bstring){sizeof(OK) - 1, OK}; ret = compose_rsp(&buf, rsp); ck_assert_int_eq(ret, sizeof(SERIALIZED) - 1); ck_assert_int_eq(cc_bcmp(buf->rpos, SERIALIZED, ret), 0); el->type = ELEM_UNKNOWN; /* resets *el */ response_reset(rsp); ck_assert_int_eq(parse_rsp(rsp, buf), PARSE_OK); ck_assert_int_eq(rsp->type, ELEM_STR); ck_assert_int_eq(rsp->token->nelem, 1); el = array_first(rsp->token); ck_assert_int_eq(el->type, ELEM_STR); ck_assert_int_eq(cc_bcmp(el->bstr.data, OK, sizeof(OK) - 1), 0); #undef SERIALIZED #undef OK } END_TEST START_TEST(test_array_reply) { #define SERIALIZED "*5\r\n:-10\r\n$-1\r\n-ERR invalid arg\r\n+foo\r\n$5\r\nHELLO\r\n" size_t len = sizeof(SERIALIZED) - 1; struct element *el; test_reset(); buf_write(buf, SERIALIZED, len); ck_assert_int_eq(parse_rsp(rsp, buf), PARSE_OK); ck_assert_int_eq(rsp->type, ELEM_ARRAY); ck_assert_int_eq(rsp->token->nelem, 5); el = array_first(rsp->token); ck_assert_int_eq(el->type, ELEM_INT); el = array_get(rsp->token, 1); ck_assert_int_eq(el->type, ELEM_NIL); el = array_get(rsp->token, 2); ck_assert_int_eq(el->type, ELEM_ERR); el = array_get(rsp->token, 3); ck_assert_int_eq(el->type, ELEM_STR); el = array_get(rsp->token, 4); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(el->bstr.len, 5); ck_assert_int_eq(cc_bcmp(el->bstr.data, "HELLO", 5), 0); ck_assert_int_eq(buf_rsize(buf), 0); ck_assert_int_eq(compose_rsp(&buf, rsp), len); ck_assert_int_eq(buf_rsize(buf), len); ck_assert_int_eq(cc_bcmp(buf->rpos, SERIALIZED, len), 0); #undef SERIALIZED } END_TEST /* * edge cases */ START_TEST(test_empty_buf) { struct element el; test_reset(); ck_assert(!token_is_array(buf)); ck_assert_int_eq(parse_element(&el, buf), PARSE_EUNFIN); ck_assert_int_eq(parse_rsp(rsp, buf), PARSE_EUNFIN); ck_assert_int_eq(parse_req(req, buf), PARSE_EUNFIN); } END_TEST /* * request/response pool */ START_TEST(test_req_pool_basic) { #define POOL_SIZE 10 int i; struct request *reqs[POOL_SIZE]; request_options_st options = { .request_ntoken = {.type = OPTION_TYPE_UINT, .val.vuint = REQ_NTOKEN}, .request_poolsize = {.type = OPTION_TYPE_UINT, .val.vuint = POOL_SIZE}}; request_setup(&options, NULL); for (i = 0; i < POOL_SIZE; i++) { reqs[i] = request_borrow(); ck_assert_msg(reqs[i] != NULL, "expected to borrow a request"); } ck_assert_msg(request_borrow() == NULL, "expected request pool to be depleted"); for (i = 0; i < POOL_SIZE; i++) { request_return(&reqs[i]); ck_assert_msg(reqs[i] == NULL, "expected request to be nulled after return"); } request_teardown(); #undef POOL_SIZE } END_TEST START_TEST(test_rsp_pool_basic) { #define POOL_SIZE 10 int i; struct response *rsps[POOL_SIZE]; response_options_st options = { .response_ntoken = {.type = OPTION_TYPE_UINT, .val.vuint = RSP_NTOKEN}, .response_poolsize = {.type = OPTION_TYPE_UINT, .val.vuint = POOL_SIZE}}; response_setup(&options, NULL); for (i = 0; i < POOL_SIZE; i++) { rsps[i] = response_borrow(); ck_assert_msg(rsps[i] != NULL, "expected to borrow a response"); } ck_assert_msg(response_borrow() == NULL, "expected response pool to be depleted"); for (i = 0; i < POOL_SIZE; i++) { response_return(&rsps[i]); ck_assert_msg(rsps[i] == NULL, "expected response to be nulled after return"); } response_teardown(); #undef POOL_SIZE } END_TEST /* * test suite */ static Suite * redis_suite(void) { Suite *s = suite_create(SUITE_NAME); /* token */ TCase *tc_token = tcase_create("token"); suite_add_tcase(s, tc_token); tcase_add_test(tc_token, test_simple_string); tcase_add_test(tc_token, test_error); tcase_add_test(tc_token, test_integer); tcase_add_test(tc_token, test_bulk_string); tcase_add_test(tc_token, test_array); tcase_add_test(tc_token, test_nil_bulk); tcase_add_test(tc_token, test_unfin_token); /* basic requests */ TCase *tc_request = tcase_create("request"); suite_add_tcase(s, tc_request); tcase_add_test(tc_request, test_quit); tcase_add_test(tc_request, test_ping); tcase_add_test(tc_request, test_unfin_req); /* basic responses */ TCase *tc_response = tcase_create("response"); suite_add_tcase(s, tc_response); tcase_add_test(tc_response, test_ok); tcase_add_test(tc_response, test_array_reply); /* edge cases */ TCase *tc_edge = tcase_create("edge cases"); suite_add_tcase(s, tc_edge); tcase_add_test(tc_edge, test_empty_buf); /* req/rsp objects, pooling */ TCase *tc_pool = tcase_create("request/response pool"); suite_add_tcase(s, tc_pool); tcase_add_test(tc_pool, test_req_pool_basic); tcase_add_test(tc_pool, test_rsp_pool_basic); return s; } /* TODO(yao): move main to a different file, keep most test files main-less */ int main(void) { int nfail; /* setup */ test_setup(); Suite *suite = redis_suite(); SRunner *srunner = srunner_create(suite); srunner_set_log(srunner, DEBUG_LOG); srunner_run_all(srunner, CK_ENV); /* set CK_VEBOSITY in ENV to customize */ nfail = srunner_ntests_failed(srunner); srunner_free(srunner); /* teardown */ test_teardown(); return (nfail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
static int parse_format (GLogItem * glog, const char *fmt, const char *date_format, char *str) { const char *p; double serve_secs; int special = 0; struct tm tm; unsigned long long bandw, serve_time; if (str == NULL || *str == '\0') return 1; memset (&tm, 0, sizeof (tm)); /* iterate over the log format */ for (p = fmt; *p; p++) { if (*p == '%') { special++; continue; } if (special && *p != '\0') { char *pch, *sEnd, *bEnd, *tkn = NULL, *end = NULL; errno = 0; bandw = 0; serve_time = 0; serve_secs = 0; switch (*p) { /* date */ case 'd': if (glog->date) return 1; /* parse date format including dates containing spaces, * i.e., syslog date format (Jul 15 20:10:56) */ tkn = parse_string (&str, p[1], count_matches (date_format, ' ') + 1); if (tkn == NULL) return 1; end = strptime (tkn, date_format, &tm); if (end == NULL || *end != '\0') { free (tkn); return 1; } glog->date = tkn; break; /* remote hostname (IP only) */ case 'h': if (glog->host) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; if (invalid_ipaddr (tkn)) { free (tkn); return 1; } glog->host = tkn; break; /* request method */ case 'm': if (glog->method) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; if (!extract_method (tkn)) { free (tkn); return 1; } glog->method = tkn; break; /* request not including method or protocol */ case 'U': if (glog->req) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL || *tkn == '\0') return 1; if ((glog->req = decode_url (tkn)) == NULL) return 1; free (tkn); break; /* request protocol */ case 'H': if (glog->protocol) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; if (invalid_protocol (tkn)) { free (tkn); return 1; } glog->protocol = tkn; break; /* request, including method + protocol */ case 'r': if (glog->req) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; glog->req = parse_req (tkn, &glog->method, &glog->protocol); free (tkn); break; /* Status Code */ case 's': if (glog->status) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; strtol (tkn, &sEnd, 10); if (tkn == sEnd || *sEnd != '\0' || errno == ERANGE) { free (tkn); return 1; } glog->status = tkn; break; /* size of response in bytes - excluding HTTP headers */ case 'b': if (glog->resp_size) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; bandw = strtol (tkn, &bEnd, 10); if (tkn == bEnd || *bEnd != '\0' || errno == ERANGE) bandw = 0; glog->resp_size = bandw; conf.bandwidth = 1; free (tkn); break; /* referrer */ case 'R': if (glog->ref) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) tkn = alloc_string ("-"); if (tkn != NULL && *tkn == '\0') { free (tkn); tkn = alloc_string ("-"); } if (strcmp (tkn, "-") != 0) extract_referer_site (tkn, glog->site); glog->ref = tkn; break; /* user agent */ case 'u': if (glog->agent) return 1; tkn = parse_string (&str, p[1], 1); if (tkn != NULL && *tkn != '\0') { /* Make sure the user agent is decoded (i.e.: CloudFront) * and replace all '+' with ' ' (i.e.: w3c) */ glog->agent = char_replace (decode_url (tkn), '+', ' '); free (tkn); break; } else if (tkn != NULL && *tkn == '\0') { free (tkn); tkn = alloc_string ("-"); } /* must be null */ else { tkn = alloc_string ("-"); } glog->agent = tkn; break; /* time taken to serve the request, in seconds */ case 'T': if (glog->serve_time) return 1; /* ignore seconds if we have microseconds */ if (strstr (fmt, "%D") != NULL) break; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; if (strchr (tkn, '.') != NULL) serve_secs = strtod (tkn, &bEnd); else serve_secs = strtoull (tkn, &bEnd, 10); if (tkn == bEnd || *bEnd != '\0' || errno == ERANGE) serve_secs = 0; /* convert it to microseconds */ if (serve_secs > 0) glog->serve_time = serve_secs * SECS; else glog->serve_time = 0; conf.serve_usecs = 1; free (tkn); break; /* time taken to serve the request, in microseconds */ case 'D': if (glog->serve_time) return 1; tkn = parse_string (&str, p[1], 1); if (tkn == NULL) return 1; serve_time = strtoull (tkn, &bEnd, 10); if (tkn == bEnd || *bEnd != '\0' || errno == ERANGE) serve_time = 0; glog->serve_time = serve_time; conf.serve_usecs = 1; free (tkn); break; /* everything else skip it */ default: if ((pch = strchr (str, p[1])) != NULL) str += pch - str; } if ((str == NULL) || (*str == '\0')) return 0; special = 0; } else if (special && isspace (p[0])) { return 1; } else str++; } return 0; }
static void process_client(int fd) { register int ebp __asm__ ("ebp"); char reqpath[256]; char pn[1024]; struct stat st; const char *errmsg; fprintf(stderr, "\nreqpath = %p\nebp = 0x%x\nunlink = %p\n", reqpath, ebp, unlink); cur_f = fdopen(fd, "w+"); errmsg = parse_req(reqpath); if (errmsg) { http_err(500, "Error parsing request: %s", errmsg); return; } sprintf(pn, "%s/%s", cur_dir, reqpath); if (stat(pn, &st) < 0) { http_err(404, "File not found or not accessible: %s", pn); return; } if (S_ISDIR(st.st_mode)) { /* For directories, use index.html in that directory */ strcat(pn, "/index.html"); if (stat(pn, &st) < 0) { http_err(404, "File not found or not accessible: %s", pn); return; } } if (S_ISREG(st.st_mode) && (st.st_mode & S_IXUSR)) { /* executable bits -- run as CGI script */ fflush(cur_f); signal(SIGCHLD, SIG_DFL); int pid = fork(); if (pid < 0) { http_err(500, "Cannot fork: %s", strerror(errno)); return; } if (pid == 0) { /* Child process */ int nullfd = open("/dev/null", O_RDONLY); dup2(nullfd, 0); dup2(fileno(cur_f), 1); dup2(fileno(cur_f), 2); close(nullfd); fclose(cur_f); execl(pn, pn, 0); err(1, "execl"); } int status; waitpid(pid, &status, 0); fclose(cur_f); } else { /* Non-executable: serve contents */ int fd = open(pn, O_RDONLY); if (fd < 0) { http_err(500, "Cannot open %s: %s", pn, strerror(errno)); return; } fprintf(cur_f, "HTTP/1.0 200 OK\r\n"); fprintf(cur_f, "Content-Type: text/html\r\n"); fprintf(cur_f, "\r\n"); for (;;) { char readbuf[1024]; int cc = read(fd, &readbuf[0], sizeof(readbuf)); if (cc <= 0) break; fwrite(&readbuf[0], 1, cc, cur_f); } close(fd); fclose(cur_f); } }
/* * ************************************************************* * main of connection server * ************************************************************* */ int main(int argc, char *argv[]) { srv_opts_t run_options; int RequestCmd; void *res; initialize( &run_options ); get_arguments ( argc, argv, &run_options ); if( run_options.run_as_daemon ) { if( (run_options.error_code = start_daemon( &run_options )) != E_NOERR ) { do_log(&run_options, LOG_CRITERROR); cleanup_and_exit( &run_options ); } } if( (run_options.error_code = make_socket( &run_options )) != E_NOERR ) { do_log(&run_options, LOG_CRITERROR); cleanup_and_exit( &run_options ); } if( prepareThreads( &run_options ) != E_NOERR ) { do_log(&run_options, LOG_CRITERROR); cleanup_and_exit( &run_options ); } else { if( (run_options.error_code = ctl_create_thread( &run_options, MAINCTL_THREAD_NUM)) != E_NOERR ) { do_log(&run_options, LOG_CRITERROR); cleanup_and_exit( &run_options ); } } // while no exit request RequestCmd = 0; do { if( (run_options.error_code = wait_client( &run_options )) != E_NOERR ) { do_log(&run_options, LOG_CRITERROR); cleanup_and_exit( &run_options ); } else { if( (run_options.error_code = get_request( &run_options )) != E_NOERR ) { do_log(&run_options, LOG_CRITERROR); cleanup_and_exit( &run_options ); } else { switch( RequestCmd = parse_req( run_options.p_rcv_buf ) ) { case CTLREQ_EXIT: sprintf(run_options.p_rsp_buf, "Assume exit: %s\n", run_options.p_rcv_buf ); send_response(&run_options); close(run_options.cli_socket); break; case CTLREQ_API: sprintf(run_options.p_rsp_buf, "Assume API: %s\n", run_options.p_rcv_buf ); send_response(&run_options); close(run_options.cli_socket); break; default: // assume telnet request sprintf(run_options.p_rsp_buf, "Assume telnet: %s\n", run_options.p_rcv_buf ); send_response(&run_options); close(run_options.cli_socket); break; } } } } while( RequestCmd != CTLREQ_EXIT ); if( pthread_attr_destroy(&run_options.tattr) != 0 ) { run_options.error_code = E_FAIL; run_options.sys_errno = errno; sprintf( run_options.logbuffer, "destroy attr failed, errno was %d\n", errno ); do_log(&run_options, LOG_WARN); } run_options.mainctl_run = 0; run_options.api_run = 0; run_options.telnet_run = 0; if( run_options.tinfo[MAINCTL_THREAD_NUM].thread_id >= 0 ) { pthread_join(run_options.tinfo[MAINCTL_THREAD_NUM].thread_id, &res); } if( run_options.tinfo[API_THREAD_NUM].thread_id >= 0 ) { pthread_join(run_options.tinfo[API_THREAD_NUM].thread_id, &res); } if( run_options.tinfo[TELNET_THREAD_NUM].thread_id >= 0 ) { pthread_join(run_options.tinfo[TELNET_THREAD_NUM].thread_id, &res); } pthread_cancel(run_options.tinfo[MAINCTL_THREAD_NUM].thread_id); pthread_cancel(run_options.tinfo[API_THREAD_NUM].thread_id); pthread_cancel(run_options.tinfo[TELNET_THREAD_NUM].thread_id); // and die cleanup_and_exit( &run_options ); }