static int send_handshake (evutil_socket_t data_fd, BlockTxInfo *info) { HandshakeRequest *req; if (sendn (data_fd, BLOCK_PROTOCOL_SIGNATURE, 37) < 0) { seaf_warning ("Failed to send protocol signature: %s.\n", evutil_socket_error_to_string(evutil_socket_geterror(data_fd))); info->result = BLOCK_CLIENT_NET_ERROR; return -1; } int req_size = sizeof(HandshakeRequest) + info->enc_key_len; req = (HandshakeRequest *) g_malloc (req_size); req->version = htonl(BLOCK_PROTOCOL_VERSION); req->key_len = htonl(info->enc_key_len); memcpy (req->enc_session_key, info->enc_session_key, info->enc_key_len); if (sendn (data_fd, req, req_size) < 0) { seaf_warning ("Failed to send handshake: %s.\n", evutil_socket_error_to_string(evutil_socket_geterror(data_fd))); info->result = BLOCK_CLIENT_NET_ERROR; g_free (req); return -1; } g_free (req); return 0; }
/** * ################################################ * * Fun: * * Author: * * Date: Tue Dec 9 14:52:54 CST 2014 * * Purpose: * * * Params: * * Return: * * ################################################### */ void event_cb(struct bufferevent *bev,short events, void *ctx) { vLogErr(" the most recent error [%d] [%s]", EVUTIL_SOCKET_ERROR(), evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); vLogErr("fd error is [%d] and error string [%s]", evutil_socket_geterror(bufferevent_getfd(bev)), evutil_socket_error_to_string(evutil_socket_geterror(bufferevent_getfd(bev)))); if(events & BEV_EVENT_CONNECTED) { vLogErr("connected!\n"); } else { if(events & BEV_EVENT_READING ) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); vLogErr("reading error!\n"); } if(events & BEV_EVENT_WRITING) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); vLogErr("writing error!\n"); } if((events & BEV_EVENT_READING) && (events & BEV_EVENT_TIMEOUT)) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); vLogErr("reading timeout error!\n"); } if((events & BEV_EVENT_WRITING) && (events & BEV_EVENT_TIMEOUT)) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); vLogErr("writing timeout error!\n"); } if(events & BEV_EVENT_EOF) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); vLogErr("eof file!\n"); } if(events & BEV_EVENT_ERROR) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); } if((events & BEV_EVENT_ERROR) && (events & BEV_EVENT_TIMEOUT)) { vLogErr("error [%d] [%s]!",events,evutil_socket_error_to_string(events)); vLogErr("timeout error!\n"); } bufferevent_free(bev); } }
static void bufferevent_readcb(int32_t fd, short event, void *arg) { struct bufferevent_common *bufev = arg; struct evbuffer *input; int res = 0; int len = 0; short what = BEV_EVENT_READING; struct evbuffer_common *pInput = bufev->input; 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; } len = read(fd, pInput->data, 16384-pInput->len); pInput->data.len += len; if(pInput->data.len >= 4) { bev->len = *((int32_t *)(pInput->data)); } if (len == -1) { int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) goto reschedule; /* error case */ what |= BEV_EVENT_ERROR; } else if (len == 0) { /* eof case */ what |= BEV_EVENT_EOF; } goto done: error: if (event & EV_READ) { event_del(&bufev->ev_read); } bufev->errorcb(bufev, what); done: } int32_t BUFFER_add(BUFFER *buffer, void *data, uint32_t len) { uint32_t end = buffer->index + buffer->len; if(!buffer || len+buffer->len > buffer->capacity) return -1; if(end+len > buffer->capacity) { memcpy(buffer->data+end, data, capacity-end); memcpy(buffer->data, data+(capacity-end), end+len-buffer->capacity); } else { memcpy(buffer->data+end, data, len); } buffer->len += len; return 0; }
static void listener_read_cb(evutil_socket_t fd, short what, void *p) { struct evconnlistener *lev = (struct evconnlistener *)p; int err; evconnlistener_cb cb; evconnlistener_errorcb errorcb; void *user_data; LOCK(lev); while (1) { struct sockaddr_storage ss; ev_socklen_t socklen = sizeof(ss); evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags); if (new_fd < 0) break; if (socklen == 0) { /* This can happen with some older linux kernels in * response to nmap. */ evutil_closesocket(new_fd); continue; } if (lev->cb == NULL) { evutil_closesocket(new_fd); UNLOCK(lev); return; } ++lev->refcnt; cb = lev->cb; user_data = lev->user_data; UNLOCK(lev); cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen, user_data); LOCK(lev); if (lev->refcnt == 1) { int freed = listener_decref_and_unlock(lev); EVUTIL_ASSERT(freed); return; } --lev->refcnt; } err = evutil_socket_geterror(fd); if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) { UNLOCK(lev); return; } if (lev->errorcb != NULL) { ++lev->refcnt; errorcb = lev->errorcb; user_data = lev->user_data; UNLOCK(lev); errorcb(lev, user_data); LOCK(lev); listener_decref_and_unlock(lev); } else { event_sock_warn(fd, "Error from accept() call"); } }
static void listener_read_cb(evutil_socket_t fd, short what, void *p) { struct evconnlistener *lev = p; int err; evconnlistener_cb cb; evconnlistener_errorcb errorcb; void *user_data; LOCK(lev); while (1) { struct sockaddr_storage ss; #ifdef WIN32 int socklen = sizeof(ss); #else socklen_t socklen = sizeof(ss); #endif evutil_socket_t new_fd = accept(fd, (struct sockaddr*)&ss, &socklen); if (new_fd < 0) break; if (!(lev->flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING)) evutil_make_socket_nonblocking(new_fd); if (lev->cb == NULL) { UNLOCK(lev); return; } ++lev->refcnt; cb = lev->cb; user_data = lev->user_data; UNLOCK(lev); cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen, user_data); LOCK(lev); if (lev->refcnt == 1) { int freed = listener_decref_and_unlock(lev); EVUTIL_ASSERT(freed); return; } --lev->refcnt; } err = evutil_socket_geterror(fd); if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) { UNLOCK(lev); return; } if (lev->errorcb != NULL) { ++lev->refcnt; errorcb = lev->errorcb; user_data = lev->user_data; UNLOCK(lev); errorcb(lev, user_data); LOCK(lev); listener_decref_and_unlock(lev); } else { event_sock_warn(fd, "Error from accept() call"); } }
static evutil_socket_t connect_chunk_server (ChunkServer *cs) { struct sockaddr_in sa; ev_socklen_t sa_len; evutil_socket_t data_fd; ev_socklen_t optlen; if (dns_lookup (cs->addr, &sa, &sa_len) < 0) { return -1; } sa.sin_family = AF_INET; sa.sin_port = htons(cs->port); data_fd = socket (AF_INET, SOCK_STREAM, 0); if (data_fd < 0) { seaf_warning ("socket error: %s.\n", strerror(errno)); return -1; } #ifdef WIN32 /* Set large enough TCP buffer size. * This greatly enhances sync speed for high latency network. * Windows by default use 8KB buffers, which is too small for such case. * Linux has auto-tuning for TCP buffers, so don't need to set manually. * OSX is TBD. */ #define DEFAULT_SNDBUF_SIZE (1 << 16) /* 64KB */ /* Set send buffer size. */ int sndbuf_size; optlen = sizeof(int); getsockopt (data_fd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf_size, &optlen); if (sndbuf_size < DEFAULT_SNDBUF_SIZE) { sndbuf_size = DEFAULT_SNDBUF_SIZE; optlen = sizeof(int); setsockopt (data_fd, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf_size, optlen); } #endif /* Disable Nagle's algorithm. */ int val = 1; optlen = sizeof(int); setsockopt (data_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, optlen); if (connect (data_fd, (struct sockaddr *)&sa, sa_len) < 0) { seaf_warning ("connect error: %s.\n", evutil_socket_error_to_string(evutil_socket_geterror(data_fd))); evutil_closesocket (data_fd); return -1; } return data_fd; }
void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) { va_list ap; int err = evutil_socket_geterror(sock); va_start(ap, fmt); _warn_helper(_EVENT_LOG_WARN, evutil_socket_error_to_string(err), fmt, ap); va_end(ap); }
void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) { va_list ap; int err = evutil_socket_geterror(sock); va_start(ap, fmt); warn_helper_(EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap); va_end(ap); event_exit(eval); }
void do_read(evutil_socket_t fd, short events, void *arg) { struct fd_state *state = arg; char buf[1024]; int i; ev_ssize_t result; printf("do_read(): fd = %d\r\n", fd); while (1) { assert(state->write_event); result = recv(fd, buf, sizeof(buf), 0); printf("recv(): result = %d\r\n", result); if (result <= 0) break; for (i=0; i < result; ++i) { if (state->buffer_used < sizeof(state->buffer)) state->buffer[state->buffer_used++] = rot13_char(buf[i]); if (buf[i] == '\n') { //assert(state->write_event); //event_add(state->write_event, NULL); state->write_upto = state->buffer_used; buf[state->buffer_used] = '\0'; printf("\r\n"); printf("bufsize = %d, buf = %s\r\n", state->buffer_used, buf); } } } if (result == 0) { free_fd_state(state); } else if (result < 0) { //if (errno == EAGAIN) // XXXX use evutil macro // return; int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) { // WSAEWOULDBLOCK or WSAEINTR printf("event_del(state->read_event);\r\n"); event_del(state->read_event); return; } else { perror("recv"); free_fd_state(state); } } }
static int send_handshake_response (BlockTxServer *server, int status) { HandshakeResponse rsp; rsp.status = htonl (status); rsp.version = htonl (BLOCK_PROTOCOL_VERSION); if (sendn (server->data_fd, &rsp, sizeof(rsp)) < 0) { seaf_warning ("Failed to send handshake response: %s.\n", evutil_socket_error_to_string(evutil_socket_geterror(server->data_fd))); return -1; } return 0; }
void CBareConnection::conn_event(bufferevent* bev, short event, void* ctx) { assert(bev != nullptr); assert(ctx != nullptr); CBareConnection* data = static_cast<CBareConnection*>(ctx); if ((event & BEV_EVENT_CONNECTED) != 0) data->OnConnectSuccess(std::move(data->m_bev)); else { evutil_socket_t sock = bufferevent_getfd(bev); (void)sock; // sock may be BAD_SOCKET here if it wasn't successfully created. int error = evutil_socket_geterror(sock); data->m_bev.free(); data->OnConnectFailure(event, error); } }
void do_write(evutil_socket_t fd, short events, void *arg) { struct fd_state *state = arg; char buf[512]; int n_written = 0, write_upto = sizeof(buf); int buffer_used = 0; printf("do_write(): fd = %d\r\n", fd); memset(buf, 0, write_upto); strcpy(buf, "Hello World!\r\n"); printf("\r\n"); printf("bufsize = %d, buf = %s\r\n", state->buffer_used, buf); write_upto = strlen(buf); while (n_written < write_upto) { ev_ssize_t result = send(fd, buf + n_written, write_upto - n_written, 0); printf("send(): result = %d\r\n", result); if (result < 0) { //if (errno == EAGAIN) // XXX use evutil macro // return; int err = evutil_socket_geterror(fd); if (EVUTIL_ERR_RW_RETRIABLE(err)) { // WSAEWOULDBLOCK or WSAEINTR break; } else { printf("event_del(state->write_event);\r\n"); event_del(state->write_event); return; } } assert(result != 0); n_written += result; } if (n_written == buffer_used) n_written = write_upto = buffer_used = 1; printf("event_del(state->write_event);\r\n"); event_del(state->write_event); }
static int launch_request(void) { evutil_socket_t sock; struct sockaddr_in sin; struct bufferevent *b; struct request_info *ri; memset(&sin, 0, sizeof(sin)); ++total_n_launched; sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(0x7f000001); sin.sin_port = htons(8080); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; if (evutil_make_socket_nonblocking(sock) < 0) { evutil_closesocket(sock); return -1; } frob_socket(sock); if (connect(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) { int e = evutil_socket_geterror(sock); if (! EVUTIL_ERR_CONNECT_RETRIABLE(e)) { evutil_closesocket(sock); return -1; } } ri = malloc(sizeof(*ri)); ri->n_read = 0; evutil_gettimeofday(&ri->started, NULL); b = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(b, readcb, NULL, errorcb, ri); bufferevent_enable(b, EV_READ|EV_WRITE); evbuffer_add_printf(bufferevent_get_output(b), "GET %s HTTP/1.0\r\n\r\n", resource); return 0; }
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; }
ssize_t ec_net_pullup(evutil_socket_t sd, uint8_t *b, size_t b_sz, int *flags, struct sockaddr *peer, socklen_t *peer_len, int *e) { ssize_t n; struct msghdr msg; struct iovec iov[1]; dbg_return_if (sd == -1, -1); dbg_return_if (b == NULL, -1); dbg_return_if (e == NULL, -1); dbg_return_if (flags == NULL, -1); /* b_sz==0 allowed here ? */ memset(&msg, sizeof msg, 0); msg.msg_name = peer; msg.msg_namelen = *peer_len; iov[0].iov_base = b; iov[0].iov_len = b_sz; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; *e = 0; if ((n = recvmsg(sd, &msg, *flags)) < 0) { if ((*e = evutil_socket_geterror(sd)) != EAGAIN) u_dbg("%s", evutil_socket_error_to_string(*e)); goto err; } *flags = msg.msg_flags; /* TODO retrieve cmsg with type IP_RECVDSTADDR to tell datagrams that where sent to a multicast destination. */ return n; err: return -1; }
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; }
/* Callback for when the signal handler write a byte to our signaling socket */ static void evsig_cb(evutil_socket_t fd, short what, void *arg) { static char signals[1024]; ev_ssize_t n; int i; int ncaught[NSIG]; struct event_base *base; base = arg; memset(&ncaught, 0, sizeof(ncaught)); while (1) { #ifdef _WIN32 n = recv(fd, signals, sizeof(signals), 0); #else n = read(fd, signals, sizeof(signals)); #endif if (n == -1) { int err = evutil_socket_geterror(fd); if (! EVUTIL_ERR_RW_RETRIABLE(err)) event_sock_err(1, fd, "%s: recv", __func__); break; } else if (n == 0) { /* XXX warn? */ break; } for (i = 0; i < n; ++i) { ev_uint8_t sig = signals[i]; if (sig < NSIG) ncaught[sig]++; } } EVBASE_ACQUIRE_LOCK(base, th_base_lock); for (i = 0; i < NSIG; ++i) { if (ncaught[i]) evmap_signal_active_(base, i, ncaught[i]); } EVBASE_RELEASE_LOCK(base, th_base_lock); }
void Listener::read_cb(evutil_socket_t fd, short what){ //TODO:locker //LOCK(lev); while (true) { struct sockaddr_storage ss; #ifdef WIN32 int socklen = sizeof(ss); #else socklen_t socklen = sizeof(ss); #endif evutil_socket_t new_fd = accept(fd, (struct sockaddr*)&ss, &socklen); if (!isSocketValid(new_fd)) break; if (!(this->flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING)) evutil_make_socket_nonblocking(new_fd); ++this->refcnt; //TODO //UNLOCK(lev); this->on_new_conn_accepted(new_fd,(struct sockaddr*)&ss, (int)socklen); //LOCK(lev); if (this->refcnt == 1) { MYASSERT(this->decref_and_unlock()); return; } else --this->refcnt; } int err = evutil_socket_geterror(fd); if (!MY_ERR_ACCEPT_RETRIABLE(err)) { ++this->refcnt; //UNLOCK(lev); this->on_fatal_error(); //LOCK(lev); this->decref_and_unlock(); } //TODO //UNLOCK(lev); }
/* Callback for when the signal handler write a byte to our signaling socket */ static void evsig_cb(evutil_socket_t fd, short what, void *arg) { static char signals[1024];//用来存放信号处理函数传过来的的信号? ev_ssize_t n; int i; int ncaught[NSIG];//NSIG在哪定义? struct event_base *base; base = arg; memset(&ncaught, 0, sizeof(ncaught)); while (1) { n = recv(fd, signals, sizeof(signals), 0); if (n == -1) { int err = evutil_socket_geterror(fd);//windows平台这是函数,而linux平台这是宏函数 if (! EVUTIL_ERR_RW_RETRIABLE(err)) //判断是否可重读写,即检查EINTR和EAGAIN event_sock_err(1, fd, "%s: recv", __func__); break; } else if (n == 0) { /* XXX warn? */ break; } for (i = 0; i < n; ++i) { ev_uint8_t sig = signals[i]; if (sig < NSIG) ncaught[sig]++;//记录传进来的信号 } } EVBASE_ACQUIRE_LOCK(base, th_base_lock);//base虽然是在本函数中定义的,貌似在栈上,但是他指向的地址是从外部传过来的,所以需要加锁 for (i = 0; i < NSIG; ++i) { if (ncaught[i]) evmap_signal_active(base, i, ncaught[i]);//激活base中等待的信号 } EVBASE_RELEASE_LOCK(base, th_base_lock); }
static void listener_read_cb(evutil_socket_t fd, short what, void *p) { struct evconnlistener *lev = p; int err; while (1) { struct sockaddr_storage ss; socklen_t socklen = sizeof(ss); evutil_socket_t new_fd = accept(fd, (struct sockaddr*)&ss, &socklen); if (new_fd < 0) break; if (!(lev->flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING)) evutil_make_socket_nonblocking(new_fd); lev->cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen, lev->user_data); } err = evutil_socket_geterror(fd); if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) return; event_sock_warn(fd, "Error from accept() call"); }
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); }
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); }
const char * socket_error_string(evutil_socket_t s) { return evutil_socket_error_to_string(evutil_socket_geterror(s)); }
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); }
static int64_t HHVM_STATIC_METHOD(EventUtil, getLastSocketErrno, const Resource &socket){ if(socket.isNull()){ return EVUTIL_SOCKET_ERROR(); } return evutil_socket_geterror(resource_to_fd(socket.asCResRef())); }
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); }
static String HHVM_STATIC_METHOD(EventUtil, getLastSocketError, const Resource &socket){ if(socket.isNull()){ return StringData::Make(evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); } return StringData::Make(evutil_socket_geterror(resource_to_fd(socket.asCResRef()))); }