void Worker::run() { int ret; __dlist_t head; __dlist_t *next; Connection *conn; NOTICE("worker is running now."); while (!_stopped) { DLIST_INIT(&head); pthread_mutex_lock(&_mutex); while (DLIST_EMPTY(&_queue)) pthread_cond_wait(&_cond, &_mutex); next = DLIST_NEXT(&_queue); DLIST_REMOVE(&_queue); pthread_mutex_unlock(&_mutex); DLIST_INSERT_B(&head, next); while (!DLIST_EMPTY(&head)) { next = DLIST_NEXT(&head); DLIST_REMOVE(next); conn = GET_OWNER(next, Connection, _list); TRACE("start to process conn, sock[%d].", conn->_sock_fd); try { ret = conn->on_process(); if (ret == 0) { conn->_status = Connection::ST_PROCESSING_REQUEST_OK; TRACE("process conn ok, sock[%d].", conn->_sock_fd); } else { conn->_status = Connection::ST_PROCESSING_REQUEST_FAIL; WARNING("failed to process conn, sock[%d], ret=%d.", conn->_sock_fd, ret); } } catch (...) { WARNING("failed to process conn, sock[%d], exception catched.", conn->_sock_fd); } _server_manager->done(conn); } } NOTICE("worker is stopped by user, exiting now."); }
int do_with_read_chunk_body(struct worker_context *ctx, struct connection *conn, int closed) { if ( parse_chunk_body(ctx, conn) < 0 ) { WARNING("failed to parse chunk body."); return -1; } else if ( REQUEST_CHUNK_BODY_STATE_END == conn->_client._state ) { DEBUG("going to write to server."); struct body_buffer *buffer = GET_OWNER(conn->_client._cur_block, struct body_buffer, _list); conn->_client._next_len = buffer->_curpos - conn->_client._cur_pos; conn->_status = CONN_CONNECTING_SERVER; int curpos = 0; int ret; static const char *const s_version[] = { "", "HTTP/0.9", "HTTP/1.0", "HTTP/1.1", }; ret = snprintf(ctx->_header, MAX_HTTP_HEADER_LEN, "POST %.*s %s\r\n", (int)(conn->_client._uri_end - conn->_client._uri_start), conn->_client._uri_start, s_version[conn->_client._version]); if ( ret < 0 ) { WARNING("snprintf error[%s].", strerror_t(errno)); return -1; } curpos += ret; __dlist_t *cur; struct http_header *header; for ( cur = DLIST_NEXT(&conn->_client._headers); cur != &conn->_client._headers; cur = DLIST_NEXT(cur) ) { header = GET_OWNER(cur, struct http_header, _list); if ( header->_name_end - header->_name_start == sizeof("Transfer-Encoding") - 1 && strncasecmp(header->_name_start, "Transfer-Encoding", sizeof("Transfer-Encoding") - 1) == 0 ) { DEBUG("ignore Transfer-Encoding header."); continue; } else if ( header->_name_end - header->_name_start == sizeof("Content-Length") - 1 && strncasecmp(header->_name_start, "Content-Length", sizeof("Content-Length") - 1) == 0 ) { DEBUG("ignore Content-Length header."); continue; } ret = snprintf(ctx->_header + curpos, MAX_HTTP_HEADER_LEN - curpos, "%.*s:%.*s\r\n", (int)(header->_name_end - header->_name_start), header->_name_start, (int)(header->_value_end - header->_value_start), header->_value_start); if ( ret < 0 ) { WARNING("snprintf error[%s].", strerror_t(errno)); return -1; } curpos += ret; } ret = snprintf(ctx->_header + curpos, MAX_HTTP_HEADER_LEN - curpos, "Content-Length:%d\r\n\r\n", conn->_client._body_len); if ( ret < 0 ) { WARNING("snprintf error[%s].", strerror_t(errno)); return -1; } if ( ret >= MAX_HTTP_HEADER_LEN - curpos ) { WARNING("too long header, need[%s].", ret + curpos + 1); return -1; } curpos += ret; memcpy(conn->_client._header, ctx->_header, curpos); conn->_client._header_len = curpos; DEBUG("%s", ctx->_header); }
void NetProxy::run() { #define SET_ERROR(errno) \ do \ { \ st->_errno = errno; \ epex_detach(_epex, st->_talk->_sock, NULL); \ } while(0) ssize_t ret; netresult_t results[20]; __dlist_t attach_ok_list; __dlist_t attach_fail_list; __dlist_t *ptr; NetStub *st; int sock; int tm_left; int elasp_tm; struct timeval now; _stop = false; while (!_stop) { DLIST_INIT(&attach_ok_list); DLIST_INIT(&attach_fail_list); { AutoLock __lock(_mutex); while (!DLIST_EMPTY(&_attach_list)) { ptr = DLIST_NEXT(&_attach_list); st = GET_OWNER(ptr, NetStub, _att_list); DLIST_REMOVE(ptr); if (epex_attach(_epex, st->_talk->_sock, st, -1)) DLIST_INSERT_B(&st->_tmp_list, &attach_ok_list); else DLIST_INSERT_B(&st->_tmp_list, &attach_fail_list); } } gettimeofday(&now, NULL); while (!DLIST_EMPTY(&attach_fail_list)) { ptr = DLIST_NEXT(&attach_fail_list); st = GET_OWNER(ptr, NetStub, _tmp_list); DLIST_REMOVE(ptr); st->_errno = NET_ERR_ATTACH_FAIL; this->done(st, &now); } while (!DLIST_EMPTY(&attach_ok_list)) { ptr = DLIST_NEXT(&attach_ok_list); st = GET_OWNER(ptr, NetStub, _tmp_list); DLIST_REMOVE(ptr); st->_talk->_req_head._magic_num = MAGIC_NUM; st->_talk->_req_head._body_len = st->_talk->_req_len; st->_status = NET_ST_SEND_HEAD; if (epex_write(_epex, st->_talk->_sock, &st->_talk->_req_head, sizeof(st->_talk->_req_head), NULL, st->_timeout)) { TRACE("try to send head to sock[%d]", st->_talk->_sock); } else { SET_ERROR(NET_ERR_WRITE); } } ret = epex_poll(_epex, results, sizeof(results)/sizeof(results[0])); gettimeofday(&now, NULL); for (long i = 0; i < ret; ++i) { const netresult_t &res = results[i]; st = (NetStub *)res._user_ptr2; if (NET_OP_NOTIFY == res._op_type) { this->done(st, &now); continue; } switch (res._status) { case NET_DONE: break; case NET_ECLOSED: SET_ERROR(NET_ERR_CLOSED); continue; case NET_ETIMEOUT: SET_ERROR(NET_ERR_TIMEOUT); continue; case NET_ERROR: st->_errno = res._errno; /* fall through */ case NET_EDETACHED: continue; default: WARNING("should not be here, res._status=%hd", res._status); continue; } sock = st->_talk->_sock; if (st->_cancel) /* canceled by user */ { TRACE("sock[%d] is canceled by user", sock); epex_detach(_epex, sock, NULL); continue; } elasp_tm = (now.tv_sec - st->_start_tm.tv_sec) * 1000 + (now.tv_usec - st->_start_tm.tv_usec) / 1000; if (st->_timeout < 0) tm_left = -1; else if (st->_timeout > elasp_tm) tm_left = st->_timeout - elasp_tm; else tm_left = 0; switch (st->_status) { case NET_ST_SEND_HEAD: TRACE("send head to sock[%d] ok", sock); st->_tm._send_head = elasp_tm; st->_status = NET_ST_SEND_BODY; if (tm_left == 0) { SET_ERROR(NET_ERR_TIMEOUT); continue; } if (!epex_write(_epex, sock, st->_talk->_req_buf, st->_talk->_req_len, NULL, tm_left)) { SET_ERROR(NET_ERR_WRITE); continue; } TRACE("try to send body[%u] to sock[%d]", st->_talk->_req_len, sock); break; case NET_ST_SEND_BODY: TRACE("send body[%u] to sock[%d] ok", st->_talk->_req_len, sock); st->_tm._send_body = elasp_tm - st->_tm._send_head; st->_status = NET_ST_RECV_HEAD; if (tm_left == 0) { SET_ERROR(NET_ERR_TIMEOUT); continue; } if (!epex_read(_epex, sock, &st->_talk->_res_head, sizeof(st->_talk->_res_head), NULL, tm_left)) { SET_ERROR(NET_ERR_READ); continue; } TRACE("try to recv head from sock[%d]", sock); break; case NET_ST_RECV_HEAD: TRACE("recv head from sock[%d] ok", sock); st->_tm._recv_head = elasp_tm - st->_tm._send_body - st->_tm._send_head; if (st->_talk->_res_head._magic_num != MAGIC_NUM) { SET_ERROR(NET_ERR_MAGIC_NUM); continue; } if (st->_talk->_res_head._body_len > st->_talk->_res_len) { SET_ERROR(NET_ERR_BIG_RESP); continue; } st->_status = NET_ST_RECV_BODY; if (tm_left == 0) { SET_ERROR(NET_ERR_TIMEOUT); continue; } if (!epex_read(_epex, sock, st->_talk->_res_buf, st->_talk->_res_head._body_len, NULL, tm_left)) { SET_ERROR(NET_ERR_READ); continue; } TRACE("try to recv body[%u] from sock[%d]", st->_talk->_res_head._body_len, sock); break; case NET_ST_RECV_BODY: TRACE("recv body[%u] from sock[%d] ok", st->_talk->_res_head._body_len, sock); st->_tm._recv_body = elasp_tm - st->_tm._recv_head - st->_tm._send_body - st->_tm._send_head; st->_status = NET_ST_DONE; epex_detach(_epex, sock, NULL); TRACE("talk with sock[%d] ok", sock); break; default: WARNING("should not be here"); break; } } } NOTICE("NetPoller is stoped now"); #undef SET_ERROR }
int main(int argc, char *argv[]) { myelmt_t *newelmt; myelmt_t *elmt; myctx_t *ctx; int i; int action; int j; int r; ctx = malloc(sizeof (myctx_t)); DLIST_INIT(ctx, headlist); DLIST_INIT(ctx, taillist); for ( i = 0; i < 50000000 ; i++) { action = rand_range(0, 9); printf("action: %i\n", action); switch (action) { case ACTION_INSHEAD: elmt = malloc(sizeof (myelmt_t)); elmt->blah = i; DLIST_INS_HEAD(ctx, headlist, elmt); break; case ACTION_INSTAIL: elmt = malloc(sizeof (myelmt_t)); elmt->blah = i; DLIST_INS_TAIL(ctx, headlist, elmt); break; case ACTION_INSNEXT: printf("* insert after a random element.\n"); newelmt = malloc(sizeof (myelmt_t)); newelmt->blah = i; if (DLIST_IS_EMPTY(ctx, headlist)) { printf(" list is empty\n"); DLIST_INS_HEAD(ctx, headlist, newelmt); continue ; } r = rand_range(0, DLIST_COUNT(ctx, headlist)); for (j = 0, elmt = DLIST_HEAD(ctx, headlist) ; j < r; j++, elmt = DLIST_NEXT(headlist, elmt)) ; DLIST_INS_NEXT(ctx, headlist, elmt, newelmt); break; case ACTION_INSPREV: printf("* insert before a random element.\n"); newelmt = malloc(sizeof (myelmt_t)); newelmt->blah = i; if (DLIST_IS_EMPTY(ctx, headlist)) { printf(" list is empty\n"); DLIST_INS_HEAD(ctx, headlist, newelmt); continue ; } r = rand_range(0, DLIST_COUNT(ctx, headlist)); for (j = 0, elmt = DLIST_HEAD(ctx, headlist) ; j < r; j++, elmt = DLIST_NEXT(headlist, elmt)) ; DLIST_INS_PREV(ctx, headlist, elmt, newelmt); break; case ACTION_UNLINK1: case ACTION_UNLINK2: case ACTION_UNLINK3: case ACTION_UNLINK4: case ACTION_UNLINK5: printf("* unlink a random element.\n"); if (DLIST_IS_EMPTY(ctx, headlist)) { printf(" list is empty\n"); continue ; } r = rand_range(0, DLIST_COUNT(ctx, headlist)); for (j = 0, elmt = DLIST_HEAD(ctx, headlist) ; j < r; j++, elmt = DLIST_NEXT(headlist, elmt)) ; DLIST_UNLINK(ctx, headlist, elmt); free(elmt); break; case ACTION_SHOWLIST: printf("* show list content: (%i elements)\n", DLIST_COUNT(ctx, headlist)); if ( DLIST_IS_EMPTY(ctx, headlist) ) { printf(" list is empty\n"); } else { j = 0; DLIST_FOR_EACH(elmt, ctx, headlist) { printf(" elmt %i: val: %i\n", j, elmt->blah); j++; } } break; } }