void evbuffer_commit_read(struct evbuffer *evbuf, ev_ssize_t nBytes) { struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf); struct evbuffer_iovec iov[2]; int n_vec; EVBUFFER_LOCK(evbuf); EVUTIL_ASSERT(buf->read_in_progress && !buf->write_in_progress); EVUTIL_ASSERT(nBytes >= 0); /* XXXX Can this be false? */ evbuffer_unfreeze(evbuf, 0); iov[0].iov_base = buf->buffers[0].buf; if ((size_t)nBytes <= buf->buffers[0].len) { iov[0].iov_len = nBytes; n_vec = 1; } else { iov[0].iov_len = buf->buffers[0].len; iov[1].iov_base = buf->buffers[1].buf; iov[1].iov_len = nBytes - iov[0].iov_len; n_vec = 2; } if (evbuffer_commit_space(evbuf, iov, n_vec) < 0) EVUTIL_ASSERT(0); /* XXXX fail nicer. */ pin_release(buf, EVBUFFER_MEM_PINNED_R); buf->read_in_progress = 0; _evbuffer_decref_and_unlock(evbuf); }
void evbuffer_commit_write_(struct evbuffer *evbuf, ev_ssize_t nBytes) { struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf); EVUTIL_ASSERT(buf->write_in_progress && !buf->read_in_progress); evbuffer_unfreeze(evbuf, 1); evbuffer_drain(evbuf, nBytes); pin_release(buf,EVBUFFER_MEM_PINNED_W); buf->write_in_progress = 0; evbuffer_decref(evbuf); }
void evbuffer_commit_read(struct evbuffer *evbuf, ev_ssize_t nBytes) { struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf); struct evbuffer_chain **chainp; size_t remaining, len; unsigned i; EVBUFFER_LOCK(evbuf); EVUTIL_ASSERT(buf->read_in_progress && !buf->write_in_progress); EVUTIL_ASSERT(nBytes >= 0); /* XXXX Can this be false? */ evbuffer_unfreeze(evbuf, 0); chainp = evbuf->last_with_datap; if (!((*chainp)->flags & EVBUFFER_MEM_PINNED_R)) chainp = &(*chainp)->next; remaining = nBytes; for (i = 0; remaining > 0 && i < (unsigned)buf->n_buffers; ++i) { EVUTIL_ASSERT(*chainp); len = buf->buffers[i].len; if (remaining < len) len = remaining; (*chainp)->off += len; evbuf->last_with_datap = chainp; remaining -= len; chainp = &(*chainp)->next; } pin_release(buf, EVBUFFER_MEM_PINNED_R); buf->read_in_progress = 0; evbuf->total_len += nBytes; evbuf->n_add_for_cb += nBytes; evbuffer_invoke_callbacks(evbuf); _evbuffer_decref_and_unlock(evbuf); }
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 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); }
int evbuffer_launch_read(struct evbuffer *buf, size_t at_most, struct event_overlapped *ol) { struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); int r = -1, i; int nvecs; int npin=0; struct evbuffer_chain *chain=NULL, **chainp; DWORD bytesRead; DWORD flags = 0; struct evbuffer_iovec vecs[MAX_WSABUFS]; if (!buf_o) return -1; EVBUFFER_LOCK(buf); EVUTIL_ASSERT(!buf_o->write_in_progress); if (buf->freeze_end || buf_o->read_in_progress) goto done; buf_o->first_pinned = NULL; buf_o->n_buffers = 0; memset(buf_o->buffers, 0, sizeof(buf_o->buffers)); if (_evbuffer_expand_fast(buf, at_most, MAX_WSABUFS) == -1) goto done; evbuffer_freeze(buf, 0); nvecs = _evbuffer_read_setup_vecs(buf, at_most, vecs, MAX_WSABUFS, &chainp, 1); for (i=0;i<nvecs;++i) { WSABUF_FROM_EVBUFFER_IOV( &buf_o->buffers[i], &vecs[i]); } buf_o->n_buffers = nvecs; buf_o->first_pinned = chain = *chainp; npin=0; for ( ; chain; chain = chain->next) { _evbuffer_chain_pin(chain, EVBUFFER_MEM_PINNED_R); ++npin; } EVUTIL_ASSERT(npin == nvecs); _evbuffer_incref(buf); if (WSARecv(buf_o->fd, buf_o->buffers, nvecs, &bytesRead, &flags, &ol->overlapped, NULL)) { int error = WSAGetLastError(); if (error != WSA_IO_PENDING) { /* An actual error. */ pin_release(buf_o, EVBUFFER_MEM_PINNED_R); evbuffer_unfreeze(buf, 0); evbuffer_free(buf); /* decref */ goto done; } } buf_o->read_in_progress = 1; r = 0; done: EVBUFFER_UNLOCK(buf); return r; }
int evbuffer_launch_write(struct evbuffer *buf, ev_ssize_t at_most, struct event_overlapped *ol) { struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf); int r = -1; int i; struct evbuffer_chain *chain; DWORD bytesSent; if (!buf) { /* No buffer, or it isn't overlapped */ return -1; } EVBUFFER_LOCK(buf); EVUTIL_ASSERT(!buf_o->read_in_progress); if (buf->freeze_start || buf_o->write_in_progress) goto done; if (!buf->total_len) { /* Nothing to write */ r = 0; goto done; } else if (at_most < 0 || (size_t)at_most > buf->total_len) { at_most = buf->total_len; } evbuffer_freeze(buf, 1); buf_o->first_pinned = NULL; buf_o->n_buffers = 0; memset(buf_o->buffers, 0, sizeof(buf_o->buffers)); chain = buf_o->first_pinned = buf->first; for (i=0; i < MAX_WSABUFS && chain; ++i, chain=chain->next) { WSABUF *b = &buf_o->buffers[i]; b->buf = (char*)( chain->buffer + chain->misalign ); _evbuffer_chain_pin(chain, EVBUFFER_MEM_PINNED_W); if ((size_t)at_most > chain->off) { /* XXXX Cast is safe for now, since win32 has no mmaped chains. But later, we need to have this add more WSAbufs if chain->off is greater than ULONG_MAX */ b->len = (unsigned long)chain->off; at_most -= chain->off; } else { b->len = (unsigned long)at_most; ++i; break; } } buf_o->n_buffers = i; _evbuffer_incref(buf); if (WSASend(buf_o->fd, buf_o->buffers, i, &bytesSent, 0, &ol->overlapped, NULL)) { int error = WSAGetLastError(); if (error != WSA_IO_PENDING) { /* An actual error. */ pin_release(buf_o, EVBUFFER_MEM_PINNED_W); evbuffer_unfreeze(buf, 1); evbuffer_free(buf); /* decref */ goto done; } } buf_o->write_in_progress = 1; r = 0; done: EVBUFFER_UNLOCK(buf); return r; }
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); }