/*----------------------------------------------------------------------------*/ int mtcp_socket(mctx_t mctx, int domain, int type, int protocol) { mtcp_manager_t mtcp; socket_map_t socket; mtcp = GetMTCPManager(mctx); if (!mtcp) { return -1; } if (domain != AF_INET) { errno = EAFNOSUPPORT; return -1; } if (type == SOCK_STREAM) { type = MTCP_SOCK_STREAM; } else { errno = EINVAL; return -1; } socket = AllocateSocket(mctx, type, FALSE); if (!socket) { errno = ENFILE; return -1; } return socket->id; }
/*----------------------------------------------------------------------------*/ int mtcp_epoll_create(mctx_t mctx, int size) { mtcp_manager_t mtcp = g_mtcp[mctx->cpu]; struct mtcp_epoll *ep; socket_map_t epsocket; if (size <= 0) { errno = EINVAL; return -1; } epsocket = AllocateSocket(mctx, MTCP_SOCK_EPOLL, FALSE); if (!epsocket) { errno = ENFILE; return -1; } ep = (struct mtcp_epoll *)calloc(1, sizeof(struct mtcp_epoll)); if (!ep) { FreeSocket(mctx, epsocket->id, FALSE); return -1; } /* create event queues */ ep->usr_queue = CreateEventQueue(size); if (!ep->usr_queue) return -1; ep->usr_shadow_queue = CreateEventQueue(size); if (!ep->usr_shadow_queue) { DestroyEventQueue(ep->usr_queue); return -1; } ep->mtcp_queue = CreateEventQueue(size); if (!ep->mtcp_queue) { DestroyEventQueue(ep->usr_queue); DestroyEventQueue(ep->usr_shadow_queue); return -1; } TRACE_EPOLL("epoll structure of size %d created.\n", size); mtcp->ep = ep; epsocket->ep = ep; if (pthread_mutex_init(&ep->epoll_lock, NULL)) { return -1; } if (pthread_cond_init(&ep->epoll_cond, NULL)) { return -1; } return epsocket->id; }
/*----------------------------------------------------------------------------*/ int mtcp_accept(mctx_t mctx, int sockid, struct sockaddr *addr, socklen_t *addrlen) { mtcp_manager_t mtcp; struct tcp_listener *listener; socket_map_t socket; tcp_stream *accepted = NULL; 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; } /* requires listening socket */ if (mtcp->smap[sockid].socktype != MTCP_SOCK_LISTENER) { errno = EINVAL; return -1; } listener = mtcp->smap[sockid].listener; /* dequeue from the acceptq without lock first */ /* if nothing there, acquire lock and cond_wait */ accepted = StreamDequeue(listener->acceptq); if (!accepted) { if (listener->socket->opts & MTCP_NONBLOCK) { errno = EAGAIN; return -1; } else { pthread_mutex_lock(&listener->accept_lock); while ((accepted = StreamDequeue(listener->acceptq)) == NULL) { pthread_cond_wait(&listener->accept_cond, &listener->accept_lock); if (mtcp->ctx->done || mtcp->ctx->exit) { pthread_mutex_unlock(&listener->accept_lock); errno = EINTR; return -1; } } pthread_mutex_unlock(&listener->accept_lock); } } if (!accepted) { TRACE_ERROR("[NEVER HAPPEN] Empty accept queue!\n"); } if (!accepted->socket) { socket = AllocateSocket(mctx, MTCP_SOCK_STREAM, FALSE); if (!socket) { TRACE_ERROR("Failed to create new socket!\n"); /* TODO: destroy the stream */ errno = ENFILE; return -1; } socket->stream = accepted; accepted->socket = socket; } TRACE_API("Stream %d accepted.\n", accepted->id); if (addr && addrlen) { struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; addr_in->sin_family = AF_INET; addr_in->sin_port = accepted->dport; addr_in->sin_addr.s_addr = accepted->daddr; *addrlen = sizeof(struct sockaddr_in); } return accepted->socket->id; }
int CSocketServer::Run() { try { vector<WorkerThread *> workers; workers.reserve( m_numThreads ); for ( size_t i = 0; i < m_numThreads; ++i ) { /* * Call to unqualified virtual function */ WorkerThread *pThread = CreateWorkerThread( m_iocp ); workers.push_back( pThread ); pThread->Start(); } HANDLE handlesToWaitFor[2]; handlesToWaitFor[0] = m_shutdownEvent.GetEvent(); handlesToWaitFor[1] = m_acceptConnectionsEvent.GetEvent(); while ( !m_shutdownEvent.Wait( 0 ) ) { DWORD waitResult = ::WaitForMultipleObjects( 2, handlesToWaitFor, false, INFINITE ); if ( waitResult == WAIT_OBJECT_0 ) { /* * Time to shutdown */ break; } else if ( waitResult == WAIT_OBJECT_0 + 1 ) { /* * accept connections */ while ( !m_shutdownEvent.Wait( 0 ) && m_acceptConnectionsEvent.Wait( 0 ) ) { CIOBuffer *pAddress = Allocate(); int addressSize = (int)pAddress->GetSize(); SOCKET acceptedSocket = ::WSAAccept( m_listeningSocket, reinterpret_cast<sockaddr *>(const_cast<BYTE *>( pAddress->GetBuffer() ) ), &addressSize, 0, 0); pAddress->Use( addressSize ); if ( acceptedSocket != INVALID_SOCKET ) { Socket *pSocket = AllocateSocket( acceptedSocket ); /* * Call to unqualified virtual function */ OnConnectionEstablished( pSocket, pAddress ); } else if ( m_acceptConnectionsEvent.Wait( 0 ) ) { /* * Call to unqualified virtual function */ OnError( _T("CSocketServer::Run() - WSAAccept:") + GetLastErrorMessage( ::WSAGetLastError() ) ); } pAddress->Release(); } } else { /* * Call to unqualified virtual function */ OnError( _T("CSocketServer::Run() - WaitForMultipleObjects: ") + GetLastErrorMessage( ::GetLastError() ) ); } } for ( i = 0; i < m_numThreads; ++i ) { workers[i]->InitiateShutdown(); } for ( i = 0; i < m_numThreads; ++i ) { workers[i]->WaitForShutdownToComplete(); delete workers[i]; workers[i] = 0; } } catch( const CException &e ) { /* * Call to unqualified virtual function */ OnError( _T("CSocketServer::Run() - Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() ); } catch(...) { /* * Call to unqualified virtual function */ OnError( _T("CSocketServer::Run() - Unexpected exception") ); } /* * Call to unqualified virtual function */ OnShutdownComplete(); return 0; }