/*----------------------------------------------------------------------------*/ static int RaisePendingStreamEvents(mtcp_manager_t mtcp, struct mtcp_epoll *ep, socket_map_t socket) { tcp_stream *stream = socket->stream; if (!stream) return -1; if (stream->state < TCP_ST_ESTABLISHED) return -1; TRACE_EPOLL("Stream %d at state %s\n", stream->id, TCPStateToString(stream)); /* if there are payloads already read before epoll registration */ /* generate read event */ if (socket->epoll & MTCP_EPOLLIN) { struct tcp_recv_vars *rcvvar = stream->rcvvar; if (rcvvar->rcvbuf && rcvvar->rcvbuf->merged_len > 0) { TRACE_EPOLL("Socket %d: Has existing payloads\n", socket->id); AddEpollEvent(ep, USR_SHADOW_EVENT_QUEUE, socket, MTCP_EPOLLIN); } else if (stream->state == TCP_ST_CLOSE_WAIT) { TRACE_EPOLL("Socket %d: Waiting for close\n", socket->id); AddEpollEvent(ep, USR_SHADOW_EVENT_QUEUE, socket, MTCP_EPOLLIN); } } /* same thing to the write event */ if (socket->epoll & MTCP_EPOLLOUT) { struct tcp_send_vars *sndvar = stream->sndvar; if (!sndvar->sndbuf || (sndvar->sndbuf && sndvar->sndbuf->len < sndvar->snd_wnd)) { if (!(socket->events & MTCP_EPOLLOUT)) { TRACE_EPOLL("Socket %d: Adding write event\n", socket->id); AddEpollEvent(ep, USR_SHADOW_EVENT_QUEUE, socket, MTCP_EPOLLOUT); } } } return 0; }
void SyncHandler::ProcessAcceptedSessionList() { SESSION_LIST_ITER it; Session *pSession; m_pAcceptedSessionList->Lock(); m_pTemplateList->splice( *m_pAcceptedSessionList ); m_pAcceptedSessionList->Unlock(); SESSION_LIST activeList; while( !m_pTemplateList->empty() ) { pSession = m_pTemplateList->pop_front(); if (m_numActiveSessions >= m_dwMaxAcceptSession) { printf("Connection full! no available accept socket! \n"); FreeSession(pSession); continue; } if (!AddEpollEvent(pSession)) { FreeSession(pSession); continue; } NetworkObject * pNet = m_fnCreateAcceptedObject(); assert(pNet); pSession->BindNetworkObject(pNet); pSession->OnAccept(); ++m_numActiveSessions; activeList.push_back(pSession); } if ( !activeList.empty() ) { m_pActiveSessionList->Lock(); m_pActiveSessionList->splice( activeList ); m_pActiveSessionList->Unlock(); } }
/*----------------------------------------------------------------------------*/ ssize_t mtcp_read(mctx_t mctx, int sockid, char *buf, size_t len) { mtcp_manager_t mtcp; socket_map_t socket; tcp_stream *cur_stream; struct tcp_recv_vars *rcvvar; int event_remaining; int ret; mtcp = GetMTCPManager(mctx); if (!mtcp) { return -1; } if (sockid < 0 || sockid >= CONFIG.max_concurrency) { TRACE_API("Socket id %d out of range.\n", sockid); errno = EBADF; return -1; } socket = &mtcp->smap[sockid]; if (socket->socktype == MTCP_SOCK_UNUSED) { TRACE_API("Invalid socket id: %d\n", sockid); errno = EBADF; return -1; } if (socket->socktype == MTCP_SOCK_PIPE) { return PipeRead(mctx, sockid, buf, len); } if (socket->socktype != MTCP_SOCK_STREAM) { TRACE_API("Not an end socket. id: %d\n", sockid); errno = ENOTSOCK; return -1; } /* stream should be in ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT */ cur_stream = socket->stream; if (!cur_stream || !(cur_stream->state >= TCP_ST_ESTABLISHED && cur_stream->state <= TCP_ST_CLOSE_WAIT)) { errno = ENOTCONN; return -1; } rcvvar = cur_stream->rcvvar; /* if CLOSE_WAIT, return 0 if there is no payload */ if (cur_stream->state == TCP_ST_CLOSE_WAIT) { if (!rcvvar->rcvbuf) return 0; if (rcvvar->rcvbuf->merged_len == 0) return 0; } /* return EAGAIN if no receive buffer */ if (socket->opts & MTCP_NONBLOCK) { if (!rcvvar->rcvbuf || rcvvar->rcvbuf->merged_len == 0) { errno = EAGAIN; return -1; } } SBUF_LOCK(&rcvvar->read_lock); #if BLOCKING_SUPPORT if (!(socket->opts & MTCP_NONBLOCK)) { while (rcvvar->rcvbuf->merged_len == 0) { if (!cur_stream || cur_stream->state != TCP_ST_ESTABLISHED) { SBUF_UNLOCK(&rcvvar->read_lock); errno = EINTR; return -1; } pthread_cond_wait(&rcvvar->read_cond, &rcvvar->read_lock); } } #endif ret = CopyToUser(mtcp, cur_stream, buf, len); event_remaining = FALSE; /* if there are remaining payload, generate EPOLLIN */ /* (may due to insufficient user buffer) */ if (socket->epoll & MTCP_EPOLLIN) { if (!(socket->epoll & MTCP_EPOLLET) && rcvvar->rcvbuf->merged_len > 0) { event_remaining = TRUE; } } /* if waiting for close, notify it if no remaining data */ if (cur_stream->state == TCP_ST_CLOSE_WAIT && rcvvar->rcvbuf->merged_len == 0 && ret > 0) { event_remaining = TRUE; } SBUF_UNLOCK(&rcvvar->read_lock); if (event_remaining) { if (socket->epoll) { AddEpollEvent(mtcp->ep, USR_SHADOW_EVENT_QUEUE, socket, MTCP_EPOLLIN); #if BLOCKING_SUPPORT } else if (!(socket->opts & MTCP_NONBLOCK)) { if (!cur_stream->on_rcv_br_list) { cur_stream->on_rcv_br_list = TRUE; TAILQ_INSERT_TAIL(&mtcp->rcv_br_list, cur_stream, rcvvar->rcv_br_link); mtcp->rcv_br_list_cnt++; } #endif } } TRACE_API("Stream %d: mtcp_read() returning %d\n", cur_stream->id, ret); return ret; }
/*----------------------------------------------------------------------------*/ int mtcp_writev(mctx_t mctx, int sockid, struct iovec *iov, int numIOV) { mtcp_manager_t mtcp; socket_map_t socket; tcp_stream *cur_stream; struct tcp_send_vars *sndvar; int ret, to_write, i; mtcp = GetMTCPManager(mctx); if (!mtcp) { return -1; } if (sockid < 0 || sockid >= CONFIG.max_concurrency) { TRACE_API("Socket id %d out of range.\n", sockid); errno = EBADF; return -1; } socket = &mtcp->smap[sockid]; if (socket->socktype == MTCP_SOCK_UNUSED) { TRACE_API("Invalid socket id: %d\n", sockid); errno = EBADF; return -1; } if (socket->socktype != MTCP_SOCK_STREAM) { TRACE_API("Not an end socket. id: %d\n", sockid); errno = ENOTSOCK; return -1; } cur_stream = socket->stream; if (!cur_stream || !(cur_stream->state == TCP_ST_ESTABLISHED || cur_stream->state == TCP_ST_CLOSE_WAIT)) { errno = ENOTCONN; return -1; } sndvar = cur_stream->sndvar; SBUF_LOCK(&sndvar->write_lock); #if BLOCKING_SUPPORT if (!(socket->opts & MTCP_NONBLOCK)) { while (sndvar->snd_wnd <= 0) { TRACE_SNDBUF("Waiting for available sending window...\n"); if (!cur_stream || cur_stream->state != TCP_ST_ESTABLISHED) { SBUF_UNLOCK(&sndvar->write_lock); errno = EINTR; return -1; } pthread_cond_wait(&sndvar->write_cond, &sndvar->write_lock); TRACE_SNDBUF("Sending buffer became ready! snd_wnd: %u\n", sndvar->snd_wnd); } } #endif /* write from the vectored buffers */ to_write = 0; for (i = 0; i < numIOV; i++) { if (iov[i].iov_len <= 0) continue; ret = CopyFromUser(mtcp, cur_stream, iov[i].iov_base, iov[i].iov_len); if (ret <= 0) break; to_write += ret; if (ret < iov[i].iov_len) break; } SBUF_UNLOCK(&sndvar->write_lock); if (to_write > 0 && !(sndvar->on_sendq || sndvar->on_send_list)) { SQ_LOCK(&mtcp->ctx->sendq_lock); sndvar->on_sendq = TRUE; StreamEnqueue(mtcp->sendq, cur_stream); /* this always success */ SQ_UNLOCK(&mtcp->ctx->sendq_lock); mtcp->wakeup_flag = TRUE; } if (to_write == 0 && (socket->opts & MTCP_NONBLOCK)) { to_write = -1; errno = EAGAIN; } /* if there are remaining sending buffer, generate write event */ if (sndvar->snd_wnd > 0) { if (socket->epoll & MTCP_EPOLLOUT && !(socket->epoll & MTCP_EPOLLET)) { AddEpollEvent(mtcp->ep, USR_SHADOW_EVENT_QUEUE, socket, MTCP_EPOLLOUT); #if BLOCKING_SUPPORT } else if (!(socket->opts & MTCP_NONBLOCK)) { if (!cur_stream->on_snd_br_list) { cur_stream->on_snd_br_list = TRUE; TAILQ_INSERT_TAIL(&mtcp->snd_br_list, cur_stream, sndvar->snd_br_link); mtcp->snd_br_list_cnt++; } #endif } } TRACE_API("Stream %d: mtcp_writev() returning %d\n", cur_stream->id, to_write); return to_write; }