static int tr_peerIoTryRead( tr_peerIo * io, size_t howmuch ) { int res = 0; if(( howmuch = tr_bandwidthClamp( &io->bandwidth, TR_DOWN, howmuch ))) { int e; EVUTIL_SET_SOCKET_ERROR( 0 ); res = evbuffer_read( io->inbuf, io->socket, (int)howmuch ); e = EVUTIL_SOCKET_ERROR( ); dbgmsg( io, "read %d from peer (%s)", res, (res==-1?strerror(e):"") ); if( EVBUFFER_LENGTH( io->inbuf ) ) canReadWrapper( io ); if( ( res <= 0 ) && ( io->gotError ) && ( e != EAGAIN ) && ( e != EINTR ) && ( e != EINPROGRESS ) ) { char errstr[512]; short what = EVBUFFER_READ | EVBUFFER_ERROR; if( res == 0 ) what |= EVBUFFER_EOF; tr_net_strerror( errstr, sizeof( errstr ), e ); dbgmsg( io, "tr_peerIoTryRead got an error. res is %d, what is %hd, errno is %d (%s)", res, what, e, errstr ); io->gotError( io, what, io->userData ); } } return res; }
static void ui_handler(evutil_socket_t fd, short what, void *arg) { struct uiclient *client = arg; if (evbuffer_read(client->inbuf, fd, -1) <= 0) { ui_dead(client); return; } for (;;) { size_t eol_len; struct evbuffer_ptr line = evbuffer_search_eol(client->inbuf, NULL, &eol_len, EVBUFFER_EOL_LF); if (line.pos == -1) break; char *p = (char *)malloc(line.pos + 1); if (p != NULL) { evbuffer_remove(client->inbuf, (void *)p, line.pos); p[line.pos] = '\0'; /* ensure termination */ evbuffer_drain(client->inbuf, eol_len); ui_handle_command(client->outbuf, p); free(p); } } ui_write_prompt(client); event_add(client->ev_read, NULL); }
void conn_input (int sockfd, short event, void* arg) { g_print("%d :conn input %d\n", sockfd, event); connection_t *conn = NULL; if ( arg ){ conn = (connection_t *)arg; } if ( EV_TIMEOUT == event ) { printf("arg is %p, timeout\n", arg); event_add (&conn->ev_read, NULL); timeout_add(&conn->ev_read, &conn->tv); } if ( EV_READ == event) { printf("arg is %p, read data\n", arg); event_add (&conn->ev_read, NULL); timeout_add(&conn->ev_read, &conn->tv); evbuffer_read(conn->input, conn->sockfd, 256); } }
static void http_read_cb(evutil_socket_t fd, short events, void *arg) { int ret = 0; struct http_connection *hc = arg; if (events & EV_TIMEOUT) { printf("timeout on fd %d, hc %p\n", fd, hc); goto failed; } if (events & EV_READ) { ret = evbuffer_read(hc->evbin, fd, 4096); if (ret == -1 || ret == 0) { goto failed; } if (hc->connection_status == HTTP_CONNECTION_STATUS_READ_HEADER) { if (evbuffer_find(hc->evbin, (const unsigned char *)"\r\n\r\n", 4) == NULL && evbuffer_get_length(hc->evbin) < 4096) { // wait to read more data return; } else { //dbprintf("evbuffer_get_length: %d\n", evbuffer_get_length(hc->evbin)); } ret = http_parse_first_line(hc, hc->evbin); if (ret) { goto failed; } ret = http_parse_headers(hc, hc->evbin); if (ret) { goto failed; } /* set no-timeout read */ event_del(hc->ev_read); event_add(hc->ev_read, NULL); hc->connection_status = HTTP_CONNECTION_STATUS_READ_BODY; } else if (hc->connection_status == HTTP_CONNECTION_STATUS_READ_BODY) { } /* dispatch to handler */ ret = http_dispatch_uri_handler_cb(hc); if (ret) { goto failed; } } return; failed: http_connection_free(hc); }
static void client_readable(int fd, short event, void *arg) { int ret = evbuffer_read(in_buf, fd, 8192); if (ret < 0) { client_destroy(strerror(errno)); } else if (ret == 0) { client_destroy("eof reached"); } else { traffic += ret; client_parse_in_buf(); } }
static void bufferevent_readcb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; int res = 0; short what = OPAL_EVBUFFER_READ; size_t len; if (event == OPAL_EV_TIMEOUT) { what |= OPAL_EVBUFFER_TIMEOUT; goto error; } res = evbuffer_read(bufev->input, fd, -1); if (res == -1) { if (errno == EAGAIN || errno == EINTR) goto reschedule; /* error case */ what |= OPAL_EVBUFFER_ERROR; } else if (res == 0) { /* eof case */ what |= OPAL_EVBUFFER_EOF; } if (res <= 0) goto error; bufferevent_add(&bufev->ev_read, bufev->timeout_read); /* See if this callbacks meets the water marks */ len = OPAL_EVBUFFER_LENGTH(bufev->input); if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) return; if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) { struct evbuffer *buf = bufev->input; opal_event_del(&bufev->ev_read); /* Now schedule a callback for us */ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); return; } /* Invoke the user callback - must always be called last */ (*bufev->readcb)(bufev, bufev->cbarg); return; reschedule: bufferevent_add(&bufev->ev_read, bufev->timeout_read); return; error: (*bufev->errorcb)(bufev, what, bufev->cbarg); }
/** * 窥探缓冲区,但不清空 * 参考read函数 * 如果@buf为空,则返回缓冲区长度 */ int im_connection::peek(char* buf, int max_len) { int buflen = evbuffer_get_length(_in); if (buflen < max_len) { if (evbuffer_read(_in, _fd, max_len-buflen) < 0) { if (_ops->network_disconnected) _ops->network_disconnected(this); return -1; } } if (buf) return evbuffer_copyout(_in, buf, max_len); else return evbuffer_get_length(_in); }
static void server_readable(int fd, short event, void *arg) { client_t *client = (client_t*)arg; // Der Client wurde 'extern' gekickt, allerdings noch // nicht entfernt. Dann wird dieser Readcallback aufgerufen, // sollte allerdings nichts mehr machen. if (client->kill_me) return; int ret = evbuffer_read(client->in_buf, fd, 128); if (ret < 0) { server_destroy(client, strerror(errno)); } else if (ret == 0) { server_destroy(client, "eof reached"); } else if (EVBUFFER_LENGTH(client->in_buf) > 8192) { server_destroy(client, "line too long. go away."); } else { char *line; while ((line = evbuffer_readline(client->in_buf))) { lua_pushliteral(L, "on_client_input"); lua_rawget(L, LUA_GLOBALSINDEX); lua_pushnumber(L, client_num(client)); lua_pushstring(L, line); free(line); // Cycles fuer die Verarbeitung hochsetzen lua_set_cycles(L, 0xFFFFFF); // Input verarbeiten output_client = client; if (lua_pcall(L, 2, 0, 0) != 0) { fprintf(stderr, "error calling on_client_input: %s\n", lua_tostring(L, -1)); server_writeto(client, lua_tostring(L, -1), lua_strlen(L, -1)); lua_pop(L, 1); } output_client = NULL; // Kill Me Flag waehrend Aufruf von on_client_input // gesetzt? Direkt rausschmeissen! if (client->kill_me) { server_destroy(client, client->kill_me); return; } } } }
static void recv_data_cb (BlockTxClient *client) { int ret = 0; /* Let evbuffer determine how much data can be read. */ int n = evbuffer_read (client->recv_buf, client->data_fd, -1); if (n == 0) { seaf_warning ("Data connection is closed by the server.\n"); client->break_loop = TRUE; client->info->result = BLOCK_CLIENT_NET_ERROR; return; } else if (n < 0) { seaf_warning ("Read data connection error: %s.\n", evutil_socket_error_to_string(evutil_socket_geterror(client->data_fd))); client->break_loop = TRUE; client->info->result = BLOCK_CLIENT_NET_ERROR; return; } switch (client->recv_state) { case RECV_STATE_HANDSHAKE: ret = handle_handshake_response (client); break; case RECV_STATE_AUTH: ret = handle_auth_response (client); break; case RECV_STATE_HEADER: ret = handle_block_header (client); if (ret < 0) break; if (client->recv_state == RECV_STATE_CONTENT && client->info->task->type == TASK_TYPE_DOWNLOAD) ret = handle_block_content (client); break; case RECV_STATE_CONTENT: ret = handle_block_content (client); break; } if (ret < 0) client->break_loop = TRUE; }
static void recv_data_cb (BlockTxServer *server) { int ret = 0; /* Let evbuffer determine how much data can be read. */ int n = evbuffer_read (server->recv_buf, server->data_fd, -1); if (n == 0) { seaf_debug ("Data connection is closed by the client. Transfer done.\n"); server->break_loop = TRUE; return; } else if (n < 0) { seaf_warning ("Read data connection error: %s.\n", evutil_socket_error_to_string(evutil_socket_geterror(server->data_fd))); server->break_loop = TRUE; return; } switch (server->recv_state) { case RECV_STATE_HANDSHAKE: ret = handle_handshake_request (server); break; case RECV_STATE_AUTH: ret = handle_auth_request (server); break; case RECV_STATE_HEADER: ret = handle_block_header (server); if (ret < 0) break; if (server->recv_state == RECV_STATE_CONTENT && server->command == REQUEST_COMMAND_PUT) ret = handle_block_content (server); break; case RECV_STATE_CONTENT: ret = handle_block_content (server); break; } if (ret < 0) server->break_loop = TRUE; }
void httpserver_handler(struct evhttp_request *req, void *arg) { int fd=open("./test.html",O_RDONLY); const char *cmdtype; struct evbuffer *buf = evbuffer_new(); if (buf == NULL) { printf("evbuffer_new error !\n"); return; } switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: cmdtype = "GET"; break; case EVHTTP_REQ_POST: cmdtype = "POST"; break; case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break; case EVHTTP_REQ_PUT: cmdtype = "PUT"; break; case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break; case EVHTTP_REQ_OPTIONS:cmdtype = "OPTIONS";break; case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break; case EVHTTP_REQ_CONNECT:cmdtype = "CONNECT";break; case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break; default: cmdtype = "unknown"; break; } printf("%s url=%s \n", cmdtype, evhttp_request_get_uri(req)); //evbuffer_add_printf(buf,"<html>\n" // "<head>\n" // " <title>Libevnet Test</title>\n" // "</head>\n" // "<body>\n" // " <h1>Hello world ,This is a Libenvet Test !</h1>\n" // "</body>\n" // "</html>\n"); evbuffer_read(buf,fd,75); evhttp_send_reply(req, 200, "OK", buf); }
void echo_read(int fd, short revents, void *conn) { int i; // create buffer /* struct evbuffer * eBuff = evbuffer_new(); */ // recieve and echo the message to the user char ** data; struct conn * c = (struct conn *) conn; data = malloc(sizeof(char*) * 1024); for (i = 0; i < 1024; i++) { data[i] = malloc(sizeof(char) * 1024); } evbuffer_read(c->buf, fd, 1024); /* evbuffer_read(c->buf, fd, 1024); */ fprintf(stdout, "fd %d: %s\n", fd, (char *)c->buf->buffer); /* fflush(stdout); */ write(fd, "Message recieved\n", 18); /* evbuffer_write(c->evbuffer, fd); */ // free the buffer event_add(&c->wr_ev, NULL); }
int sp_in_event(int fd, short why, void *data) { sp_t *sp = data; int rc = evbuffer_read(sp->input, fd, 4096); if(rc == -1 || rc == 0 /* EOF */) { return -1; } while(1) { char *cmd = io_evbuffer_readline(sp->input); if(cmd == NULL) { break; } print_command(cmd, "<- (fd %d)", fd); sp_dispatch_command(cmd, "$", 1, sp); free(cmd); } return 0; }
void connection_client(int cfd, short event, void *arg) { struct client_state *cs = arg; int cmd, break_out = 0; int uid = 0, index = 0; // ignore clients that timeout if (event & EV_TIMEOUT) cs->state = FSM_EXIT; if (event & EV_READ) { if (cs->state != FSM_ENTER) { if (evbuffer_read(cs->evb, cfd, READ_BLOCK) <= 0) cs->state = FSM_EXIT; } else { if (evbuffer_read(cs->evb, cfd, 4) <= 0) cs->state = FSM_EXIT; } } while (!break_out) { switch (cs->state) { case FSM_ENTER: if (EVBUFFER_LENGTH(cs->evb) < sizeof(int)) { break_out = 1; break; } evbuffer_remove(cs->evb, &cmd, sizeof(cmd)); if (cmd == -1) cs->state = FSM_SYNC; else if (cmd == -2) { fcntl(cfd, F_SETFL, fcntl(cfd, F_GETFL, 0) | O_NONBLOCK); cs->state = FSM_LOGIN; } else if (cmd >= 0) cs->state = FSM_EXIT; else { printf("unknown cmd=%d\n",cmd); cs->state = FSM_EXIT; } break; case FSM_SYNC: syncutmp(cfd); firstsync = 1; cs->state = FSM_EXIT; break; case FSM_LOGIN: if (firstsync) { if (EVBUFFER_LENGTH(cs->evb) < (2 + MAX_FRIEND + MAX_REJECT) * sizeof(int)) { break_out = 1; break; } evbuffer_remove(cs->evb, &index, sizeof(index)); evbuffer_remove(cs->evb, &uid, sizeof(uid)); if (index >= USHM_SIZE || index < 0) { fprintf(stderr, "bad index=%d\n", index); cs->state = FSM_EXIT; break; } if (uid > MAX_USERS || uid <= 0) { fprintf(stderr, "bad uid=%d\n", uid); cs->state = FSM_EXIT; break; } count_login++; processlogin(cs, uid, index); if (count_login >= 4000 || (time(NULL) - begin_time) > 30*60) showstat(); cs->state = FSM_WRITEBACK; break_out = 1; } else cs->state = FSM_EXIT; break; case FSM_WRITEBACK: if (event & EV_WRITE) if (evbuffer_write(cs->evb, cfd) <= 0 && EVBUFFER_LENGTH(cs->evb) > 0) break_out = 1; if (EVBUFFER_LENGTH(cs->evb) == 0) cs->state = FSM_EXIT; break; case FSM_EXIT: if (clients == MAX_CLIENTS) event_add(&ev, NULL); close(cfd); evbuffer_free(cs->evb); free(cs); clients--; return; break; } } if (cs->state == FSM_WRITEBACK) event_set(&cs->ev, cfd, EV_WRITE, (void *) connection_client, cs); event_add(&cs->ev, &tv); }
/* Thread: httpd */ static void serve_file(struct evhttp_request *req, char *uri) { const char *host; char *ext; char path[PATH_MAX]; char *deref; char *ctype; char *passwd; struct evbuffer *evbuf; struct evkeyvalq *headers; struct stat sb; int fd; int i; int ret; /* Check authentication */ passwd = cfg_getstr(cfg_getsec(cfg, "general"), "admin_password"); if (passwd) { DPRINTF(E_DBG, L_HTTPD, "Checking web interface authentication\n"); ret = httpd_basic_auth(req, "admin", passwd, PACKAGE " web interface"); if (ret != 0) return; DPRINTF(E_DBG, L_HTTPD, "Authentication successful\n"); } else { host = evhttp_request_get_host(req); if ((strcmp(host, "::1") != 0) && (strcmp(host, "127.0.0.1") != 0)) { DPRINTF(E_LOG, L_HTTPD, "Remote web interface request denied; no password set\n"); evhttp_send_error(req, 403, "Forbidden"); return; } } ret = snprintf(path, sizeof(path), "%s%s", WEBFACE_ROOT, uri + 1); /* skip starting '/' */ if ((ret < 0) || (ret >= sizeof(path))) { DPRINTF(E_LOG, L_HTTPD, "Request exceeds PATH_MAX: %s\n", uri); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); return; } ret = lstat(path, &sb); if (ret < 0) { DPRINTF(E_LOG, L_HTTPD, "Could not lstat() %s: %s\n", path, strerror(errno)); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); return; } if (S_ISDIR(sb.st_mode)) { redirect_to_index(req, uri); return; } else if (S_ISLNK(sb.st_mode)) { deref = m_realpath(path); if (!deref) { DPRINTF(E_LOG, L_HTTPD, "Could not dereference %s: %s\n", path, strerror(errno)); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); return; } if (strlen(deref) + 1 > PATH_MAX) { DPRINTF(E_LOG, L_HTTPD, "Dereferenced path exceeds PATH_MAX: %s\n", path); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); free(deref); return; } strcpy(path, deref); free(deref); ret = stat(path, &sb); if (ret < 0) { DPRINTF(E_LOG, L_HTTPD, "Could not stat() %s: %s\n", path, strerror(errno)); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); return; } if (S_ISDIR(sb.st_mode)) { redirect_to_index(req, uri); return; } } if (path_is_legal(path) != 0) { evhttp_send_error(req, 403, "Forbidden"); return; } evbuf = evbuffer_new(); if (!evbuf) { DPRINTF(E_LOG, L_HTTPD, "Could not create evbuffer\n"); evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal error"); return; } fd = open(path, O_RDONLY); if (fd < 0) { DPRINTF(E_LOG, L_HTTPD, "Could not open %s: %s\n", path, strerror(errno)); evhttp_send_error(req, HTTP_NOTFOUND, "Not Found"); return; } /* FIXME: this is broken, if we ever need to serve files here, * this must be fixed. */ ret = evbuffer_read(evbuf, fd, sb.st_size); close(fd); if (ret < 0) { DPRINTF(E_LOG, L_HTTPD, "Could not read file into evbuffer\n"); evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal error"); return; } ctype = "application/octet-stream"; ext = strrchr(path, '.'); if (ext) { for (i = 0; ext2ctype[i].ext; i++) { if (strcmp(ext, ext2ctype[i].ext) == 0) { ctype = ext2ctype[i].ctype; break; } } } headers = evhttp_request_get_output_headers(req); evhttp_add_header(headers, "Content-Type", ctype); evhttp_send_reply(req, HTTP_OK, "OK", evbuf); evbuffer_free(evbuf); }
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); }
/* * zark: 当epoll层的读事件到来, 会从活跃队列中回调该函数, * 开始从socket中读取数据. */ static void bufferevent_readcb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; int res = 0; short what = EVBUFFER_READ; size_t len; int howmuch = -1; //! zark: bufferevent是对I/O操作的封装, 所以不监听超时事件. if (event == EV_TIMEOUT) { what |= EVBUFFER_TIMEOUT; goto error; } /* * If we have a high watermark configured then we don't want to * read more data than would make us reach the watermark. * * zark: 这里有必要普及一下libevent关于输入输出时的水位概念. * 读取低水位 - 读取操作使得输入缓冲区的数据量在此级别或者更高时, * 读取回调将被调用.默认值为0, 所以每个读取操作都会 * 导致读取回调被调用. * 读取高水位 - 输入缓冲区中的数据量达到此级别后,bufferevent将停 * 止读取,直到输入缓冲区中足够量的数据被抽取,使得数 * 据量低于此级别.默认值是无限, 所以永远不会因为输入 * 缓冲区的大小而停止读取. * 写入低水位 - 写入操作使得输出缓冲区的数据量达到或者低于此级别时, * 写入回调将被调用.默认值是0, 所以只有输出缓冲区空的 * 时候才会调用写入回调. * 写入高水位 - bufferevent没有直接使用这个水位. 它在bufferevent用 * 作另外一个bufferevent的底层传输端口时有特殊意义.请 * 看后面关于过滤型bufferevent的介绍. */ //! zark: 读取高水位到达, 停止读取. if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input); /* we might have lowered the watermark, stop reading */ if (howmuch <= 0) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); //! 删除当前读事件. /* * zark: 设置一个新的读事件, 该读事件的callback函 * 数(即bufferevent_read_pressure_cb)会检测 * 当输入冲区大小小于高水位时, 会再次添加正 * 常的读取event. */ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); return; } } /* * zark: 开始从fd读取数据到我们的输入缓冲区中. */ res = evbuffer_read(bufev->input, fd, howmuch); if (res == -1) { if (errno == EAGAIN || errno == EINTR) goto reschedule; /* error case */ what |= EVBUFFER_ERROR; } else if (res == 0) { /* eof case */ what |= EVBUFFER_EOF; } if (res <= 0) goto error; /* * zark: 因为bufferevent当初添加事件的时候没有使用 * persist来修饰event, 所以需要重新添加. */ bufferevent_add(&bufev->ev_read, bufev->timeout_read); /* See if this callbacks meets the water marks */ len = EVBUFFER_LENGTH(bufev->input); /* * zark: 读取低水位线没有达到, 所以不能调用callback, 直接return~ */ if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) return; /* * zark: 读取高水位到达, 停止读取. */ if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); /* Now schedule a callback for us when the buffer changes */ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); } /* Invoke the user callback - must always be called last */ /* * zark: 哈哈, 一顿乱七八糟的check下来, 终于到了调用我们 * 真正注册的读取回调函数拉~ 散花~ */ if (bufev->readcb != NULL) (*bufev->readcb)(bufev, bufev->cbarg); return; reschedule: bufferevent_add(&bufev->ev_read, bufev->timeout_read); return; /* * zark: 调用我们注册的错误处理回调函数. */ error: (*bufev->errorcb)(bufev, what, bufev->cbarg); }
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 bufferevent_readcb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; int res = 0; short what = EVBUFFER_READ; size_t len; int howmuch = -1; if (event == EV_TIMEOUT) { what |= EVBUFFER_TIMEOUT; goto error; } /* * 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_LENGTH(bufev->input); /* we might have lowered the watermark, stop reading */ if (howmuch <= 0) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); return; } } res = evbuffer_read(bufev->input, fd, howmuch); if (res == -1) { if (errno == EAGAIN || errno == EINTR) goto reschedule; /* error case */ what |= EVBUFFER_ERROR; } else if (res == 0) { /* eof case */ what |= EVBUFFER_EOF; } if (res <= 0) goto error; bufferevent_add(&bufev->ev_read, bufev->timeout_read); /* See if this callbacks meets the water marks */ len = EVBUFFER_LENGTH(bufev->input); if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) return; if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); /* Now schedule a callback for us when the buffer changes */ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); } /* Invoke the user callback - must always be called last */ if (bufev->readcb != NULL) (*bufev->readcb)(bufev, bufev->cbarg); return; reschedule: bufferevent_add(&bufev->ev_read, bufev->timeout_read); return; error: (*bufev->errorcb)(bufev, what, bufev->cbarg); }
void shard_connection::handle_event(short evtype) { // connect() returning to us? normally we expect EV_WRITE, but for UNIX domain // sockets we workaround since connect() returned immediately, but we don't want // to do any I/O from the client::connect() call... if (!m_connected && (evtype == EV_WRITE || m_unix_sockaddr != NULL)) { int error = -1; socklen_t errsz = sizeof(error); if (getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, (void *) &error, &errsz) == -1) { benchmark_error_log("connect: error getting connect response (getsockopt): %s\n", strerror(errno)); return; } if (error != 0) { benchmark_error_log("connect: connection failed: %s\n", strerror(error)); return; } m_connected = true; if (!m_conns_manager->get_reqs_processed()) { process_first_request(); } else { benchmark_debug_log("reconnection complete, proceeding with test\n"); fill_pipeline(); } } assert(m_connected == true); if ((evtype & EV_WRITE) == EV_WRITE && evbuffer_get_length(m_write_buf) > 0) { if (evbuffer_write(m_write_buf, m_sockfd) < 0) { if (errno != EWOULDBLOCK) { benchmark_error_log("write error: %s\n", strerror(errno)); disconnect(); return; } } } if ((evtype & EV_READ) == EV_READ) { int ret = 1; while (ret > 0) { ret = evbuffer_read(m_read_buf, m_sockfd, -1); } if (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { benchmark_error_log("read error: %s\n", strerror(errno)); disconnect(); return; } if (ret == 0) { benchmark_error_log("connection dropped.\n"); disconnect(); return; } if (evbuffer_get_length(m_read_buf) > 0) { process_response(); // process_response may have disconnected, in which case // we just abort and wait for libevent to call us back sometime if (!m_connected) { return; } } } // update event short new_evtype = 0; if (m_pending_resp) { new_evtype = EV_READ; } if (evbuffer_get_length(m_write_buf) > 0) { assert(!m_conns_manager->finished()); new_evtype |= EV_WRITE; } if (new_evtype) { int ret = event_assign(m_event, m_event_base, m_sockfd, new_evtype, cluster_client_event_handler, (void *)this); assert(ret == 0); ret = event_add(m_event, NULL); assert(ret == 0); } else if (m_conns_manager->finished()) { m_conns_manager->set_end_time(); } }
static void event_read_cb( int fd, short event UNUSED, void * vio ) { int res; int e; tr_peerIo * io = vio; /* Limit the input buffer to 256K, so it doesn't grow too large */ unsigned int howmuch; unsigned int curlen; const tr_direction dir = TR_DOWN; const unsigned int max = 256 * 1024; assert( tr_isPeerIo( io ) ); io->hasFinishedConnecting = TRUE; io->pendingEvents &= ~EV_READ; curlen = EVBUFFER_LENGTH( io->inbuf ); howmuch = curlen >= max ? 0 : max - curlen; howmuch = tr_bandwidthClamp( &io->bandwidth, TR_DOWN, howmuch ); dbgmsg( io, "libevent says this peer is ready to read" ); /* if we don't have any bandwidth left, stop reading */ if( howmuch < 1 ) { tr_peerIoSetEnabled( io, dir, FALSE ); return; } EVUTIL_SET_SOCKET_ERROR( 0 ); res = evbuffer_read( io->inbuf, fd, (int)howmuch ); e = EVUTIL_SOCKET_ERROR( ); if( res > 0 ) { tr_peerIoSetEnabled( io, dir, TRUE ); /* Invoke the user callback - must always be called last */ canReadWrapper( io ); } else { char errstr[512]; short what = EVBUFFER_READ; if( res == 0 ) /* EOF */ what |= EVBUFFER_EOF; else if( res == -1 ) { if( e == EAGAIN || e == EINTR ) { tr_peerIoSetEnabled( io, dir, TRUE ); return; } what |= EVBUFFER_ERROR; } tr_net_strerror( errstr, sizeof( errstr ), e ); dbgmsg( io, "event_read_cb got an error. res is %d, what is %hd, errno is %d (%s)", res, what, e, errstr ); if( io->gotError != NULL ) io->gotError( io, what, io->userData ); } }
static void echo_read_cb(struct bufferevent *bev, void *ctx) { printf("echo_read_cb ctx:%p\n", ctx); /* This callback is invoked when there is data to read on bev. */ struct evbuffer *input = bufferevent_get_input(bev); /* Copy all the data from the input buffer to the output buffer. */ // evbuffer_add_buffer(output, input); // 能读到数据的时候 去连接其他server 而且是以阻塞的方式 printf("echo_read_cb1 \n"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); //servaddr.sin_family = AF_INET; ////servaddr.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ //if (inet_aton("192.168.1.104", &servaddr.sin_addr) == 0) //{ // perror("inet_aton failure!"); // printf("address:%u\n", servaddr.sin_addr.s_addr); // exit(EXIT_FAILURE); //} //servaddr.sin_port = htons(5188); /* Port 9876*/ // TODO 错误判断 char buff[64]; evutil_snprintf(buff, sizeof(buff), "%s:%d", "192.168.1.104", 5188); int servadd_len = sizeof(servaddr); //int retx = evutil_parse_sockaddr_port("192.168.1.104:5188", (struct sockaddr*)&servaddr, &servadd_len); int retx = evutil_parse_sockaddr_port(buff, (struct sockaddr*)&servaddr, &servadd_len); printf("address:%s\n", buff); if (retx < 0) { printf("address:error\n"); } else { printf("address:%u\n", servaddr.sin_addr.s_addr); } int sockconn; errno = 0; if ((sockconn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("socket failure"); exit(EXIT_FAILURE); } //evutil_make_socket_nonblocking(sockconn); struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; setsockopt(sockconn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(sockconn, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); // bufferevent_socket_new 只是分配内存 没有系统调用 struct bufferevent *bev1 = bufferevent_socket_new(ctx, sockconn, BEV_OPT_CLOSE_ON_FREE); //bufferevent_settimeout(bev1, 10, 10); //bev1 = bufferevent_socket_new(ctx, -1, BEV_OPT_CLOSE_ON_FREE); bufferevent_enable(bev1, EV_READ|EV_WRITE); bufferevent_setcb(bev1, NULL, NULL, eventcb, "hello"); //SetSocketBlockingEnabled(sockconn, 1); // 这里默认是阻塞的,会一直阻塞 直到连接成功 或超时 // // if (bufferevent_socket_connect(bev1, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { /* Error starting connection */ // 连接不能马上建立的时候 应该添加到写事件中 fprintf(stderr, "Connect failed.\n"); perror("connect..........."); //#define ETIMEDOUT 110 /* Connection timed out */ // 无条件超时 非自定义超时 走这里// //bufferevent_free(bev1); // 此时错误码是 BEV_EVENT_ERROR 在那里销毁 BEV_EVENT_ERROR //return -1; // 110错误码走到这里 11, 115错误码 不会走到这里 } printf("bufferevent_socket_connect return errno:%d \n", errno); ////#define EAGAIN 11 /* Try again */ ////#define ECONNREFUSED 111 /* Connection refused */ ////#define EINPROGRESS 115 /* Operation now in progress */ // connect 被超时打断11, // //if (errno != EAGAIN ) if (errno == EINPROGRESS) // 自定义 超时中断 { perror("self timeout............."); bufferevent_free(bev1); return; } else if (errno != 0) { perror("00buffevent_connect"); printf("bufferevent_socket_connect error\n"); //如果 在过程中 超时会被 打断 EINPROGRESS 115 /* Operation now in progress */ // 除了自定义超时timeout不宜在这里销毁 在 回调函数中销毁 不然调用不到回调函数// //bufferevent_free(bev1); return ; } else { // 连接成功 perror("11buffevent_connect"); printf("bufferevent_socket_connect success\n"); } //if (connect(sockconn, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) //{ // perror("connnect error"); // exit(EXIT_FAILURE); //} //else //{ // printf("connect success\n"); //} //char recvbuf[1024] = {0}; //memset(recvbuf, 0, sizeof(recvbuf)); //sleep(5); //read(sockconn, recvbuf, sizeof(recvbuf)); //printf("----%s-----\n", recvbuf); // struct evbuffer *input1 = bufferevent_get_input(bev1); // printf("before read ---------\n"); // bufferevent_read_buffer(bev1, input1); // size_t len = evbuffer_get_length(input1); // unsigned char * recvbuf = evbuffer_pullup(input1, len); // printf("end read len:%ld---------\n", len); // printf("----%s-----\n", recvbuf); //struct evbuffer * buffer = evbuffer_new(); struct evbuffer *buffer = bufferevent_get_input(bev1); struct evbuffer *buffero = bufferevent_get_output(bev1); evutil_socket_t fd = bufferevent_getfd(bev1); time_t rawtime; time ( &rawtime ); printf("before read ---------%ld\n", rawtime); int ret = evbuffer_read(buffer, fd, 1024); // not work // bufferevent_read_buffer(bev1, buffer); size_t len = evbuffer_get_length(buffer); time ( &rawtime ); printf("end readlen ---------%ld\n", len); unsigned char * recvbuf = evbuffer_pullup(buffer, len); printf("end read ---------%ld\n", rawtime); printf("----%s-----\n", recvbuf); evbuffer_drain(buffer, len); // int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd); time ( &rawtime ); printf("before write---------%ld\n", rawtime); sleep(10); time ( &rawtime ); printf("before write1---------%ld\n", rawtime); evbuffer_add(buffero, "hello,china", 12); ret = evbuffer_write(buffero, fd); // ret =write(fd, "hello,china", 12); if (ret < 0) { if (errno != 0) { perror("write "); } } time ( &rawtime ); printf("end write1 ---------%ld\n", rawtime); // 出现read 在connect 之前// //root@debian:~/programming/libevent/libevent2/libevent/sample/study-buffevent_block# ./echoserver_block // create listener success, base:0xfdbc40 // echo_read_cb ctx:0xfdbc40 // echo_read_cb1 // bufferevent_socket_connect return errno:11 // 11buffevent_connect: Resource temporarily unavailable // bufferevent_socket_connect success // ----hello,world----- // Connect okay,-------------------------- hello. // disConnect --------------------------. }
static void bufferevent_readcb(int fd, short event, void *arg) { struct bufferevent *bufev = arg; int res = 0; short what = EVBUFFER_READ; size_t len; int howmuch = -1; if (event == EV_TIMEOUT) { what |= EVBUFFER_TIMEOUT; goto error; } if (bufev->wm_read.high != 0) { howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input); if (howmuch <= 0) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); return; } } res = evbuffer_read(bufev->input, fd, howmuch); if (res == -1) { if (errno == EAGAIN || errno == EINTR) goto reschedule; what |= EVBUFFER_ERROR; } else if (res == 0) { what |= EVBUFFER_EOF; } if (res <= 0) goto error; bufferevent_add(&bufev->ev_read, bufev->timeout_read); len = EVBUFFER_LENGTH(bufev->input); if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) return; if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) { struct evbuffer *buf = bufev->input; event_del(&bufev->ev_read); evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); } if (bufev->readcb != NULL) (*bufev->readcb)(bufev, bufev->cbarg); return; reschedule: bufferevent_add(&bufev->ev_read, bufev->timeout_read); return; error: (*bufev->errorcb)(bufev, what, bufev->cbarg); }
/* * Reads data from a file descriptor into conn->input_buffer, parse and place the headers into conn->input_headers */ int mhf_read_buffer(CONN *conn) { int n, len,ret; enum parse_result res; struct evbuffer *input_buffer = conn->input_buffer; int fd = conn->fd; conn->state = HTTP_STATE_READING_FIRSTLINE; while(1) { ret = mhf_select(fd, HTTP_TIMEOUT); if (ret < 0) { fprintf(stderr,"%s %d %s select error \n",__func__,errno,strerror(errno)); return(-2); } else if (ret == 0) { fprintf(stderr,"%s timeout \n",__func__); return(-1); } n = evbuffer_read(input_buffer, fd, -1); if (n == -1) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { fprintf(stderr,"%s %d(EINTR||EAGAIN|EWOULDBLOCK) %s\n",__func__,errno,strerror(errno)); continue; } else { fprintf(stderr,"%s %d(other error) %s\n",__func__,errno,strerror(errno)); return(-2); } } else if (n == 0) { #ifdef DEBUG fprintf(stderr,"%s connection closed \n",__func__); #endif return(-3); } while(1) { switch (conn->state) { case HTTP_STATE_READING_FIRSTLINE: res = mhf_read_firstline(conn); break; case HTTP_STATE_READING_HEADERS: res = mhf_read_header(conn); break; case HTTP_STATE_READING_BODY: break; case HTTP_STATE_END: return (0); case HTTP_STATE_END_WITH_ERR: #ifdef DEBUG fprintf(stderr,"%s %d HTTP protocol error \n",__func__,res); #endif return(-1); default: fprintf(stderr,"unsupported http state\n",__func__,res); exit(1); } if (res == MORE_DATA_EXPECTED) break; } } }