// error event socket ( all client socket) // connecting socket (client side client) static void sock_buffer_error_event(bufferevent *bev, short what, void *arg) { coro_sock *sock = (coro_sock *)arg; coro_event ev; ev.sock = bufferevent_getfd(bev); ev.sock = sock->sock; if ( what & BEV_EVENT_ERROR ) { SET_ERROR(sock->status); ev.event = SOCK_ERROR_NOTIFY; } else if ( what & BEV_EVENT_EOF ) { ev.event = SOCK_EOF_NOTIFY; SET_EOF(sock->status); if ( evbuffer_get_length(bufferevent_get_input(sock->bev)) ) { SET_READ(sock->status); // printf("set read: %d\n", ev.sock); } } else { ; // pass } sock->ctx->curev.push(ev); coro_yield_uthread(__g_coroutine_ctx->io, 0); }
/* Called to extract data from the BIO. */ static int bio_bufferevent_read(BIO *b, char *out, int outlen) { int r = 0; struct evbuffer *input; BIO_clear_retry_flags(b); if (!out) return 0; if (!b->ptr) return -1; input = bufferevent_get_input(b->ptr); if (evbuffer_get_length(input) == 0) { /* If there's no data to read, say so. */ BIO_set_retry_read(b); return -1; } else { r = evbuffer_remove(input, out, outlen); } return r; }
static void http_request_done(struct evhttp_request *req, void *ctx) { HTTPReply *reply = static_cast<HTTPReply*>(ctx); if (req == nullptr) { /* If req is nullptr, it means an error occurred while connecting: the * error code will have been passed to http_error_cb. */ reply->status = 0; return; } reply->status = evhttp_request_get_response_code(req); struct evbuffer *buf = evhttp_request_get_input_buffer(req); if (buf) { size_t size = evbuffer_get_length(buf); const char *data = (const char*)evbuffer_pullup(buf, size); if (data) reply->body = std::string(data, size); evbuffer_drain(buf, size); } }
static void userInput2Buff(struct evhttp_request *req, void *args) { UserInput *ui = (UserInput *)args; struct event_base *base = ui->base; char *buff = ui->buff; struct evbuffer *body = evhttp_request_get_input_buffer(req); size_t len = evbuffer_get_length(body); unsigned char *requestLine; struct evbuffer *buf = evbuffer_new(); switch(req->type) { case EVHTTP_REQ_POST: requestLine = evbuffer_pullup(body, -1); requestLine[len] = '\0'; memcpy(buff, requestLine, len); evhttp_send_reply(req, HTTP_OK, "OK", buf); break; default: evhttp_send_error(req, HTTP_BADREQUEST, "Available POST only"); break; } evbuffer_free(buf); event_base_loopbreak(base); }
static void conn_readcb(struct bufferevent *bev, void *arg) { struct conninfo *info = arg; struct evbuffer *inbuf = bufferevent_get_input(bev); unsigned char *data; unsigned char code; /* socks4 and socks4a both have an 8 byte response */ if (evbuffer_get_length(inbuf) < 8) { log_debug("conn: waiting for full socks response"); return; } data = evbuffer_pullup(inbuf, 8); code = data[1]; evbuffer_drain(inbuf, 8); if (code != 0x5a) { finish_connection(info, 0, socks4_error_to_string(code)); } else { finish_connection(info, 1, NULL); } }
static void _evhtp_connection_writecb(evbev_t * bev, void * arg) { evhtp_connection_t * c = reinterpret_cast<evhtp_connection_t*>(arg); if (c->request == NULL) { return; } if (c->request->finished == 0 || evbuffer_get_length(bufferevent_get_output(bev))) { return; } if (c->request->keepalive) { delete(c->request); c->request = NULL; c->parser->init(htp_type_request); c->parser->set_userdata(c); } else { delete c; return ; } return; }
//******************************************************************************** // Event handler when there is data to be read // General message format: // command:payload$ // New group: // -command = new // -payload = <empty> // Store group info: // -command = new // -payload = <groupdata> // Restore group info: // -command = restore // -payload = <empty> // Remove group: // -command = remove // -payload = <empty> //******************************************************************************** static void read_cb(struct bufferevent *bev, void *ctx) { // Get input buffer struct evbuffer *input = bufferevent_get_input(bev); ev_uint32_t record_len = evbuffer_get_length(input); // Setup buffer to get data char* record = (char*) malloc(record_len); if (record == NULL) return; // Obtain data evbuffer_remove(input, record, record_len); // Store in structure //printf("Received: %s.\n", record); if(strncmp(record, "new", strlen("new")) == 0) { // First remove previous one, if there was one; then create a new one if(removeGroupSession()) { printf("Removed old session\n"); } printf("Starting new session\n"); newGroupSession(); printStaticPointer(); } else if(strncmp(record, "store", strlen("store")) == 0) { // Check start data marker char* start = strchr(record, ':') + 1; char* endMarker = strrchr(record, '$'); int msgLength = endMarker - start + 1; // Include marker in saved data // Turn into string char* dataToStore = (char*) malloc(msgLength + 1); // +1 for null terminator memset(dataToStore, 0, msgLength + 1); memcpy(dataToStore, start, msgLength); // Store data in RVM printf("Received: %s \n", dataToStore); if(!updateGroupSession(dataToStore, strlen(dataToStore)+1)) printf("Couldn't update group session as there was no session loaded\n"); else printf("Stored: %s \n", g_groupState); free(dataToStore); } else if(strncmp(record, "restore", strlen("restore")) == 0) { // Restore command received; send information back printf("Restore\n"); struct evbuffer *output = bufferevent_get_output(bev); if(g_groupState != NULL) { // Send msg printf("Sending %s.\n", g_groupState); evbuffer_add(output, g_groupState, strlen(g_groupState)+1); } else { evbuffer_add(output, "groupNotFound$", strlen("groupNotFound$")+1); printf("Couldn't restore group session as there was no session loaded\n"); } } else if(strncmp(record, "remove", strlen("new")) == 0) { printf("Removing session\n"); if(!removeGroupSession()) printf("Couldn't remove group session as there was no session loaded\n"); printStaticPointer(); } else { printf("Invalid command received\n"); } }
static void add_response (struct evhttp_request * req, struct tr_rpc_server * server, struct evbuffer * out, struct evbuffer * content) { const char * key = "Accept-Encoding"; const char * encoding = evhttp_find_header (req->input_headers, key); const int do_compress = encoding && strstr (encoding, "gzip"); if (!do_compress) { evbuffer_add_buffer (out, content); } else { int state; struct evbuffer_iovec iovec[1]; void * content_ptr = evbuffer_pullup (content, -1); const size_t content_len = evbuffer_get_length (content); if (!server->isStreamInitialized) { int compressionLevel; server->isStreamInitialized = true; server->stream.zalloc = (alloc_func) Z_NULL; server->stream.zfree = (free_func) Z_NULL; server->stream.opaque = (voidpf) Z_NULL; /* zlib's manual says: "Add 16 to windowBits to write a simple gzip header * and trailer around the compressed data instead of a zlib wrapper." */ #ifdef TR_LIGHTWEIGHT compressionLevel = Z_DEFAULT_COMPRESSION; #else compressionLevel = Z_BEST_COMPRESSION; #endif deflateInit2 (&server->stream, compressionLevel, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY); } server->stream.next_in = content_ptr; server->stream.avail_in = content_len; /* allocate space for the raw data and call deflate () just once -- * we won't use the deflated data if it's longer than the raw data, * so it's okay to let deflate () run out of output buffer space */ evbuffer_reserve_space (out, content_len, iovec, 1); server->stream.next_out = iovec[0].iov_base; server->stream.avail_out = iovec[0].iov_len; state = deflate (&server->stream, Z_FINISH); if (state == Z_STREAM_END) { iovec[0].iov_len -= server->stream.avail_out; #if 0 fprintf (stderr, "compressed response is %.2f of original (raw==%zu bytes; compressed==%zu)\n", (double)evbuffer_get_length (out)/content_len, content_len, evbuffer_get_length (out)); #endif evhttp_add_header (req->output_headers, "Content-Encoding", "gzip"); } else { memcpy (iovec[0].iov_base, content_ptr, content_len); iovec[0].iov_len = content_len; } evbuffer_commit_space (out, iovec, 1); deflateReset (&server->stream); } }
// Grab these bytes, and close the connection. // Even if we don't need to read any bytes, // we have to have this so that libevent thinks we have // a read event, so that it can timeout TCP connects // (as a read timeout) void read_cb(struct bufferevent *bev, void *arg) { struct evbuffer *in = bufferevent_get_input(bev); struct state *st = arg; size_t len = evbuffer_get_length(in); struct in_addr addr; addr.s_addr = st->src_ip; log_debug("forge-socket", "read_cb for %s", inet_ntoa(addr)); if (len > MAX_BANNER_LEN) { len = MAX_BANNER_LEN; } if (len > 0) { // Grab the banner unsigned int i; unsigned char *buf = malloc(len+1); st->state = RECEIVED; if (!buf) { log_fatal("forge-socket", "cannot alloc %d byte buf", len+1); return; } evbuffer_remove(in, buf, len); printf("%s ", inet_ntoa(addr)); if (st->conf->format == FORMAT_ASCII) { // Ascii buf[len] = '\0'; printf("%s\n", buf); } else if (st->conf->format == FORMAT_HEX) { // Hex output for (i=0; i<len; i++) { printf("%02x", buf[i]); } printf("\n"); } else if (st->conf->format == FORMAT_BASE64) { // Base64 int i=0; char out[4] = {0,0,0,0}; while (i < len) { uint32_t value = 0; value += (i < len) ? buf[i++] << 16 : 0; value += (i < len) ? buf[i++] << 8 : 0; value += (i < len) ? buf[i++] : 0; out[0] = BASE64_ALPHABET[(value >> 18) & 0x3F]; out[1] = BASE64_ALPHABET[(value >> 12) & 0x3F]; out[2] = BASE64_ALPHABET[(value >> 6) & 0x3F]; out[3] = BASE64_ALPHABET[(value ) & 0x3F]; if (i < len) { printf("%c%c%c%c", out[0], out[1], out[2], out[3]); } } if (len > 0) { switch (len % 3) { case 1: out[2] = '='; case 2: out[3] = '='; default: break; } printf("%c%c%c%c\n", out[0], out[1], out[2], out[3]); } }
static void bufferevent_readcb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); struct evbuffer *input; int res = 0; short what = BEV_EVENT_READING; ev_ssize_t howmuch = -1, readmax=-1; bufferevent_incref_and_lock_(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_READ, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } input = bufev->input; /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - evbuffer_get_length(input); /* we somehow lowered the watermark, stop reading */ if (howmuch <= 0) { bufferevent_wm_suspend_read(bufev); goto done; } } readmax = bufferevent_get_read_max_(bufev_p); if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" * uglifies this code. XXXX */ howmuch = readmax; if (bufev_p->read_suspended) goto done; evbuffer_unfreeze(input, 0); res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ evbuffer_freeze(input, 0); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; /* error case */ what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; bufferevent_decrement_read_buckets_(bufev_p, res); /* Invoke the user callback - must always be called last */ if (evbuffer_get_length(input) >= bufev->wm_read.low) bufferevent_run_readcb_(bufev); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); bufferevent_run_eventcb_(bufev, what); done: bufferevent_decref_and_unlock_(bufev); }
void _ws_read_websocket(ws_t ws, struct evbuffer *in) { assert(ws); assert(ws->bev); assert(in); LIBWS_LOG(LIBWS_DEBUG2, "Read websocket data"); while (evbuffer_get_length(in)) { // First read the websocket header. if (!ws->has_header) { size_t header_len; ev_ssize_t bytes_read; char header_buf[WS_HDR_MAX_SIZE]; ws_parse_state_t state; LIBWS_LOG(LIBWS_DEBUG2, "Read websocket header"); bytes_read = evbuffer_copyout(in, (void *)header_buf, sizeof(header_buf)); LIBWS_LOG(LIBWS_DEBUG2, "Copied %d header bytes", bytes_read); state = ws_unpack_header(&ws->header, &header_len, (unsigned char *)header_buf, bytes_read); assert(state != WS_PARSE_STATE_USER_ABORT); // Look for protocol violations in the header. if (state != WS_PARSE_STATE_NEED_MORE && _ws_validate_header(ws)) { state = WS_PARSE_STATE_ERROR; } switch (state) { case WS_PARSE_STATE_SUCCESS: { ws_header_t *h = &ws->header; ws->has_header = 1; LIBWS_LOG(LIBWS_DEBUG2, "Got header (%lu bytes):\n" "fin = %d, rsv = {%d,%d,%d}, mask_bit = %d, opcode = 0x%x (%s), " "mask = %x, len = %d", header_len, h->fin, h->rsv1, h->rsv2, h->rsv3, h->mask_bit, h->opcode, ws_opcode_str(h->opcode), h->mask, (int)h->payload_len); if (evbuffer_drain(in, header_len)) { // TODO: Error! close LIBWS_LOG(LIBWS_ERR, "Failed to drain header buffer"); } break; } case WS_PARSE_STATE_NEED_MORE: LIBWS_LOG(LIBWS_DEBUG2, " Need more header data"); return; case WS_PARSE_STATE_ERROR: LIBWS_LOG(LIBWS_ERR, "Error protocol violation in header"); ws_close_with_status(ws, WS_CLOSE_STATUS_PROTOCOL_ERR_1002); return; case WS_PARSE_STATE_USER_ABORT: // TODO: What to do here? LIBWS_LOG(LIBWS_ERR, "User abort"); break; } _ws_handle_frame_begin(ws); } if (ws->has_header) { // We're in a frame. size_t recv_len = evbuffer_get_length(in); size_t remaining = (size_t)(ws->header.payload_len - ws->recv_frame_len); LIBWS_LOG(LIBWS_DEBUG2, "In frame (remaining %u bytes of %u payload)", remaining, ws->header.payload_len); if (recv_len > remaining) { LIBWS_LOG(LIBWS_DEBUG2, "Received %u of %u remaining bytes", recv_len, remaining); recv_len = remaining; } if (remaining == 0) { _ws_handle_frame_end(ws); } else { int bytes_read; char *buf = (char *)_ws_malloc(recv_len); // TODO: Maybe we should only do evbuffer_pullup here instead // and pass that pointer on instead. bytes_read = evbuffer_remove(in, buf, recv_len); ws->recv_frame_len += bytes_read; if (bytes_read != recv_len) { LIBWS_LOG(LIBWS_ERR, "Wanted to read %u but only got %d", recv_len, bytes_read); } LIBWS_LOG(LIBWS_DEBUG2, "read: %d (%llu of %llu bytes)", bytes_read, ws->recv_frame_len, ws->header.payload_len); if (ws->header.mask_bit) { ws_unmask_payload(ws->header.mask, buf, bytes_read); } // Validate UTF8 text. Control frames are handled seperately. if (!ws->msg_isbinary && !WS_OPCODE_IS_CONTROL(ws->header.opcode)) { LIBWS_LOG(LIBWS_DEBUG2, "About to validate UTF8, state = %d" " len = %d", ws->utf8_state, bytes_read); ws_utf8_validate(&ws->utf8_state, buf, bytes_read); // Either the UTF8 is invalid, or a codepoint is not // complete in the finish frame. if ((ws->utf8_state == WS_UTF8_REJECT) || ((ws->utf8_state != WS_UTF8_ACCEPT) && (ws->header.fin))) { LIBWS_LOG(LIBWS_ERR, "Invalid UTF8!"); ws_close_with_status(ws, WS_CLOSE_STATUS_INCONSISTENT_DATA_1007); } LIBWS_LOG(LIBWS_DEBUG2, "Validated UTF8, state = %d", ws->utf8_state); } if (_ws_handle_frame_data(ws, buf, bytes_read)) { // TODO: Raise protocol error via error cb. // TODO: Close connection. LIBWS_LOG(LIBWS_ERR, "Failed to handle frame data"); } else { // TODO: This is not hit in some cases. LIBWS_LOG(LIBWS_DEBUG2, "recv_frame_len = %llu, payload_len = %llu", ws->recv_frame_len, ws->header.payload_len); // The entire frame has been received. if (ws->recv_frame_len == ws->header.payload_len) { _ws_handle_frame_end(ws); } } _ws_free(buf); } } } LIBWS_LOG(LIBWS_DEBUG, " %lu bytes left after websocket read", evbuffer_get_length(in)); }
static void bufferevent_writecb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); int res = 0; short what = BEV_EVENT_WRITING; int connected = 0; ev_ssize_t atmost = -1; _bufferevent_incref_and_lock(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } //正在连接服务器... if (bufev_p->connecting) { int c = evutil_socket_finished_connecting(fd); /* we need to fake the error if the connection was refused * immediately - usually connection to localhost on BSD */ if (bufev_p->connection_refused) { //在bufferevent_socket_connect中被设置 bufev_p->connection_refused = 0; c = -1; } if (c == 0) //正在连接,继续监听可写。 goto done; bufev_p->connecting = 0; if (c < 0) { //连接发生错误 event_del(&bufev->ev_write); event_del(&bufev->ev_read); _bufferevent_run_eventcb(bufev, BEV_EVENT_ERROR); goto done; } else { //连接成功 connected = 1; #ifdef WIN32 if (BEV_IS_ASYNC(bufev)) { event_del(&bufev->ev_write); bufferevent_async_set_connected(bufev); _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); goto done; } #endif //连接成功,调用用户错误处理函数。比较奇怪。 _bufferevent_run_eventcb(bufev, BEV_EVENT_CONNECTED); if (!(bufev->enabled & EV_WRITE) || bufev_p->write_suspended) { event_del(&bufev->ev_write); goto done; } } } atmost = _bufferevent_get_write_max(bufev_p); //写被挂起 if (bufev_p->write_suspended) goto done; //存在可写数据 if (evbuffer_get_length(bufev->output)) { evbuffer_unfreeze(bufev->output, 1); //将缓冲区数据写入socket。 res = evbuffer_write_atmost(bufev->output, fd, atmost); evbuffer_freeze(bufev->output, 1); if (res == -1) { //写发生错误 int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) //socket缓冲区满,一次未写完,继续监听可写事件,等待下次写入。 goto reschedule; what |= BEV_EVENT_ERROR; //写发生异常错误 } else if (res == 0) { /* eof case XXXX Actually, a 0 on write doesn't indicate an EOF. An ECONNRESET might be more typical. */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; _bufferevent_decrement_write_buckets(bufev_p, res); } //缓冲区数据已写完,删除写事件。 if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } /* 低于写低水位,调用用户回调。 */ if ((res || !connected) && evbuffer_get_length(bufev->output) <= bufev->wm_write.low) { _bufferevent_run_writecb(bufev); } goto done; reschedule: if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } goto done; error: bufferevent_disable(bufev, EV_WRITE); _bufferevent_run_eventcb(bufev, what); done: _bufferevent_decref_and_unlock(bufev); }
/** * @brief get_request_cb The callback function of get a image request. * * @param req The request with a list of params and the md5 of image. * @param arg It is not useful. */ void get_request_cb(evhtp_request_t *req, void *arg) { char *md5 = NULL, *fmt = NULL, *type = NULL; zimg_req_t *zimg_req = NULL; char *buff = NULL; size_t len; evhtp_connection_t *ev_conn = evhtp_request_get_connection(req); struct sockaddr *saddr = ev_conn->saddr; struct sockaddr_in *ss = (struct sockaddr_in *)saddr; char address[16]; const char *xff_address = evhtp_header_find(req->headers_in, "X-Forwarded-For"); if(xff_address) { inet_aton(xff_address, &ss->sin_addr); } strncpy(address, inet_ntoa(ss->sin_addr), 16); int req_method = evhtp_request_get_method(req); if(req_method >= 16) req_method = 16; LOG_PRINT(LOG_DEBUG, "Method: %d", req_method); if(strcmp(method_strmap[req_method], "POST") == 0) { LOG_PRINT(LOG_DEBUG, "POST Request."); post_request_cb(req, NULL); return; } else if(strcmp(method_strmap[req_method], "GET") != 0) { LOG_PRINT(LOG_DEBUG, "Request Method Not Support."); LOG_PRINT(LOG_INFO, "%s refuse method", address); goto err; } if(settings.down_access != NULL) { int acs = zimg_access_inet(settings.down_access, ss->sin_addr.s_addr); LOG_PRINT(LOG_DEBUG, "access check: %d", acs); if(acs == ZIMG_FORBIDDEN) { LOG_PRINT(LOG_DEBUG, "check access: ip[%s] forbidden!", address); LOG_PRINT(LOG_INFO, "%s refuse get forbidden", address); goto forbidden; } else if(acs == ZIMG_ERROR) { LOG_PRINT(LOG_DEBUG, "check access: check ip[%s] failed!", address); LOG_PRINT(LOG_ERROR, "%s fail get access", address); goto err; } } const char *uri; uri = req->uri->path->full; if(strlen(uri) == 1 && uri[0] == '/') { LOG_PRINT(LOG_DEBUG, "Root Request."); int fd = -1; struct stat st; if((fd = open(settings.root_path, O_RDONLY)) == -1) { LOG_PRINT(LOG_DEBUG, "Root_page Open Failed. Return Default Page."); evbuffer_add_printf(req->buffer_out, "<html>\n<body>\n<h1>\nWelcome To zimg World!</h1>\n</body>\n</html>\n"); } else { if (fstat(fd, &st) < 0) { /* Make sure the length still matches, now that we * opened the file :/ */ LOG_PRINT(LOG_DEBUG, "Root_page Length fstat Failed. Return Default Page."); evbuffer_add_printf(req->buffer_out, "<html>\n<body>\n<h1>\nWelcome To zimg World!</h1>\n</body>\n</html>\n"); } else { evbuffer_add_file(req->buffer_out, fd, 0, st.st_size); } } //evbuffer_add_printf(req->buffer_out, "<html>\n </html>\n"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_OK); LOG_PRINT(LOG_DEBUG, "============get_request_cb() DONE!==============="); LOG_PRINT(LOG_INFO, "%s succ root page", address); goto done; } if(strstr(uri, "favicon.ico")) { LOG_PRINT(LOG_DEBUG, "favicon.ico Request, Denied."); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); zimg_headers_add(req, settings.headers); evhtp_send_reply(req, EVHTP_RES_OK); goto done; } LOG_PRINT(LOG_DEBUG, "Got a GET request for <%s>", uri); /* Don't allow any ".."s in the path, to avoid exposing stuff outside * of the docroot. This test is both overzealous and underzealous: * it forbids aceptable paths like "/this/one..here", but it doesn't * do anything to prevent symlink following." */ if (strstr(uri, "..")) { LOG_PRINT(LOG_DEBUG, "attempt to upper dir!"); LOG_PRINT(LOG_INFO, "%s refuse directory", address); goto forbidden; } size_t md5_len = strlen(uri) + 1; md5 = (char *)malloc(md5_len); if(md5 == NULL) { LOG_PRINT(LOG_DEBUG, "md5 malloc failed!"); LOG_PRINT(LOG_ERROR, "%s fail malloc", address); goto err; } if(uri[0] == '/') str_lcpy(md5, uri+1, md5_len); else str_lcpy(md5, uri, md5_len); LOG_PRINT(LOG_DEBUG, "md5 of request is <%s>", md5); if(is_md5(md5) == -1) { LOG_PRINT(LOG_DEBUG, "Url is Not a zimg Request."); LOG_PRINT(LOG_INFO, "%s refuse url illegal", address); goto err; } /* This holds the content we're sending. */ evthr_t *thread = get_request_thr(req); thr_arg_t *thr_arg = (thr_arg_t *)evthr_get_aux(thread); int width, height, proportion, gray, x, y, rotate, quality, sv; width = 0; height = 0; proportion = 1; gray = 0; x = -1; y = -1; rotate = 0; quality = 0; sv = 0; evhtp_kvs_t *params; params = req->uri->query; if(params != NULL) { if(settings.disable_args != 1) { const char *str_w = evhtp_kv_find(params, "w"); const char *str_h = evhtp_kv_find(params, "h"); width = (str_w) ? atoi(str_w) : 0; height = (str_h) ? atoi(str_h) : 0; const char *str_p = evhtp_kv_find(params, "p"); proportion = (str_p) ? atoi(str_p) : 1; const char *str_g = evhtp_kv_find(params, "g"); gray = (str_g) ? atoi(str_g) : 0; const char *str_x = evhtp_kv_find(params, "x"); const char *str_y = evhtp_kv_find(params, "y"); x = (str_x) ? atoi(str_x) : -1; y = (str_y) ? atoi(str_y) : -1; if(x != -1 || y != -1) { proportion = 1; } const char *str_r = evhtp_kv_find(params, "r"); rotate = (str_r) ? atoi(str_r) : 0; const char *str_q = evhtp_kv_find(params, "q"); quality = (str_q) ? atoi(str_q) : 0; const char *str_f = evhtp_kv_find(params, "f"); if(str_f) { size_t fmt_len = strlen(str_f) + 1; fmt = (char *)malloc(fmt_len); if(fmt != NULL) str_lcpy(fmt, str_f, fmt_len); LOG_PRINT(LOG_DEBUG, "fmt = %s", fmt); } } if(settings.disable_type != 1) { const char *str_t = evhtp_kv_find(params, "t"); if(str_t) { size_t type_len = strlen(str_t) + 1; type = (char *)malloc(type_len); if(type != NULL) str_lcpy(type, str_t, type_len); LOG_PRINT(LOG_DEBUG, "type = %s", type); } } } else { sv = 1; } quality = (quality != 0 ? quality : settings.quality); zimg_req = (zimg_req_t *)malloc(sizeof(zimg_req_t)); if(zimg_req == NULL) { LOG_PRINT(LOG_DEBUG, "zimg_req malloc failed!"); LOG_PRINT(LOG_ERROR, "%s fail malloc", address); goto err; } zimg_req -> md5 = md5; zimg_req -> type = type; zimg_req -> width = width; zimg_req -> height = height; zimg_req -> proportion = proportion; zimg_req -> gray = gray; zimg_req -> x = x; zimg_req -> y = y; zimg_req -> rotate = rotate; zimg_req -> quality = quality; zimg_req -> fmt = (fmt != NULL ? fmt : settings.format); zimg_req -> sv = sv; zimg_req -> thr_arg = thr_arg; int get_img_rst = -1; get_img_rst = settings.get_img(zimg_req, req); if(get_img_rst == -1) { LOG_PRINT(LOG_DEBUG, "zimg Requset Get Image[MD5: %s] Failed!", zimg_req->md5); if(type) LOG_PRINT(LOG_ERROR, "%s fail pic:%s t:%s", address, md5, type); else LOG_PRINT(LOG_ERROR, "%s fail pic:%s w:%d h:%d p:%d g:%d x:%d y:%d r:%d q:%d f:%s", address, md5, width, height, proportion, gray, x, y, rotate, quality, zimg_req->fmt); goto err; } if(get_img_rst == 2) { LOG_PRINT(LOG_DEBUG, "Etag Matched Return 304 EVHTP_RES_NOTMOD."); if(type) LOG_PRINT(LOG_INFO, "%s succ 304 pic:%s t:%s", address, md5, type); else LOG_PRINT(LOG_INFO, "%s succ 304 pic:%s w:%d h:%d p:%d g:%d x:%d y:%d r:%d q:%d f:%s", address, md5, width, height, proportion, gray, x, y, rotate, quality, zimg_req->fmt); evhtp_send_reply(req, EVHTP_RES_NOTMOD); goto done; } len = evbuffer_get_length(req->buffer_out); LOG_PRINT(LOG_DEBUG, "get buffer length: %d", len); LOG_PRINT(LOG_DEBUG, "Got the File!"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "image/jpeg", 0, 0)); zimg_headers_add(req, settings.headers); evhtp_send_reply(req, EVHTP_RES_OK); if(type) LOG_PRINT(LOG_INFO, "%s succ pic:%s t:%s size:%d", address, md5, type, len); else LOG_PRINT(LOG_INFO, "%s succ pic:%s w:%d h:%d p:%d g:%d x:%d y:%d r:%d q:%d f:%s size:%d", address, md5, width, height, proportion, gray, x, y, rotate, quality, zimg_req->fmt, len); LOG_PRINT(LOG_DEBUG, "============get_request_cb() DONE!==============="); goto done; forbidden: evbuffer_add_printf(req->buffer_out, "<html><body><h1>403 Forbidden!</h1></body></html>"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_FORBIDDEN); LOG_PRINT(LOG_DEBUG, "============get_request_cb() FORBIDDEN!==============="); goto done; err: evbuffer_add_printf(req->buffer_out, "<html><body><h1>404 Not Found!</h1></body></html>"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); evhtp_send_reply(req, EVHTP_RES_NOTFOUND); LOG_PRINT(LOG_DEBUG, "============get_request_cb() ERROR!==============="); done: free(fmt); free(md5); free(type); free(zimg_req); free(buff); }
/** * @brief post_request_cb The callback function of a POST request to upload a image. * * @param req The request with image buffer. * @param arg It is not useful. */ void post_request_cb(evhtp_request_t *req, void *arg) { int post_size = 0; char *buff = NULL; int err_no = 0; int ret_json = 1; evhtp_connection_t *ev_conn = evhtp_request_get_connection(req); struct sockaddr *saddr = ev_conn->saddr; struct sockaddr_in *ss = (struct sockaddr_in *)saddr; char address[16]; const char *xff_address = evhtp_header_find(req->headers_in, "X-Forwarded-For"); if(xff_address) { inet_aton(xff_address, &ss->sin_addr); } strncpy(address, inet_ntoa(ss->sin_addr), 16); int req_method = evhtp_request_get_method(req); if(req_method >= 16) req_method = 16; LOG_PRINT(LOG_DEBUG, "Method: %d", req_method); if(strcmp(method_strmap[req_method], "POST") != 0) { LOG_PRINT(LOG_DEBUG, "Request Method Not Support."); LOG_PRINT(LOG_INFO, "%s refuse post method", address); err_no = 2; goto err; } if(settings.up_access != NULL) { int acs = zimg_access_inet(settings.up_access, ss->sin_addr.s_addr); LOG_PRINT(LOG_DEBUG, "access check: %d", acs); if(acs == ZIMG_FORBIDDEN) { LOG_PRINT(LOG_DEBUG, "check access: ip[%s] forbidden!", address); LOG_PRINT(LOG_INFO, "%s refuse post forbidden", address); err_no = 3; goto forbidden; } else if(acs == ZIMG_ERROR) { LOG_PRINT(LOG_DEBUG, "check access: check ip[%s] failed!", address); LOG_PRINT(LOG_ERROR, "%s fail post access %s", address); err_no = 0; goto err; } } const char *content_len = evhtp_header_find(req->headers_in, "Content-Length"); if(!content_len) { LOG_PRINT(LOG_DEBUG, "Get Content-Length error!"); LOG_PRINT(LOG_ERROR, "%s fail post content-length", address); err_no = 5; goto err; } post_size = atoi(content_len); if(post_size <= 0) { LOG_PRINT(LOG_DEBUG, "Image Size is Zero!"); LOG_PRINT(LOG_ERROR, "%s fail post empty", address); err_no = 5; goto err; } if(post_size > settings.max_size) { LOG_PRINT(LOG_DEBUG, "Image Size Too Large!"); LOG_PRINT(LOG_ERROR, "%s fail post large", address); err_no = 7; goto err; } const char *content_type = evhtp_header_find(req->headers_in, "Content-Type"); if(!content_type) { LOG_PRINT(LOG_DEBUG, "Get Content-Type error!"); LOG_PRINT(LOG_ERROR, "%s fail post content-type", address); err_no = 6; goto err; } evbuf_t *buf; buf = req->buffer_in; buff = (char *)malloc(post_size); if(buff == NULL) { LOG_PRINT(LOG_DEBUG, "buff malloc failed!"); LOG_PRINT(LOG_ERROR, "%s fail malloc buff", address); err_no = 0; goto err; } int rmblen, evblen; if(evbuffer_get_length(buf) <= 0) { LOG_PRINT(LOG_DEBUG, "Empty Request!"); LOG_PRINT(LOG_ERROR, "%s fail post empty", address); err_no = 4; goto err; } while((evblen = evbuffer_get_length(buf)) > 0) { LOG_PRINT(LOG_DEBUG, "evblen = %d", evblen); rmblen = evbuffer_remove(buf, buff, evblen); LOG_PRINT(LOG_DEBUG, "rmblen = %d", rmblen); if(rmblen < 0) { LOG_PRINT(LOG_DEBUG, "evbuffer_remove failed!"); LOG_PRINT(LOG_ERROR, "%s fail post parse", address); err_no = 4; goto err; } } if(strstr(content_type, "multipart/form-data") == NULL) { err_no = binary_parse(req, content_type, address, buff, post_size); } else { ret_json = 0; err_no = multipart_parse(req, content_type, address, buff, post_size); } if(err_no != -1) { goto err; } evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_send_reply(req, EVHTP_RES_OK); LOG_PRINT(LOG_DEBUG, "============post_request_cb() DONE!==============="); goto done; forbidden: json_return(req, err_no, NULL, 0); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_send_reply(req, EVHTP_RES_OK); LOG_PRINT(LOG_DEBUG, "============post_request_cb() FORBIDDEN!==============="); goto done; err: if(ret_json == 0) { evbuffer_add_printf(req->buffer_out, "<h1>Upload Failed!</h1></body></html>"); evhtp_headers_add_header(req->headers_out, evhtp_header_new("Content-Type", "text/html", 0, 0)); } else { json_return(req, err_no, NULL, 0); } evhtp_headers_add_header(req->headers_out, evhtp_header_new("Server", settings.server_name, 0, 1)); evhtp_send_reply(req, EVHTP_RES_OK); LOG_PRINT(LOG_DEBUG, "============post_request_cb() ERROR!==============="); done: free(buff); }
//void drive_machine(conn* c){ //改成bufferevent之后event_handler和drive_machine都不能幸免需要改参数 void drive_machine(conn* c, struct bufferevent * incoming){ assert(c != NULL); // 真正的处理函数,根据不同的conn的状态来进行不同的处理。 // 虽然我做这个demo只是把消息回显而已,但貌似这么多种状态还是得处理。 bool stop = false; int sfd; socklen_t addrlen; struct sockaddr_storage addr; struct evbuffer *evreturn; char *req; while(!stop){ switch(c->state){ case conn_listening: //如果是listenting状态,则需要把连接accept addrlen = sizeof(addr); sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen); if (sfd == -1) { // accept错误 perror("sfd accept failed"); accept_new_conns(false); //用来决定主线程是否还需要accept连接,如果已经接近饱和了,就停住,等一个时间间隔再来试。 stop = true; } //分派conn任务 dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST, DATA_BUFFER_SIZE, tcp_transport); stop = true; break; case conn_new_cmd: /* fall through */ case conn_read: /* now try reading from the socket */ req = evbuffer_readline(incoming->input); if (req == NULL){ //conn_set_state(c, conn_closing); //goto set_conn_closing; conn_set_state(c, conn_waiting); break; } if(c->req != NULL){ free(c->req); c->req = NULL; } c->req = req; conn_set_state(c, conn_mwrite); //if (!update_event(c, EV_WRITE | EV_PERSIST)){ // printf("conn_read update event failed"); // goto set_conn_closing; //} //stop = true; //stop = true; break; //evreturn = evbuffer_new(); //evbuffer_add_printf(evreturn, "You said %s\n", req); // bufferevent_write_buffer(incoming, evreturn); //evbuffer_free(evreturn); //free(req); set_conn_closing: conn_set_state(c, conn_closing); break; case conn_mwrite: //所有的回复到在这个函数进行输出 req = c->req; evreturn = evbuffer_new(); // bufferevent_setwatermark(incoming, EV_WRITE, 0, 0); int res1 = evbuffer_add_printf(evreturn, "You said %s\n", req); int res2 = bufferevent_write_buffer(incoming, evreturn); // int res3 = bufferevent_flush(incoming, EV_WRITE, BEV_FLUSH); int res4 = evbuffer_get_length(incoming->output); evbuffer_free(evreturn); free(req); evreturn = NULL; //int fd = (int)bufferevent_getfd(incoming); //char buf[20]; // //sprintf(buf, "You said %s\n", req); //write(fd, buf, 11); c->req = NULL; conn_set_state(c,conn_waiting); stop = true; break; case conn_waiting: if (!update_event(c, EV_READ | EV_PERSIST)) { fprintf(stderr, "Couldn't update event\n"); conn_set_state(c, conn_closing); break; } conn_set_state(c, conn_read); stop = true; break; case conn_closing: conn_close(c); stop = true; break; } /* otherwise we have a real error, on which we close the connection */ } }
size_t CD_BufferLength (CDBuffer* self) { return evbuffer_get_length(self->raw); }
static void bufferevent_readcb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); struct evbuffer *input; int res = 0; short what = BEV_EVENT_READING; ev_ssize_t howmuch = -1, readmax=-1; _bufferevent_incref_and_lock(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_READ, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } input = bufev->input; /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. */ if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - evbuffer_get_length(input); /* 缓冲区超过高水位,挂起读。 */ if (howmuch <= 0) { bufferevent_wm_suspend_read(bufev); goto done; } } //因为用户可以限速,所以这么要检测最大的可读大小。 //如果没有限速的话,那么将返回16384字节,即16K //默认情况下是没有限速的。 readmax = _bufferevent_get_read_max(bufev_p); if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" * uglifies this code. XXXX */ howmuch = readmax; if (bufev_p->read_suspended) goto done; evbuffer_unfreeze(input, 0); res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ evbuffer_freeze(input, 0); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) //EINTER or EAGAIN goto reschedule; /* error case */ what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; _bufferevent_decrement_read_buckets(bufev_p, res); /* 数据大于低水平,调用用户设置的回调。 */ if (evbuffer_get_length(input) >= bufev->wm_read.low) _bufferevent_run_readcb(bufev); goto done; reschedule: goto done; error: bufferevent_disable(bufev, EV_READ); _bufferevent_run_eventcb(bufev, what); done: _bufferevent_decref_and_unlock(bufev); }
static void doScrape (const tr_info * inf) { unsigned int i; for (i=0; i<inf->trackerCount; ++i) { CURL * curl; CURLcode res; struct evbuffer * buf; const char * scrape = inf->trackers[i].scrape; char * url; char escaped[SHA_DIGEST_LENGTH*3 + 1]; if (scrape == NULL) continue; tr_http_escape_sha1 (escaped, inf->hash); url = tr_strdup_printf ("%s%cinfo_hash=%s", scrape, strchr (scrape, '?') ? '&' : '?', escaped); printf ("%s ... ", url); fflush (stdout); buf = evbuffer_new (); curl = tr_curl_easy_init (buf); curl_easy_setopt (curl, CURLOPT_URL, url); curl_easy_setopt (curl, CURLOPT_TIMEOUT, TIMEOUT_SECS); if ((res = curl_easy_perform (curl))) { printf ("error: %s\n", curl_easy_strerror (res)); } else { long response; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response); if (response != 200) { printf ("error: unexpected response %ld \"%s\"\n", response, tr_webGetResponseStr (response)); } else /* HTTP OK */ { tr_variant top; tr_variant * files; bool matched = false; const char * begin = (const char*) evbuffer_pullup (buf, -1); if (!tr_variantFromBenc (&top, begin, evbuffer_get_length(buf))) { if (tr_variantDictFindDict (&top, TR_KEY_files, &files)) { int i = 0; tr_quark key; tr_variant * val; while (tr_variantDictChild (files, i++, &key, &val)) { if (memcmp (inf->hash, tr_quark_get_string (key, NULL), SHA_DIGEST_LENGTH) == 0) { int64_t seeders = -1; int64_t leechers = -1; tr_variantDictFindInt (val, TR_KEY_complete, &seeders); tr_variantDictFindInt (val, TR_KEY_incomplete, &leechers); printf ("%d seeders, %d leechers\n", (int)seeders, (int)leechers); matched = true; } } } tr_variantFree (&top); } if (!matched) printf ("no match\n"); } } curl_easy_cleanup (curl); evbuffer_free (buf); tr_free (url); } }
static void test_evbuffer(void *ptr) { static char buffer[512], *tmp; struct evbuffer *evb = evbuffer_new(); struct evbuffer *evb_two = evbuffer_new(); size_t sz_tmp; int i; evbuffer_validate(evb); evbuffer_add_printf(evb, "%s/%d", "hello", 1); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 7); tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "hello/1", 1)); evbuffer_add_buffer(evb, evb_two); evbuffer_validate(evb); evbuffer_drain(evb, strlen("hello/")); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 1); tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1", 1)); evbuffer_add_printf(evb_two, "%s", "/hello"); evbuffer_validate(evb); evbuffer_add_buffer(evb, evb_two); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb_two) == 0); tt_assert(evbuffer_get_length(evb) == 7); tt_assert(!memcmp((char*)EVBUFFER_DATA(evb), "1/hello", 7) != 0); memset(buffer, 0, sizeof(buffer)); evbuffer_add(evb, buffer, sizeof(buffer)); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) == 7 + 512); tmp = (char *)evbuffer_pullup(evb, 7 + 512); tt_assert(tmp); tt_assert(!strncmp(tmp, "1/hello", 7)); tt_assert(!memcmp(tmp + 7, buffer, sizeof(buffer))); evbuffer_validate(evb); evbuffer_prepend(evb, "something", 9); evbuffer_validate(evb); evbuffer_prepend(evb, "else", 4); evbuffer_validate(evb); tmp = (char *)evbuffer_pullup(evb, 4 + 9 + 7); tt_assert(!strncmp(tmp, "elsesomething1/hello", 4 + 9 + 7)); evbuffer_validate(evb); evbuffer_drain(evb, -1); evbuffer_validate(evb); evbuffer_drain(evb_two, -1); evbuffer_validate(evb); for (i = 0; i < 3; ++i) { evbuffer_add(evb_two, buffer, sizeof(buffer)); evbuffer_validate(evb_two); evbuffer_add_buffer(evb, evb_two); evbuffer_validate(evb); evbuffer_validate(evb_two); } tt_assert(evbuffer_get_length(evb_two) == 0); tt_assert(evbuffer_get_length(evb) == i * sizeof(buffer)); /* test remove buffer */ sz_tmp = (size_t)(sizeof(buffer)*2.5); evbuffer_remove_buffer(evb, evb_two, sz_tmp); tt_assert(evbuffer_get_length(evb_two) == sz_tmp); tt_assert(evbuffer_get_length(evb) == sizeof(buffer) / 2); evbuffer_validate(evb); if (memcmp(evbuffer_pullup( evb, -1), buffer, sizeof(buffer) / 2) != 0 || memcmp(evbuffer_pullup( evb_two, -1), buffer, sizeof(buffer) != 0)) tt_abort_msg("Pullup did not preserve content"); evbuffer_validate(evb); /* testing one-vector reserve and commit */ { struct evbuffer_iovec v[1]; char *buf; int i, j, r; for (i = 0; i < 3; ++i) { r = evbuffer_reserve_space(evb, 10000, v, 1); tt_int_op(r, ==, 1); tt_assert(v[0].iov_len >= 10000); tt_assert(v[0].iov_base != NULL); evbuffer_validate(evb); buf = v[0].iov_base; for (j = 0; j < 10000; ++j) { buf[j] = j; } evbuffer_validate(evb); tt_int_op(evbuffer_commit_space(evb, v, 1), ==, 0); evbuffer_validate(evb); tt_assert(evbuffer_get_length(evb) >= 10000); evbuffer_drain(evb, j * 5000); evbuffer_validate(evb); } } end: evbuffer_free(evb); evbuffer_free(evb_two); }
static int chunk_stream_size(struct chunk_stream *cs) { return evbuffer_get_length(bufferevent_get_input(cs->bev)); }
static void on_read(struct bufferevent *bev, void *ctx) { struct evbuffer *input; int fd; size_t len; char *line; char *emsg; char **argv = malloc(sizeof(char *)); int argc = 0; char *arg_ptr, *save_ptr; /* * 1: Unknown command * 2: Too few arguments * 3: Internal error * 4: Missing command */ int status; int i; input = bufferevent_get_input(bev); fd = bufferevent_getfd(bev); len = evbuffer_get_length(input); line = malloc(len + 1); evbuffer_copyout(input, line, len); if (len == 0) { status = 4; goto END; } if (line[len - 1] == '\n') { line[len - 1] = 0; } else { line[len] = 0; } arg_ptr = strtok_r(line, " ", &save_ptr); while (arg_ptr != NULL) { len = strlen(arg_ptr) + 1; argv[argc] = malloc(len); strncpy(argv[argc], arg_ptr, len); argv = realloc(argv, argc + 1); arg_ptr = strtok_r(NULL, " ", &save_ptr); argc++; } printf("%s LookingGlass: Received command \"%s\" with %d arguments", date(), argv[0], argc - 1); for (i = 1; i < argc; i++) { printf(" %d:\"%s\"", i, argv[i]); } printf(".\n"); status = call_function(argv[0], fd, argc, argv); END: switch (status) { case 1: emsg = "Unknown command"; write(fd, emsg, strlen(emsg)); fprintf(stdout, "%s LookingGlass: Error: Disconnecting client. Reason: %s: %s.\n", date(), emsg, argv[0]); break; case 2: emsg = "Too few arguments"; write(fd, emsg, strlen(emsg)); fprintf(stdout, "%s LookingGlass: Disconnecting client. Error: %s.\n", date(), emsg); break; case 3: emsg = "Internal error"; write(fd, emsg, strlen(emsg)); fprintf(stdout, "%s LookingGlass: Disconnecting client. Error: %s.\n", date(), emsg); break; case 4: emsg = "Missing command"; write(fd, emsg, strlen(emsg)); fprintf(stdout, "%s LookingGlass: Disconnecting client. Error: %s.\n", date(), emsg); break; default: printf("%s LookingGlass: Disconnecting client.\n", date()); break; } bufferevent_free(bev); for (i = 0; i < argc; i++) { free(argv[i]); } free(argv); free(line); }
static void static_dump_request_cb(struct evhttp_request *req, void *arg) { const char *cmdtype; struct evkeyvalq *headers; struct evkeyval *header; struct evbuffer *buf; switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: cmdtype = "GET"; break; case EVHTTP_REQ_POST: cmdtype = "POST"; break; default: cmdtype = "unknown"; break; } printf("Received a %s request for %s\nHeaders:\n", cmdtype, evhttp_request_get_uri(req)); headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; header = header->next.tqe_next) { printf(" %s: %s\n", header->key, header->value); } buf = evhttp_request_get_input_buffer(req); puts("Input data: <<<"); printf("len:%d", evbuffer_get_length(buf)); /* while (evbuffer_get_length(buf)) { int n; char cbuf[128]; n = evbuffer_remove(buf, cbuf, sizeof(buf)-1); if (n > 0) (void) fwrite(cbuf, 1, n, stdout); } puts(">>>"); */ //get params struct evkeyvalq *query_params_ptr = calloc(sizeof(struct evkeyvalq), 1); getParams(req, query_params_ptr); char *test = NULL; test = getParam(query_params_ptr, "test"); if (test != NULL) { fprintf(stderr, "param test: %s", test); } evhttp_clear_headers(query_params_ptr); free(test); //post params struct evkeyvalq *post_params_ptr = calloc(sizeof(struct evkeyvalq), 1); postParams(req, post_params_ptr); char *name = NULL; name = postParam(post_params_ptr, "name"); if (name != NULL) { fprintf(stderr, "param name: %s", name); } evhttp_clear_headers(post_params_ptr); free(name); evhttp_send_reply(req, 200, "OK", NULL); //evhttp_request_free(req); }
static void bufferevent_writecb(evutil_socket_t fd, short event, void *arg) { struct bufferevent *bufev = arg; struct bufferevent_private *bufev_p = EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); int res = 0; short what = BEV_EVENT_WRITING; int connected = 0; ev_ssize_t atmost = -1; bufferevent_incref_and_lock_(bufev); if (event == EV_TIMEOUT) { /* Note that we only check for event==EV_TIMEOUT. If * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the * timeout, since a read has occurred */ what |= BEV_EVENT_TIMEOUT; goto error; } if (bufev_p->connecting) { int c = evutil_socket_finished_connecting_(fd); /* we need to fake the error if the connection was refused * immediately - usually connection to localhost on BSD */ if (bufev_p->connection_refused) { bufev_p->connection_refused = 0; c = -1; } if (c == 0) goto done; bufev_p->connecting = 0; if (c < 0) { event_del(&bufev->ev_write); event_del(&bufev->ev_read); bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR); goto done; } else { connected = 1; #ifdef _WIN32 if (BEV_IS_ASYNC(bufev)) { event_del(&bufev->ev_write); bufferevent_async_set_connected_(bufev); bufferevent_run_eventcb_(bufev, BEV_EVENT_CONNECTED); goto done; } #endif bufferevent_run_eventcb_(bufev, BEV_EVENT_CONNECTED); if (!(bufev->enabled & EV_WRITE) || bufev_p->write_suspended) { event_del(&bufev->ev_write); goto done; } } } atmost = bufferevent_get_write_max_(bufev_p); if (bufev_p->write_suspended) goto done; if (evbuffer_get_length(bufev->output)) { evbuffer_unfreeze(bufev->output, 1); res = evbuffer_write_atmost(bufev->output, fd, atmost); evbuffer_freeze(bufev->output, 1); if (res == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; what |= BEV_EVENT_ERROR; } else if (res == 0) { /* eof case XXXX Actually, a 0 on write doesn't indicate an EOF. An ECONNRESET might be more typical. */ what |= BEV_EVENT_EOF; } if (res <= 0) goto error; bufferevent_decrement_write_buckets_(bufev_p, res); } if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } /* * Invoke the user callback if our buffer is drained or below the * low watermark. */ if ((res || !connected) && evbuffer_get_length(bufev->output) <= bufev->wm_write.low) { bufferevent_run_writecb_(bufev); } goto done; reschedule: if (evbuffer_get_length(bufev->output) == 0) { event_del(&bufev->ev_write); } goto done; error: bufferevent_disable(bufev, EV_WRITE); bufferevent_run_eventcb_(bufev, what); done: bufferevent_decref_and_unlock_(bufev); }
int run_unmarshal(struct run *tmp, struct evbuffer *evbuf) { ev_uint32_t tag; while (evbuffer_get_length(evbuf) > 0) { if (evtag_peek(evbuf, &tag) == -1) return (-1); switch (tag) { case RUN_HOW: if (tmp->how_set) return (-1); if (evtag_unmarshal_string(evbuf, RUN_HOW, &tmp->how_data) == -1) { event_warnx("%s: failed to unmarshal how", __func__); return (-1); } tmp->how_set = 1; break; case RUN_SOME_BYTES: if (tmp->some_bytes_set) return (-1); if (evtag_payload_length(evbuf, &tmp->some_bytes_length) == -1) return (-1); if (tmp->some_bytes_length > evbuffer_get_length(evbuf)) return (-1); if ((tmp->some_bytes_data = malloc(tmp->some_bytes_length)) == NULL) return (-1); if (evtag_unmarshal_fixed(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length) == -1) { event_warnx("%s: failed to unmarshal some_bytes", __func__); return (-1); } tmp->some_bytes_set = 1; break; case RUN_FIXED_BYTES: if (tmp->fixed_bytes_set) return (-1); if (evtag_unmarshal_fixed(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, (24)) == -1) { event_warnx("%s: failed to unmarshal fixed_bytes", __func__); return (-1); } tmp->fixed_bytes_set = 1; break; case RUN_NOTES: if (tmp->notes_length >= tmp->notes_num_allocated && run_notes_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } if (evtag_unmarshal_string(evbuf, RUN_NOTES, &tmp->notes_data[tmp->notes_length]) == -1) { event_warnx("%s: failed to unmarshal notes", __func__); return (-1); } ++tmp->notes_length; tmp->notes_set = 1; break; case RUN_LARGE_NUMBER: if (tmp->large_number_set) return (-1); if (evtag_unmarshal_int64(evbuf, RUN_LARGE_NUMBER, &tmp->large_number_data) == -1) { event_warnx("%s: failed to unmarshal large_number", __func__); return (-1); } tmp->large_number_set = 1; break; case RUN_OTHER_NUMBERS: if (tmp->other_numbers_length >= tmp->other_numbers_num_allocated && run_other_numbers_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } if (evtag_unmarshal_int(evbuf, RUN_OTHER_NUMBERS, &tmp->other_numbers_data[tmp->other_numbers_length]) == -1) { event_warnx("%s: failed to unmarshal other_numbers", __func__); return (-1); } ++tmp->other_numbers_length; tmp->other_numbers_set = 1; break; default: return -1; } } if (run_complete(tmp) == -1) return (-1); return (0); }
static int bptree_message_incomplete(struct evbuffer *b) { // BTree messages also should contain a bpt_id int bsize = evbuffer_get_length(b); if (bsize < sizeof(uint16_t)) return 1; return 0; }
int msg_unmarshal(struct msg *tmp, struct evbuffer *evbuf) { ev_uint32_t tag; while (evbuffer_get_length(evbuf) > 0) { if (evtag_peek(evbuf, &tag) == -1) return (-1); switch (tag) { case MSG_FROM_NAME: if (tmp->from_name_set) return (-1); if (evtag_unmarshal_string(evbuf, MSG_FROM_NAME, &tmp->from_name_data) == -1) { event_warnx("%s: failed to unmarshal from_name", __func__); return (-1); } tmp->from_name_set = 1; break; case MSG_TO_NAME: if (tmp->to_name_set) return (-1); if (evtag_unmarshal_string(evbuf, MSG_TO_NAME, &tmp->to_name_data) == -1) { event_warnx("%s: failed to unmarshal to_name", __func__); return (-1); } tmp->to_name_set = 1; break; case MSG_ATTACK: if (tmp->attack_set) return (-1); tmp->attack_data = kill_new(); if (tmp->attack_data == NULL) return (-1); if (evtag_unmarshal_kill(evbuf, MSG_ATTACK, tmp->attack_data) == -1) { event_warnx("%s: failed to unmarshal attack", __func__); return (-1); } tmp->attack_set = 1; break; case MSG_RUN: if (tmp->run_length >= tmp->run_num_allocated && msg_run_expand_to_hold_more(tmp) < 0) { puts("HEY NOW"); return (-1); } tmp->run_data[tmp->run_length] = run_new(); if (tmp->run_data[tmp->run_length] == NULL) return (-1); if (evtag_unmarshal_run(evbuf, MSG_RUN, tmp->run_data[tmp->run_length]) == -1) { event_warnx("%s: failed to unmarshal run", __func__); return (-1); } ++tmp->run_length; tmp->run_set = 1; break; default: return -1; } } if (msg_complete(tmp) == -1) return (-1); return (0); }
/* Thread: httpd */ void httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *evbuf) { unsigned char outbuf[128 * 1024]; z_stream strm; struct evbuffer *gzbuf; struct evkeyvalq *headers; const char *param; int flush; int zret; int ret; if (!req) return; if (!evbuf || (evbuffer_get_length(evbuf) == 0)) { DPRINTF(E_DBG, L_HTTPD, "Not gzipping body-less reply\n"); goto no_gzip; } headers = evhttp_request_get_input_headers(req); param = evhttp_find_header(headers, "Accept-Encoding"); if (!param) { DPRINTF(E_DBG, L_HTTPD, "Not gzipping; no Accept-Encoding header\n"); goto no_gzip; } else if (!strstr(param, "gzip") && !strstr(param, "*")) { DPRINTF(E_DBG, L_HTTPD, "Not gzipping; gzip not in Accept-Encoding (%s)\n", param); goto no_gzip; } gzbuf = evbuffer_new(); if (!gzbuf) { DPRINTF(E_LOG, L_HTTPD, "Could not allocate evbuffer for gzipped reply\n"); goto no_gzip; } strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; /* Set up a gzip stream (the "+ 16" in 15 + 16), instead of a zlib stream (default) */ zret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); if (zret != Z_OK) { DPRINTF(E_DBG, L_HTTPD, "zlib setup failed: %s\n", zError(zret)); goto out_fail_init; } strm.next_in = evbuffer_pullup(evbuf, -1); strm.avail_in = evbuffer_get_length(evbuf); flush = Z_NO_FLUSH; /* 2 iterations: Z_NO_FLUSH until input is consumed, then Z_FINISH */ for (;;) { do { strm.next_out = outbuf; strm.avail_out = sizeof(outbuf); zret = deflate(&strm, flush); if (zret == Z_STREAM_ERROR) { DPRINTF(E_LOG, L_HTTPD, "Could not deflate data: %s\n", strm.msg); goto out_fail_gz; } ret = evbuffer_add(gzbuf, outbuf, sizeof(outbuf) - strm.avail_out); if (ret < 0) { DPRINTF(E_LOG, L_HTTPD, "Out of memory adding gzipped data to evbuffer\n"); goto out_fail_gz; } } while (strm.avail_out == 0); if (flush == Z_FINISH) break; flush = Z_FINISH; } if (zret != Z_STREAM_END) { DPRINTF(E_LOG, L_HTTPD, "Compressed data not finalized!\n"); goto out_fail_gz; } deflateEnd(&strm); headers = evhttp_request_get_output_headers(req); evhttp_add_header(headers, "Content-Encoding", "gzip"); evhttp_send_reply(req, code, reason, gzbuf); evbuffer_free(gzbuf); /* Drain original buffer, as would be after evhttp_send_reply() */ evbuffer_drain(evbuf, evbuffer_get_length(evbuf)); return; out_fail_gz: deflateEnd(&strm); out_fail_init: evbuffer_free(gzbuf); no_gzip: evhttp_send_reply(req, code, reason, evbuf); }
if (cb == NULL) { cb = tr_new (struct cache_block, 1); cb->tor = torrent; cb->piece = piece; cb->offset = offset; cb->length = length; cb->block = _tr_block (torrent, piece, offset); cb->evbuf = evbuffer_new (); tr_ptrArrayInsertSorted (&cache->blocks, cb, cache_block_compare); } cb->time = tr_time (); assert (cb->length == length); evbuffer_drain (cb->evbuf, evbuffer_get_length (cb->evbuf)); evbuffer_remove_buffer (writeme, cb->evbuf, cb->length); cache->cache_writes++; cache->cache_write_bytes += cb->length; return cacheTrim (cache); } int tr_cacheReadBlock (tr_cache * cache, tr_torrent * torrent, tr_piece_index_t piece, uint32_t offset, uint32_t len, uint8_t * setme)
// Эта штука срабатывает, когда кто-то нам пишет void connection::buff_on_read(struct bufferevent *bev, void *ctx) { connection* _this = static_cast<connection*>(ctx); log << "Sth read\n"; // буфер с нашими данными evbuffer* input = bev->input; // копируем всё это дело в строку size_t len = evbuffer_get_length(bev->input); char* data = new char[len]; if ((evbuffer_copyout(input, data, len)) < 0) { event_base_loopbreak(_this->evbase); } else { log << "Parsing...\n"; // ПАРСИМ (TODO: здесь в оригинале должно быть всё красиво. Нужно смотреть тип запроса, обрабатывать все заголовки, вешать нормальные колбеки и много всего.), но сейчас нам важно поолучить только URL _this->parser.data = _this; // устанавливаем для парсера связь с внешним миром http_parser_settings settings; memset(&settings, 0, sizeof(settings)); // устанавливаем обработчики settings.on_url = [](http_parser* p, const char* at, size_t len) -> int { // копируем URL // printf("Url: %.*s\n", (int)len, at); char* t = new char[len-1]; memset(t, '\0', len*sizeof(char)); strncpy(t, at+1, len-1); // len-1 т.к. там пробел // избавляемся от параметров for (char* i = t; *i; ++i) { if (*i == '?') { *i = '\0'; break; } } static_cast<connection*>(p->data)->client_request.uri = t; delete t; return 0; }; settings.on_header_field = [](http_parser* p, const char* at, size_t len) -> int {return 0;}; settings.on_header_value = [](http_parser* p, const char* at, size_t len) -> int {return 0;}; settings.on_headers_complete = [](http_parser*) -> int {return 0;}; size_t nparsed = http_parser_execute(&_this->parser, &settings, data, len); if (nparsed != len) { log << "Can't parse\n"; event_base_loopbreak(_this->evbase); } // НА ЭТОМ ЭТАПЕ МЫ ВСЁ РАСПАРСИЛИ И ИМЕЕМ ЗАПОЛНЕННЫЙ РЕКВЕСТ (client_request) // _this->client_request.method = http_method_str(_this->parser.method); log << "URI=" << _this->client_request.uri << std::endl; // Пытаемся открыть требуемый файл и скрамливаем его клиенту int fd = open(_this->client_request.uri.c_str(), O_RDONLY); //вывод имени файла по байтам // for (auto& i: _this->client_request.uri) { // printf("%d ", i); // } // puts(""); // Если не получилось - шлём ошибку if (fd < 0) { log << "No such file or directory\n";//perror("KEK"); if ((send(_this->client_sock, response::not_found.c_str(), response::not_found.length(), MSG_NOSIGNAL)) < 0) { log << "cant't send!!!\n"; } } else { // если всё окей if ((send(_this->client_sock, response::ok.c_str(), response::ok.length(), MSG_NOSIGNAL | MSG_MORE)) < 0) { log << "can't send\n"; } else { struct stat stat_buf; fstat(fd, &stat_buf); // Посылаем файл ssize_t recv = sendfile( _this->client_sock, fd, nullptr, stat_buf.st_size); if (recv != stat_buf.st_size) { log << "file not sent at all\n"; } } } event_base_loopexit(_this->evbase, nullptr); } }
void conn_read_cb(struct bufferevent *bev, void *arg) { conn *c = (conn *)arg; user_callback *cb = (user_callback *)(c->data); struct evbuffer* input = bufferevent_get_input(bev); size_t total_len = evbuffer_get_length(input); while (1) { if (total_len < MSG_HEAD_SIZE) { goto conti; } else { unsigned char *buffer = evbuffer_pullup(input, MSG_HEAD_SIZE); if (NULL == buffer) { merror("evbuffer_pullup MSG_HEAD_SIZE failed!"); goto err; } unsigned short *cur = (unsigned short *)buffer; unsigned int len = ntohs(*(unsigned int *)cur); cur += 2; if (MSG_MAX_SIZE < len) { merror("len:%d > MSG_MAX_SIZE!", len); goto err; } if (total_len < MSG_HEAD_SIZE + len) goto conti; size_t msg_len = MSG_HEAD_SIZE + len; buffer = evbuffer_pullup(input, msg_len); if (NULL == buffer) { merror("evbuffer_pullup msg_len failed!"); goto err; } /* TODO frequency limit */ /* callback */ if (cb->rpc) (*(cb->rpc))(c, buffer, msg_len); if (evbuffer_drain(input, msg_len) < 0) { merror("evbuffer_drain failed!"); goto err; } total_len -= msg_len; } } return; err: mdebug("close sockect!"); if (cb->disconnect) { (*(cb->disconnect))(c); } conn_decref(c); return; conti: bufferevent_enable(bev, EV_READ); return; }