ssize_t sock_recv(int fd, char *buf, size_t size) { coro_sock *sock = find_sock_by_fd(fd); // 一个socket可能被多个协程持有,而这多个持有当前socket的协程,可能 // 当前并没有阻塞再这个socket上,考虑如下情况,某个持有当前socket的协程 // 释放了这个socket对象,那么,当某个持有这个socket的协程在使用这个socket的 // 时候,就可能无法通过fd反查socket了 // 所以,这里要重新尝试获取socket,判断socket对象是否有效 // 这里可能会有bug产生,因为fd是每次取最小的,如果close掉了,立马又创建了一个socket // 那么2个fd是重复,因此,完善的解决方案大概是这样子的 // 但是这个情况在非协程环境也是存在的,因此,不做针对他的特殊处理了 if ( !sock ) { return -1; } sock->op = READING; ssize_t status = 0; // 调用sock_recv的时候,还没有进行yield // 所以,当前协程就是持有当前socket对象的协程 // 因此,我们可以把当前协程加到socket的持有协程里面去 uthread_t cur = coro_current_uthread(); if ( TEST_WAIT_READ(sock->status) ) { if ( TEST_EOF(sock->status) ) { status = -1; // SET_EOF(sock->status); } else { // 如果当前socket在等待读 // 那么说明当前协程已经无法继续往下执行了, // 1. 协程会阻塞在当前socket的读队列里面 // 2. socket被阻塞在当前协程 // 发生了阻塞,那么我们需要切换到其他的协程上去,放弃继续执行机会 set_pending_status(sock, set_wait_read_status, cur, set_wait_read_status); sock->readqueue->push(cur); status = coro_schedule_uthread(cur, 0); } } // 执行到这里,说明我们完成了IO操作 // 那么说明,我们的协程当前一定没有被阻塞,所以移除阻塞标志 // 假设read被阻塞了,那么,执行到这里一定是经历过调度,然后回来的 // 那么,我们就无法保证这个sock指针还是有效的,因为他可能被释放过了 // 因此这里要重新获取sock指针 ssize_t ret = status; sock = find_sock_by_fd(fd); if ( ret >= 0 && sock ) { bufferevent * bev = sock->bev; struct evbuffer *input; input = bufferevent_get_input(bev); int n = evbuffer_remove(input, buf, size); // 无论如何,我们都认为这次read已经结束了 clear_pending_status(sock, cur); // 如果inputbuffer还有剩余空间,那么我们留下可读标记 if ( n >= 0 && evbuffer_get_length(input) > 0 ) { SET_READ(sock->status); } else { SET_WAIT_READ(sock->status); } ret = (n >= 0 ? n : -1); } return ret; }
/** * Called by libevent when there is data to read. */ void buffered_on_read(struct bufferevent *bev, void *arg) { client_t *client = (client_t *)arg; char *line; size_t n; /* If we have input data, the number of bytes we have is contained in * bev->input->off. Copy the data from the input buffer to the output * buffer in 4096-byte chunks. There is a one-liner to do the whole thing * in one shot, but the purpose of this server is to show actual real-world * reading and writing of the input and output buffers, so we won't take * that shortcut here. */ struct evbuffer *input = bufferevent_get_input(bev); line = evbuffer_readln(input, &n, EVBUFFER_EOL_CRLF); char cmd[256], protocol[256], path[MAX_PATH_SIZE]; httpHeader_t httpHeader; httpHeader.command = UNKNOWN_C; httpHeader.status = OK; if (n != 0) { int scaned = sscanf(line, "%s %s %s\n", cmd, path, protocol); if (scaned == 3) { if (!strcmp(cmd, "GET")) { httpHeader.command = GET; } else if (!strcmp(cmd, "HEAD")) { httpHeader.command = HEAD; } else { httpHeader.command = UNKNOWN_C; } /* if (strcmp(protocol, "HTTP/1.1")) { printf("BAD PROTOCOL%s\n", protocol); httpHeader.status = BAD_REQUEST; }*/ if (path[0] != '/') { printf("BAD INPUtT\n"); httpHeader.status = BAD_REQUEST; } urlDecode(path); httpHeader.type = getContentType(path); if (getDepth(path) == -1) { printf("BAD DEPTH\n"); httpHeader.status = BAD_REQUEST; } } else { printf("Bad scanned\n"); httpHeader.status = BAD_REQUEST; } } else { printf("OOO BAD N\n"); httpHeader.status = BAD_REQUEST; } switch (httpHeader.status) { case BAD_REQUEST: printf("Bad request\n"); break; case OK: printf("OK\n"); break; case NOT_FOUND: printf("NOt found\n"); break; } switch (httpHeader.command) { case UNKNOWN_C: printf("UNKNOWS\n"); break; case GET: printf("GET\n"); break; case HEAD: printf("HEAD\n"); break; } printf("%s\n", path); free(line); if (httpHeader.status != BAD_REQUEST) { char fullPath[2048] = {'\0'}; strcpy(fullPath, ROOT_PATH); strcat(fullPath, path); int fd = open(fullPath, O_RDONLY); if (fd < 0) { httpHeader.status = NOT_FOUND; printf("Can't open %s", fullPath); } client->openFd = -1; struct stat st; httpHeader.length = lseek(fd, 0, SEEK_END); if (httpHeader.length == -1 || lseek(fd, 0, SEEK_SET) == -1) { httpHeader.status = BAD_REQUEST; printf("Cant seek\n"); } addHeader(&httpHeader, client->output_buffer); if (fstat(fd, &st) < 0) { perror("fstat"); } if (fd != -1 && httpHeader.status == OK && httpHeader.command == GET) { evbuffer_set_flags(client->output_buffer, EVBUFFER_FLAG_DRAINS_TO_FD); if(evbuffer_add_file(client->output_buffer, fd, 0, httpHeader.length) != 0) { perror("add file"); } } // printf("%d\n", fd); } //evbuffer_add(client->output_buffer, "AAA", 3); /* while ((line = evbuffer_readln(input, &n, EVBUFFER_EOL_CRLF))) { evbuffer_add(client->output_buffer, line, n); evbuffer_add(client->output_buffer, "\n", 1); free(line); }*/ //evbuffer_add_printf(client->output_buffer, "HTTP/1.1 200 OK\r\rContent-Type: text/html\r\nDate: Sun, 14 Sep 2014 08:39:53 GMT\r\nContent-Length: 5\r\n\r\n OKK\r\n"); // while (evbuffer_get_length(input) > 0) { /* Remove a chunk of data from the input buffer, copying it into our * local array (data). */ // nbytes = evbuffer_remove(input, data, 4096); /* Add the chunk of data from our local array (data) to the client's * output buffer. */ // evbuffer_add(client->output_buffer, data, nbytes); //} /* Send the results to the client. This actually only queues the results * for sending. Sending will occur asynchronously, handled by libevent. */ if (bufferevent_write_buffer(bev, client->output_buffer) == -1) { errorOut("Error sending data to client on fd %d\n", client->fd); } //bufferevent_setcb(bev, NULL, buffered_on_write, NULL, NULL); //bufferevent_enable(bev, EV_WRITE); }
int netstring_read_evbuffer(struct bufferevent *bev, netstring_t **netstring) { int bytes, offset; size_t read_len; char *temp_buffer; temp_buffer = NULL; offset = 0; struct evbuffer *ib = bufferevent_get_input(bev); if (*netstring == NULL) { /* No buffer yet. Peek at first 10 bytes, to get length and colon. */ unsigned char *lenstr; int i, len; struct evbuffer_ptr *search_end = pkg_malloc(sizeof(struct evbuffer_ptr)); CHECK_MALLOC(search_end); i = evbuffer_get_length(ib); len = ((NETSTRING_PEEKLEN <= i) ? (NETSTRING_PEEKLEN) : (i-1)); evbuffer_ptr_set(ib, search_end, len, EVBUFFER_PTR_SET); struct evbuffer_ptr loc = evbuffer_search_range(ib, ":", 1, NULL, search_end); pkg_free(search_end); if (loc.pos < 0) { // no colon found if (i > NETSTRING_PEEKLEN) return NETSTRING_ERROR_TOO_LONG; // TODO: peek at what's available and return suitable errors return NETSTRING_INCOMPLETE; } lenstr = pkg_malloc(loc.pos+1); CHECK_MALLOC(lenstr); bytes = evbuffer_remove(ib, lenstr, loc.pos+1); /* First character must be a digit */ if (!isdigit(lenstr[0])) return NETSTRING_ERROR_NO_LENGTH; /* No leading zeros allowed! */ if (lenstr[0] == '0' && isdigit(lenstr[1])) return NETSTRING_ERROR_LEADING_ZERO; if (lenstr[loc.pos] != ':') { return NETSTRING_ERROR_NO_COLON; } len = i = 0; /* Read the number of bytes */ for (i = 0; i < loc.pos; i++) { /* Accumulate each digit, assuming ASCII. */ len = len*10 + (lenstr[i] - '0'); } pkg_free(lenstr); /* alloc the memory needed for the whole netstring */ read_len = len+1; temp_buffer = pkg_malloc(read_len); CHECK_MALLOC(temp_buffer); /* initialize the netstring struct */ *netstring = pkg_malloc(sizeof(netstring_t)); CHECK_MALLOC(netstring); (*netstring)->read = 0; (*netstring)->length = len; (*netstring)->buffer = temp_buffer; (*netstring)->string = NULL; } else { /* Continue reading into an existing buffer. */ offset = (*netstring)->read; read_len = (*netstring)->length-offset+1; temp_buffer = (*netstring)->buffer + offset; } /* Read from the evbuffer */ bytes = evbuffer_remove(ib, temp_buffer, read_len); int total = (*netstring)->read += bytes; /* See if we have the whole netstring yet */ if (read_len > bytes) { return NETSTRING_INCOMPLETE; } /* Test for the trailing comma */ if (((*netstring)->buffer)[total-1] != ',') { return NETSTRING_ERROR_NO_COMMA; } /* Replace the comma with \0 */ (*netstring)->buffer[total-1] = '\0'; /* Set the string pointer to the "body" of the netstring */ (*netstring)->string = (*netstring)->buffer; return 0; }
void TS3::telnetMessage(bufferevent *bev, void *parentPtr) { auto parent = static_cast<TS3*>(parentPtr); std::string s; char buf[1024]; int n; evbuffer *input = bufferevent_get_input(bev); while ((n = evbuffer_remove(input, buf, sizeof(buf))) > 0) s.append(buf, n); // trim CR LF if (s.size() > 2) s.erase(s.size() - 2); else LOG(ERROR) << "Received telnet line that is too short!"; // Pong messages clutter INFO log badly // LOG(INFO) << s; switch (parent->_sqState) { case TS3::State::NotConnected: // FIXME: very poor criteria for connection static const std::string welcome = "Welcome to the TeamSpeak 3 ServerQuery interface"; if (s.find(welcome) != s.npos) { LOG(INFO) << "Connected to ServerQuery interface"; parent->_sqState = TS3::State::ServerQueryConnected; evbuffer_add_printf(bufferevent_get_output(bev), "login %s %s\n", parent->GetRawConfigValue("Teamspeak.Login").c_str(), parent->GetRawConfigValue("Teamspeak.Password").c_str()); } break; case TS3::State::ServerQueryConnected: static const std::string okMsg = "error id=0 msg=ok"; if (beginsWith(s, okMsg)) { LOG(INFO) << "Authorized on TS3 server"; parent->_sqState = TS3::State::Authrozied; evbuffer_add_printf(bufferevent_get_output(bev), "use port=9987\n"); } break; case TS3::State::Authrozied: if (beginsWith(s, okMsg)) { LOG(INFO) << "Connected to Virtual Server"; parent->_sqState = TS3::State::VirtualServerConnected; evbuffer_add_printf(bufferevent_get_output(bev), "clientupdate client_nickname=%s\n", parent->_nickname.c_str()); } break; case TS3::State::VirtualServerConnected: if (beginsWith(s, okMsg)) { LOG(INFO) << "Nickname is set"; parent->_sqState = TS3::State::NickSet; evbuffer_add_printf(bufferevent_get_output(bev), "servernotifyregister event=server\n"); } break; case TS3::State::NickSet: if (beginsWith(s, okMsg)) { LOG(INFO) << "Subscribed to connects/disconnects"; parent->_sqState = TS3::State::Subscribed; evbuffer_add_printf(bufferevent_get_output(bev), "servernotifyregister event=textchannel id=%ld\n", parent->_channelID); } break; case TS3::State::Subscribed: if (beginsWith(s, "notifycliententerview")) { auto tokens = tokenize(s, ' '); try { parent->TS3Connected(tokens.at(4).substr(5), tokens.at(6).substr(16)); } catch (std::exception &e) { LOG(ERROR) << "Can't parse message: \"" << s << "\" | Exception: " << e.what(); } break; } if (beginsWith(s, "notifyclientleftview")) { auto tokens = tokenize(s, ' '); try { parent->TS3Disconnected(tokens.at(5).substr(5, tokens.at(5).size() - 5)); } catch (std::exception &e) { LOG(ERROR) << "Can't parse message: \"" << s << "\" | Exception: " << e.what(); } break; } if (beginsWith(s, "notifytextmessage")) { auto tokens = tokenize(s, ' '); try { auto nick = ReplaceTS3Spaces(tokens.at(4).substr(12)); auto message = ReplaceTS3Spaces(tokens.at(2).substr(4)); parent->TS3Message(nick, message); } catch (std::exception &e) { LOG(ERROR) << "Can't parse message: \"" << s << "\" | Exceptions: " << e.what(); } break; } break; } }
// a part of input data is received static void s3http_client_read_cb (struct bufferevent *bev, void *ctx) { S3HttpClient *http = (S3HttpClient *) ctx; struct evbuffer *in_buf; in_buf = bufferevent_get_input (bev); if (http->response_state == S3R_expected_first_line) { if (!s3http_client_parse_first_line (http, in_buf)) { g_free (http->response_code_line); http->response_code_line = NULL; LOG_debug (HTTP_LOG, "More first line data expected !"); return; } LOG_debug (HTTP_LOG, "Response: HTTP %d.%d, code: %d, code_line: %s", http->major, http->minor, http->response_code, http->response_code_line); http->response_state = S3R_expected_headers; } if (http->response_state == S3R_expected_headers) { if (!s3http_client_parse_headers (http, in_buf)) { LOG_debug (HTTP_LOG, "More headers data expected !"); s3http_client_free_headers (http->l_input_headers); http->l_input_headers = NULL; return; } LOG_debug (HTTP_LOG, "ALL headers received !"); http->response_state = S3R_expected_data; } if (http->response_state == S3R_expected_data) { // add input data to the input buffer http->input_read += evbuffer_get_length (in_buf); evbuffer_add_buffer (http->input_buffer, in_buf); // LOG_debug (HTTP_LOG, "INPUT buf: %zd bytes", evbuffer_get_length (http->input_buffer)); // request is fully downloaded if (http->input_read >= http->input_length) { LOG_debug (HTTP_LOG, "DONE downloading last chunk, in buf size: %zd !", evbuffer_get_length (http->input_buffer)); // inform client that a end of data is received if (http->on_last_chunk_cb) http->on_last_chunk_cb (http, http->input_buffer, http->cb_ctx); http->response_state = S3R_expected_first_line; // rest s3http_client_request_reset (http); // inform pool client // XXX: /* if (http->on_request_done_pool_cb) http->on_request_done_pool_cb (http, http->pool_cb_ctx); */ // only the part of it } else { // inform client that a part of data is received if (http->on_chunk_cb) http->on_chunk_cb (http, http->input_buffer, http->cb_ctx); } } }
void client_event_read(struct bufferevent *bev, void *arg) { log_debug("client_event_read"); client_t *c = (client_t*) arg; server_t *s = c->server; log_debug("Received read event from client socket %d", c->socket); if(c->msg == NULL) { c->msg = msg_init(c->worker->msg_buf); } int res = evbuffer_add_buffer(c->evbuf, bufferevent_get_input(bev)); char *line; while((line = evbuffer_readln(c->evbuf, NULL, EVBUFFER_EOL_CRLF)) != NULL) { log_debug("Read data : %s", line); decode_result res = decoder_run(c->msg, line); msg_print(c->msg); switch(res) { case DR_ERR_FORMAT: client_increase_req_err(c); worker_increase_req_err(c->worker); msg_clean(c->msg); log_debug("Wrong message format : %s", line); resp_error_wrong_msg_format(c->worker->msg_buf, c->socket); break; case DR_ERR_PARAM_FORMAT: client_increase_req_err(c); worker_increase_req_err(c->worker); msg_clean(c->msg); log_debug("Wrong parameter format : %s", line); resp_error_param_format(c->worker->msg_buf, c->socket); break; case DR_OK: log_debug("Data OK."); break; default: break; } enum cmd_func_ret cmd_ret; switch(msg_get_stat(c->msg)) { case MSG_STAT_DONE: log_debug("Message Done."); client_increase_req_ok(c); worker_increase_req_ok(c->worker); cmd_ret = command_proc(c, c->msg); if(cmd_ret != CMD_FUNC_DONE) { c->req_ok++; s->req_ok++; } msg_clean(c->msg); break; } // ic_trans_stat trans_stat = decoder_read_line(c, line); // log_debug("Trans stat : %d", trans_stat); // if(trans_stat == IC_TRANS_ALL_DONE) // { // log_debug("Trasfer done, "); // } } }
//处理读事件 void TcpHandler::dealReadEvent(int & success) { //cout << "m_pLastNode addr is: " << m_pLastNode <<endl; if(m_pLastNode) { //cout << "m_pLastNode msglen is: "<< m_pLastNode->m_nMsgLen <<endl; //cout << "m_pLastNode m_nOffSet is: " << m_pLastNode->m_nOffSet <<endl; } else { //cout << "m_pLastNode addr is null!!!" <<endl; } evbuffer * inputBuf = bufferevent_get_input(m_pBufferevent); size_t inputLen = evbuffer_get_length(inputBuf); //cout <<"total len is : "<< inputLen <<endl; while(inputLen > 0) { //tcphandler第一次接收消息或者该node接收完消息,需要开辟新的node接受消息 if(!m_pLastNode || m_pLastNode->m_nMsgLen <= m_pLastNode->m_nOffSet) { //判断消息长度是否满足包头大小,不满足跳出 if(inputLen < PACKETHEADLEN) { break; } char data[PACKETHEADLEN] = {0}; bufferevent_read(m_pBufferevent, data, PACKETHEADLEN); struct PacketHead packetHead; memcpy(&packetHead, data, PACKETHEADLEN); cout << "packetId is : " <<packetHead.packetID << endl; cout << "packetLen is : " << packetHead.packetLen << endl; if(packetHead.packetID > 1024 || packetHead.packetID < 0) { success = 0; return; } insertNode(packetHead.packetID, packetHead.packetLen); inputLen -= PACKETHEADLEN; //cout << "after remove head the length is : " << inputLen <<endl; } //考虑可能去包头后剩余的为0 if(inputLen <= 0) { break; } //读取去除包头后剩余消息 tcpRead(inputLen); } }
void read_cb(struct bufferevent* bev, void* ctx) { struct evbuffer* input = bufferevent_get_input(bev); if (!input) return; size_t length = evbuffer_get_length(input); btc_node *node = (btc_node *)ctx; // expand the cstring buffer if required cstr_alloc_minsize(node->recvBuffer, node->recvBuffer->len+length); // copy direct to cstring, avoid another heap buffer evbuffer_copyout(input, node->recvBuffer->str+node->recvBuffer->len, length); node->recvBuffer->len += length; // drain the event buffer evbuffer_drain(input, length); struct const_buffer buf = {node->recvBuffer->str, node->recvBuffer->len}; btc_p2p_msg_hdr hdr; char *read_upto = NULL; do { //check if message is complete if (buf.len < BTC_P2P_HDRSZ) { break; } btc_p2p_deser_msghdr(&hdr, &buf); if (buf.len < hdr.data_len) { //if we haven't read the whole message, continue and wait for the next chunk break; } if (buf.len >= hdr.data_len) { //at least one message is complete struct const_buffer cmd_data_buf = {buf.p, buf.len}; btc_node_parse_message(node, &hdr, &cmd_data_buf); //skip the size of the whole message buf.p += hdr.data_len; buf.len -= hdr.data_len; read_upto = (void *)buf.p; } if (buf.len == 0) { //if we have "consumed" the whole buffer node->recvBuffer->len = 0; break; } } while(1); if (read_upto != NULL && node->recvBuffer->len != 0 && read_upto != (node->recvBuffer->str + node->recvBuffer->len)) { char *end = node->recvBuffer->str + node->recvBuffer->len; size_t available_chunk_data = end - read_upto; //partial message cstring *tmp = cstr_new_buf(read_upto, available_chunk_data); cstr_free(node->recvBuffer, true); node->recvBuffer = tmp; } }
void ClientImpl::regularReadCallback(struct bufferevent *bev) { struct evbuffer *evbuf = bufferevent_get_input(bev); boost::shared_ptr<CxnContext> context = m_contexts[bev]; int32_t remaining = static_cast<int32_t>(evbuffer_get_length(evbuf)); bool breakEventLoop = false; if (context->m_lengthOrMessage && remaining < 4) { return; } while (true) { if (context->m_lengthOrMessage && remaining >= 4) { char lengthBytes[4]; ByteBuffer lengthBuffer(lengthBytes, 4); evbuffer_remove( evbuf, lengthBytes, 4); context->m_nextLength = static_cast<size_t>(lengthBuffer.getInt32()); context->m_lengthOrMessage = false; remaining -= 4; } else if (remaining >= context->m_nextLength) { boost::shared_array<char> messageBytes = boost::shared_array<char>(new char[context->m_nextLength]); context->m_lengthOrMessage = true; evbuffer_remove( evbuf, messageBytes.get(), static_cast<size_t>(context->m_nextLength)); remaining -= context->m_nextLength; InvocationResponse response(messageBytes, context->m_nextLength); boost::shared_ptr<CallbackMap> callbackMap = m_callbacks[bev]; CallbackMap::iterator i = callbackMap->find(response.clientData()); if(i != callbackMap->end()){ try { m_ignoreBackpressure = true; breakEventLoop |= i->second->callback(response); m_ignoreBackpressure = false; } catch (std::exception &e) { if (m_listener.get() != NULL) { try { m_ignoreBackpressure = true; breakEventLoop |= m_listener->uncaughtException( e, i->second, response); m_ignoreBackpressure = false; } catch (const std::exception& e) { std::cerr << "Uncaught exception handler threw exception: " << e.what() << std::endl; } } } /* * When Volt sends us out a notification, it comes with the ClientData * filled in with a known 64-bit number. * In this case, we don't want to remove the callback. We need a static * callback here to continually process notifications. */ if(response.clientData() != VOLT_NOTIFICATION_MAGIC_NUMBER){ callbackMap->erase(i); m_outstandingRequests--; } } //If the client is draining and it just drained the last request, break the loop if (m_isDraining && m_outstandingRequests == 0) { breakEventLoop = true; } else if (m_loopBreakRequested && (m_outstandingRequests <= m_maxOutstandingRequests)) { // ignore break requested until we have too many outstanding requests breakEventLoop = true; } } else { if (context->m_lengthOrMessage) { bufferevent_setwatermark( bev, EV_READ, 4, HIGH_WATERMARK); } else { bufferevent_setwatermark( bev, EV_READ, static_cast<size_t>(context->m_nextLength), HIGH_WATERMARK); } breakEventLoop |= (m_loopBreakRequested && (m_outstandingRequests <= m_maxOutstandingRequests)); break; } } if (breakEventLoop) { event_base_loopbreak( m_base ); } }
void NFCNet::conn_readcb(struct bufferevent *bev, void *user_data) { //接受到消息 NetObject* pObject = (NetObject*)user_data; if (!pObject) { return; } NFCNet* pNet = (NFCNet*)pObject->GetNet(); if (!pNet) { return; } if (pObject->GetRemoveState()) { return; } struct evbuffer *input = bufferevent_get_input(bev); if (!input) { return; } size_t len = evbuffer_get_length(input); //返回给客户端 // struct evbuffer *output = bufferevent_get_output(bev); // evbuffer_add_buffer(output, input); // SendMsg(1, strData,len, pObject->GetFd()); ////////////////////////////////////////////////////////////////////////// if (len > NFIMsgHead::NF_MSGBUFF_LENGTH) { char* strMsg = new char[len]; if(evbuffer_remove(input, strMsg, len) > 0) { pObject->AddBuff(strMsg, len); } delete[] strMsg; } else { memset(pNet->mstrMsgData, 0, NFIMsgHead::NF_MSGBUFF_LENGTH); if(evbuffer_remove(input, pNet->mstrMsgData, len) > 0) { pObject->AddBuff(pNet->mstrMsgData, len); } } while (1) { int nDataLen = pObject->GetBuffLen(); if (nDataLen > pNet->mnHeadLength) { if (!pNet->Dismantle(pObject)) { break; } } else { break; } } }
static void socks_read_cb(struct bufferevent *bev, void *ptr) { obfsproxyssh_client_session_t *session = ptr; obfsproxyssh_t *state = session->client->state; struct evbuffer *buf; struct sockaddr_in addr; unsigned char *p, *userid; size_t len; int i; assert(bev == session->socks_ev); buf = bufferevent_get_input(bev); len = evbuffer_get_length(buf); if (len < SOCKS_4_CONNECT_REQUEST_LEN) return; p = evbuffer_pullup(buf, len); if (NULL == p) { log_f(state, "SOCKS: Error: %s Failed to pullup (OOM?)", bdata(session->socks_addr)); goto out_free; } /* * Parse the SOCKS 4 CONNECT * * uint8_4 VN -> 4 * uint8_t CN -> 1 * uint16_t DSTPORT * uint32_t DSTIP * uint8_t USERID[] (Tor PT arguments) * uint8_t NULL -> 0 */ if (SOCKS_4_VER != p[0]) { log_f(state, "SOCKS: Error: %s Invalid SOCKS protocol version %d", bdata(session->socks_addr), p[0]); goto out_free; } if (SOCKS_4_CMD_CONNECT != p[1]) { log_f(state, "SOCKS: Error: %s Invalid SOCKS 4 command %d", bdata(session->socks_addr), p[1]); goto out_free; } userid = p + SOCKS_4_CONNECT_REQUEST_LEN; for (i = 0; i < len - SOCKS_4_CONNECT_REQUEST_LEN; i++) { if ('\0' == userid[i]) { if (len != SOCKS_4_CONNECT_REQUEST_LEN + i + 1) { log_f(state, "SOCKS: Error: %s Trailing garbage after CONNECT", bdata(session->socks_addr)); goto out_free; } bufferevent_disable(bev, EV_READ); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = *(uint16_t *) (p + 2); addr.sin_addr.s_addr = *(uint32_t *) (p + 4); if (ssh_new_connection(session, &addr, (char *) userid)) goto out_free; evbuffer_drain(buf, len); return; } } if (len > OBFSPROXYSSH_CLIENT_MAX_SOCKS_REQ) { log_f(state, "SOCKS: Error: %s SOCKS 4 Request too big", bdata(session->socks_addr)); goto out_free; } return; out_free: session_free(session); return; }
/* * Discard any data received. This is used after reading the response's * status line. */ static void session_readcb_drain(struct bufferevent *bev, void *thunk) { struct evbuffer *evbuf = bufferevent_get_input(bev); evbuffer_drain(evbuf, evbuffer_get_length(evbuf)); }
/** * 客户端和远程服务器的交互 */ void srv_bufferread_cb(struct bufferevent *bev, void *ptr) { size_t n = 0; CTL_HEAD head; struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *output = bufferevent_get_output(bev); if ( evbuffer_remove(input, &head, CTL_HEAD_LEN) != CTL_HEAD_LEN) { st_d_print("读取数据包头%d错误!", CTL_HEAD_LEN); return; } if (!sd_id128_equal(head.mach_uuid, cltopt.session_uuid)) { SYS_ABORT("服务端返回UUID校验失败:%s-%s", SD_ID128_CONST_STR(head.mach_uuid), SD_ID128_CONST_STR(cltopt.session_uuid)); } if (head.cmd == HD_CMD_ERROR) { st_d_error("SERVER RETURNED ERROR!"); exit(EXIT_SUCCESS); } if (head.cmd == HD_CMD_CONN_ACT) { P_PORTTRANS p_trans = sc_find_trans(head.extra_param); if (!p_trans) { SYS_ABORT("本地未找到连接信息:%d", head.extra_param); } bufferevent_enable(p_trans->local_bev, EV_READ|EV_WRITE); bufferevent_enable(p_trans->srv_bev, EV_READ|EV_WRITE); st_d_print("开始传输数据:%d", head.extra_param); } if (head.cmd == HD_CMD_END_TRANS) { P_PORTTRANS p_trans = sc_find_trans(head.extra_param); if (p_trans) { st_d_print("EXTRA CLOSE TRANS: %d", head.extra_param); sc_free_trans(p_trans); } } if (head.cmd == HD_CMD_SS5_ACT) { // OK,返回给本地程序告知可以开始传输了 // 这个绑定地址目前还没利用,主要是需要FTP这类需要带外传输另外连接端口的 char ret_msg[10] = "\x05\x00\x00\x01\x00\x00\x00\x00\x10\x10"; P_PORTTRANS p_trans = sc_find_trans(head.extra_param); if (!p_trans) { SYS_ABORT("本地SS5未找到连接信息:%d", head.extra_param); } bufferevent_enable(p_trans->local_bev, EV_READ|EV_WRITE); bufferevent_enable(p_trans->srv_bev, EV_READ|EV_WRITE); bufferevent_write(p_trans->local_bev, ret_msg, sizeof(ret_msg)); st_d_print("SS5准备传输数据:%d", head.extra_param); return; } if (head.cmd == HD_CMD_CONN) { assert(cltopt.C_TYPE == C_DAEMON); if (cltopt.C_TYPE == C_DAEMON) { sc_find_daemon_portmap(head.daemonport, 1); P_PORTTRANS p_trans = sc_create_trans(head.extra_param); p_trans->is_enc = 0; if (!p_trans) { st_d_error("本地无空闲TRANS!"); return; } /*建立本地连接*/ int local_fd = socket(AF_INET, SOCK_STREAM, 0); int reuseaddr_on = 1; if (setsockopt(local_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on)) == -1) { st_d_error("Reuse socket opt faile!\n"); return; } struct sockaddr_in local_srv; local_srv.sin_family = AF_INET; local_srv.sin_addr.s_addr = inet_addr("127.0.0.1"); local_srv.sin_port = htons(head.daemonport); if (connect(local_fd, (struct sockaddr *)&local_srv, sizeof(local_srv))) { st_d_error("连接本地端口%d失败!", head.daemonport); return; } else { st_d_print("连接本地端口%d OK!", head.daemonport); } /*建立服务器连接*/ int srv_fd = socket(AF_INET, SOCK_STREAM, 0); if(sc_connect_srv(srv_fd) != RET_YES) { st_d_error("连接服务器失败!"); return; } struct event_base *base = bufferevent_get_base(bev); evutil_make_socket_nonblocking(local_fd); struct bufferevent *local_bev = bufferevent_socket_new(base, local_fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(local_bev, bufferread_cb, NULL, bufferevent_cb, p_trans); //bufferevent_enable(local_bev, EV_READ|EV_WRITE); evutil_make_socket_nonblocking(srv_fd); struct bufferevent *srv_bev = bufferevent_socket_new(base, srv_fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(srv_bev, bufferread_cb, NULL, bufferevent_cb, p_trans); //bufferevent_enable(srv_bev, EV_READ|EV_WRITE); p_trans->l_port = head.extra_param; p_trans->local_bev = local_bev; p_trans->srv_bev = srv_bev; /* 向服务器报告连接请求 */ // 必须要发送CONN包,触发这个连接转移到线程池处理 CTL_HEAD ret_head; memset(&ret_head, 0, CTL_HEAD_LEN); ret_head.cmd = HD_CMD_CONN; ret_head.extra_param = p_trans->l_port; ret_head.mach_uuid = cltopt.session_uuid; ret_head.direct = DAEMON_USR; bufferevent_write(srv_bev, &ret_head, CTL_HEAD_LEN); st_d_print("DAEMON端准备OK!"); } } }
void BaseServer::read_callback(bufferevent *pBufferEvent, void *user_data) { evbuffer* inputbuf = bufferevent_get_input(pBufferEvent); evbuffer* outputbuf = bufferevent_get_output(pBufferEvent); size_t t; std::string request; request=evbuffer_readln(inputbuf,&t,EVBUFFER_EOL_CRLF); printf("request= %s\n",request.c_str()); std::vector<std::string> result; result = split(request," "); std::string http_method = result[0]; std::string http_path = result[1]; std::string http_version= result[2]; std::cout<<"method: "<<http_method<<std::endl; std::cout<<"path: "<<http_path<<std::endl; std::cout<<"http_version: "<<http_version<<std::endl; printf("path=%d\n",http_path.size()); std::string content_type; auto pos = http_path.find(".jpg"); if(std::string::npos==pos) content_type = "text/html\r\n"; else content_type = "image/jpg\r\n"; if(http_path=="/") { http_path="index.html"; } else { http_path=http_path.substr(1); } std::ifstream ifile(http_path.c_str()); if(ifile) { std::stringstream stream; stream << ifile.rdbuf(); std::string filecontent(stream.str()); ifile.close(); stream.str(""); stream<<"HTTP/1.1 200 OK\r\n"<<"Content-Type: "<<content_type <<"Content-Length: "<<filecontent.size()<<"\r\n\r\n"; stream<<filecontent; std::string response(stream.str()); stream.str(""); //std::cout<<"response****"<<response; evbuffer_add(outputbuf,response.c_str(),response.size()); }else { } evbuffer* tmp=evbuffer_new(); evbuffer_add_buffer(tmp,inputbuf); evbuffer_free(tmp); }
void MessageManager::MessageDispatcher(struct bufferevent *bev, void *ctx) { bufferevent_lock(bev); struct evbuffer *input = bufferevent_get_input(bev); evutil_socket_t socketFD = bufferevent_getfd(bev); uint32_t length = 0, evbufferLength; bool keepGoing = true; while(keepGoing) { evbufferLength = evbuffer_get_length(input); //If we don't even have enough data to read the length, just quit if(evbufferLength < sizeof(length)) { keepGoing = false; continue; } //Copy the length field out of the message // We only want to copy this data at first, because if the whole message hasn't reached us, // we'll want the whole buffer still present here, undrained if(evbuffer_copyout(input, &length, sizeof(length)) != sizeof(length)) { keepGoing = false; continue; } // Make sure the length appears valid // TODO: Assign some arbitrary max message size to avoid filling up memory by accident if(length < MESSAGE_MIN_SIZE) { LOG(WARNING, "Error parsing message: message too small.", ""); evbuffer_drain(input, sizeof(length)); keepGoing = false; continue; } //If we don't yet have enough data, then just quit and wait for more if(evbufferLength < length) { keepGoing = false; continue; } evbuffer_drain(input, sizeof(length)); //Remove the length of the "length" variable itself length -= sizeof(length); char *buffer = (char*)malloc(length); if(buffer == NULL) { // This should never happen. If it does, probably because length is an absurd value (or we're out of memory) LOG(WARNING, "Error parsing message: malloc returned NULL. Out of memory?.", ""); free(buffer); keepGoing = false; continue; } // Read in the actual message int bytesRead = evbuffer_remove(input, buffer, length); if(bytesRead == -1) { LOG(WARNING, "Error parsing message: couldn't remove data from buffer.", ""); } else if((uint32_t)bytesRead != length) { LOG(WARNING, "Error parsing message: incorrect amount of data received than what expected.", ""); } MessageEndpointLock endpoint = MessageManager::Instance().GetEndpoint(socketFD); if(endpoint.m_endpoint != NULL) { Message *message = Message::Deserialize(buffer, length); if(!endpoint.m_endpoint->PushMessage(message)) { LOG(DEBUG, "Discarding message. Error in pushing it to a queue.", ""); } } else { LOG(DEBUG, "Discarding message. Received it for a non-existent endpoint.", ""); } free(buffer); } bufferevent_unlock(bev); }
static char *read_line(struct bufferevent *bev, size_t *n) { return evbuffer_readln(bufferevent_get_input(bev), n, EVBUFFER_EOL_CRLF_STRICT); }
void createResponse(bufferevent *pBufferEvent) { struct evbuffer* pInputBuffer = bufferevent_get_input(pBufferEvent); struct evbuffer* pOutputBuffer = bufferevent_get_output(pBufferEvent); char *line; size_t size = 0; line = evbuffer_readln(pInputBuffer, &size, EVBUFFER_EOL_CRLF); std::string Request = std::string(line); //std::cout << Request << "\n"; //read method and path size_t nMethodEnd = Request.find(" "); std::string sMethod = std::string(Request, 0, nMethodEnd); //std::cout << sMethod << "\n"; size_t nPathEnd = Request.find(" ", nMethodEnd+1); std::string sRawPath = std::string(Request, nMethodEnd+1, nPathEnd-nMethodEnd-1); //std::cout << sRawPath << "\n"; size_t nDelimPos = sRawPath.find('?'); std::string sHalfRawPath = sRawPath.substr(0, nDelimPos); //std::cout << sHalfRawPath << "\n"; char* sTempPath = new char[sHalfRawPath.length()+1]; // at most the same size + term\0 urlDecode(sTempPath, sHalfRawPath.c_str()); std::string sPath = std::string(sTempPath); //std::cout << sPath << "\n"; if (Request.find(" ", nPathEnd+1) != std::string::npos) { // extra spaces in request //std::cout << "ERROR: extra spaces\n"; writeHeader(pOutputBuffer, STATUS_BAD_REQUEST, TYPE_HTML, MASSAGE_LENGTH_BAD_REQUEST); evbuffer_add(pOutputBuffer, MASSAGE_BAD_REQUEST, MASSAGE_LENGTH_BAD_REQUEST); return; } //Validate path if(!validatePath(sPath)) { //std::cout << "Warning: forbidden path\n"; writeHeader(pOutputBuffer, STATUS_FORBIDDEN, TYPE_HTML, MASSAGE_LENGTH_FORBIDDEN); evbuffer_add(pOutputBuffer, MASSAGE_FORBIDDEN, MASSAGE_LENGTH_FORBIDDEN); return; } //std::cout << "Ok: path ok\n"; //find target file std::string sRealPath = std::string(DOCUMENT_ROOT); sRealPath.append(std::string(sPath)); bool bIndex = false; if (sRealPath[sRealPath.length()-1] == '/') { //std::cout << "Ok: index\n"; sRealPath.append("index.html"); bIndex = true; } int fFile = open(sRealPath.c_str(), O_NONBLOCK|O_RDONLY); if (fFile == -1) { //std::cout << "Warning: file not opened\n"; if (bIndex) { writeHeader(pOutputBuffer, STATUS_FORBIDDEN, TYPE_HTML, MASSAGE_LENGTH_FORBIDDEN); evbuffer_add(pOutputBuffer, MASSAGE_FORBIDDEN, MASSAGE_LENGTH_FORBIDDEN); } else { writeHeader(pOutputBuffer, STATUS_NOT_FOUND, TYPE_HTML, MASSAGE_LENGTH_NOT_FOUND); evbuffer_add(pOutputBuffer, MASSAGE_NOT_FOUND, MASSAGE_LENGTH_NOT_FOUND); } return; } //std::cout << "Ok: file opened\n"; struct stat FileStats; fstat(fFile, &FileStats); if(!strcmp(sMethod.c_str(), METHOD_GET)) { //std::cout << "Ok: method \"get\"\n"; writeHeader(pOutputBuffer, STATUS_OK, getContentType(sRealPath), FileStats.st_size); evbuffer_add_file(pOutputBuffer, fFile, 0, FileStats.st_size); } else if(!strcmp(sMethod.c_str(), METHOD_HEAD)){ //std::cout << "Ok: method \"head\"\n"; // ctime gives only /n so we'll add proper CRLF writeHeader(pOutputBuffer, STATUS_OK, getContentType(sRealPath), FileStats.st_size); evbuffer_add(pOutputBuffer, CRLF, 2); } else { writeHeader(pOutputBuffer, STATUS_BAD_REQUEST, TYPE_HTML, MASSAGE_LENGTH_BAD_REQUEST); evbuffer_add(pOutputBuffer, MASSAGE_BAD_REQUEST, MASSAGE_LENGTH_BAD_REQUEST); } return; }
/* Функция обратного вызова для события: данные готовы для чтения в buf_ev */ static void echo_read_cb(struct bufferevent *buf_ev, void *arg) { struct evbuffer *buf_input = bufferevent_get_input(buf_ev); struct evbuffer *buf_output = bufferevent_get_output(buf_ev); size_t length = evbuffer_get_length(buf_input); char recvBuf[10000]; evbuffer_copyout(buf_input, recvBuf, length); recvBuf[length] = '\0'; std::istringstream split(recvBuf); std::string sRequestFileName; for (std::string token; std::getline(split, token);) { if (token.find("GET ") != std::string::npos) { std::istringstream ss(token); std::getline(ss, sRequestFileName, ' '); // GET std::getline(ss, sRequestFileName, ' '); // fname } } if (sRequestFileName.empty()) { std::cout << "invalid request" << std::endl; //onDisconnect(); bufferevent_free(buf_ev); return; } std::cout << "GET " << sRequestFileName << std::endl; std::string sUsedFileName; if (sRequestFileName == "/") sUsedFileName = "/index.html"; else { std::stringstream ss(sRequestFileName); std::getline(ss, sUsedFileName, '?'); //sUsedFileName = sRequestFileName; } FILE *f = fopen((mainDir + sUsedFileName).c_str(), "r"); if (f == NULL) { // 404 std::cout << "No page " << (mainDir + sUsedFileName) << ", disconnecting." << std::endl; //std::string s404 = "HTTP/1.1 404 Not Found\r\n\r\n"; std::string s404 = "HTTP/1.0 404 Not Found\r\nContent-Length: 0\r\nContent-Type: text/html\r\n\r\n"; /* std::string s404 = "HTTP/1.1 "; s404 += sRequestFileName; const char sz404page[] = "<html><body>404 Page not found :(</html></body>"; s404 += " 404 Not Found\r\nContent-Type: text/html;charset=win-1251\r\nContent-Length: "; s404 += std::to_string(sizeof(sz404page)); s404 += "\r\nCache - Control: no - cache, no - store\r\n\r\n"; s404 += sz404page;*/ //send(m_sock, s404.c_str(), s404.length(), 0); bufferevent_write(buf_ev, s404.c_str(), s404.length()); std::cout << s404 << std::endl; bufferevent_flush(buf_ev, EV_WRITE, BEV_NORMAL); //onDisconnect(); //bufferevent_free(buf_ev); return; } long lSize = 0; if (fseek(f, 0, SEEK_END) == 0) { lSize = ftell(f); fseek(f, 0, SEEK_SET); } char *pBuf = new char[lSize + 1]; if (fread(pBuf, lSize, 1, f) != 1) { // read error delete[] pBuf; std::cout << "Read error, disconnecting." << std::endl; std::string s404 = "HTTP/1.1 "; s404 += sRequestFileName; const char sz404page[] = "<html><body>404 Page not found :(</html></body>"; s404 += " 404 Not Found\r\nContent-Type: text/html;charset=win-1251\r\nContent-Length: "; s404 += std::to_string(sizeof(sz404page)); s404 += "\r\nCache - Control: no - cache, no - store\r\n\r\n"; s404 += sz404page; //send(m_sock, s404.c_str(), s404.length(), 0); bufferevent_write(buf_ev, s404.c_str(), s404.length()); //onDisconnect(); //bufferevent_free(buf_ev); fclose(f); return; }; std::string sMsg = "HTTP/1.1 "; sMsg += sRequestFileName; sMsg += " 200 OK \r\nContent-Type: text/html;charset=win-1251\r\nContent-Length: "; //if( pBuf[1] != 'h' ) // sMsg += std::to_string(lSize + 12 + 14 - 1); //else sMsg += std::to_string(lSize - 1); sMsg += "\r\nCache - Control: no - cache, no - store\r\n\r\n"; pBuf[lSize] = '\0'; // if( pBuf[1] != 'h' ) // sMsg += "<html><body>"; sMsg += pBuf; sMsg.pop_back(); delete[] pBuf; //if( pBuf[1] != 'h' ) // sMsg += "</body></html>"; if (bufferevent_write(buf_ev, sMsg.c_str(), sMsg.length()) != 0) { std::cout << "Send fails, disconnecting." << std::endl; //onDisconnect(); //bufferevent_free(buf_ev); fclose(f); return; } std::cout << "File " << sUsedFileName << " transferred." << std::endl; fclose(f); }
Bool HawkGateThread::OnSessionRead(Session* pSession) { if (!pSession || pSession->Socket == INVALID_SOCKET) return false; //检测输入缓冲区 struct evbuffer* pBuf = bufferevent_get_input((bufferevent*)pSession->Event); if (!pBuf || !evbuffer_get_length(pBuf)) { OnSessionError(pSession); return false; } //循环操作避免事件边缘触发引起的未读取问题 while (evbuffer_get_length(pBuf)) { m_pOctets->Clear(); //读取数据 Int32 iReadSize = evbuffer_remove(pBuf, m_pOctets->Begin(), (Size_t)m_pOctets->Capacity()); if (iReadSize <= 0) { OnSessionError(pSession); return false; } m_pOctets->Resize(iReadSize); //调用性能监视器(只记流量, 解密前才是真实流量数据) if (m_pGateway->GetProfiler()) m_pGateway->GetProfiler()->RegRecvProto(0, iReadSize); //解密 if (pSession->ISecurity) pSession->ISecurity->Update(*m_pOctets); //填充到输入缓冲区 UInt32 iFillPos = 0; UInt32 iBufSize = m_pOctets->Size(); while(iBufSize) { //尽可能填充解码缓冲区 UInt32 iFillSize = HawkMath::Min<UInt32>(pSession->IBuffer->EmptyCap(), iBufSize); if (iFillSize) { void* pData = (Char*)m_pOctets->Begin() + iFillPos; pSession->IBuffer->Insert(pSession->IBuffer->End(), pData, iFillSize); iFillPos += iFillSize; iBufSize -= iFillSize; } //检测是否可以解码输入缓冲区 if (OnSessionDecode(pSession, pSession->IBuffer)) { UInt32 iProtoSize = 0; while (P_ProtocolManager->CheckDecodeProtocol(*pSession->IBuffer, &iProtoSize)) { Char* pProtoData = (Char*)pSession->IBuffer->AvailableData(); ProtoType iProtoType = *((ProtoType*)pProtoData); //检测协议合法性 /* if (!P_ProtocolManager->CheckProtocolLegal(iProtoType)) { HawkFmtError("UnknownProtocol: %d", iProtoType); OnSessionError(pSession); return false; } */ //响应连接的Ping协议 if (iProtoType == SysProtocol::SYS_CLT_PING) { //回复Pong响应 SysProtocol::Sys_SvrPong sProto((UInt32)HawkOSOperator::GetSysTime()); if (!SendProtocol(pSession, &sProto)) return false; } //传递给网关, 再发往后端服务器 else { //给网关发协议消息 SendGateMsg(pSession->Sid, pProtoData, iProtoSize); } //移动数据游标 pSession->IBuffer->MoveNonius(iProtoSize); //调用性能监视器(只记协议数, 避免流量统计不准确) if (m_pGateway->GetProfiler()) m_pGateway->GetProfiler()->RegRecvProto(iProtoType, 0); } } //移除输入缓冲的前段空白 pSession->IBuffer->RemoveBlank(); } } return true; }