細かいところはいい加減。なぜか動いてる。
echoサーバ
#include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <io.h> #include "wsepoll.h" #include <memory.h> #define ECHO_PORT 7 #define MAX_BACKLOG 5 #define RCVBUFSIZE 256 #define MAX_EVENTS WSA_MAXIMUM_WAIT_EVENTS #define EPOLL_TIMEOUT 1000 #define die(...) do { fprintf(stderr, __VA_ARGS__); WSACleanup(); exit(1); } while(0) #define error(...) do { fprintf(stderr, __VA_ARGS__); } while(0) static void wsa_startup(WORD version) { int n; WSADATA wsaData; if ((n = WSAStartup(version, &wsaData)) != 0) { die("WASStartup(): %d\n", n); } if (version != wsaData.wVersion) { die("WASStartup(): WinSock version %d.%d not supported\n", LOWORD(version), HIWORD(version)); } } int echo(SOCKET sock) { char buf[RCVBUFSIZE + 1]; size_t len; if ((len = recv(sock, buf, RCVBUFSIZE, 0)) < 0) { error("recv(): %d\n", WSAGetLastError()); return -1; } if (len == 0) { return 0; } buf[len] = '\0'; error("recv: %d '%s'\n", sock, buf); if (send(sock, buf, len, 0) < 0) { error("send(): %d\n", WSAGetLastError()); return -1; } return len; } int main() { int epfd; SOCKET sock; struct sockaddr_in addr; struct epoll_event event; wsa_startup(MAKEWORD(2, 0)); if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { die("socket(): %d\n", WSAGetLastError()); } addr.sin_family = AF_INET; addr.sin_port = htons(ECHO_PORT); addr.sin_addr.S_un.S_addr = INADDR_ANY; if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) != 0) { die("bind(): %d\n", WSAGetLastError()); } if (listen(sock, MAX_BACKLOG) != 0) { die("listen(): %d\n", WSAGetLastError()); } if((epfd = epoll_create(MAX_EVENTS)) < 0) { die("epoll_create()\n"); } memset(&event, 0, sizeof(event)); event.events = EPOLLIN; event.data.fd = sock; if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &event) < 0) { die("epoll_ctl()\n"); } while (1) { int i, nfds; struct sockaddr_in sa; socklen_t len = sizeof(sa); struct epoll_event events[MAX_EVENTS]; if ((nfds = epoll_wait(epfd, events, MAX_EVENTS, EPOLL_TIMEOUT)) < 0) { die("epoll_wait()\n"); } for (i = 0; i < nfds; i++) { SOCKET fd = events[i].data.fd; if (sock == fd) { int s; if ((s = accept(sock, (struct sockaddr*) &sa, &len)) < 0) { die("accept()\n"); } error("accepted.\n"); event.events = EPOLLIN; event.data.fd = s; if (epoll_ctl(epfd, EPOLL_CTL_ADD, s, &event) < 0) { die("epoll_ctl()\n"); } } else { if (echo(fd) < 1) { if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event) < 0) { die("epoll_ctl()\n"); } closesocket(fd); } } } } _close(epfd); closesocket(sock); WSACleanup(); return 0; }
wsepoll.h
#ifndef _WSEPOLL_H_ #define _WSEPOLL_H_ #include <winsock2.h> #define EPOLLIN (FD_READ | FD_ACCEPT | FD_CLOSE) #define EPOLLOUT (FD_WRITE | FD_CONNECT | FD_CLOSE) #define EPOLLRDHUP (FD_CLOSE) #define EPOLLPRI (FD_OOB) #define EPOLLERR 0 #define EPOLLHUP (FD_CLOSE) #define EPOLLET 0 #define EPOLLONESHOT 0 #define EPOLL_CTL_ADD 1 #define EPOLL_CTL_DEL 2 #define EPOLL_CTL_MOD 3 struct epoll_data { int fd; }; struct epoll_event { unsigned int events; struct epoll_data data; }; int epoll_create(int size); int epoll_ctl(int epfd, int op, SOCKET fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); #endif
wsepoll.c
#include <winsock2.h> #include <windows.h> #include <io.h> #include <fcntl.h> #include <share.h> #include <sys/stat.h> #include <sys/locking.h> #include <malloc.h> #include <errno.h> #include "wsepoll.h" struct wsepsock { SOCKET socket; unsigned int events; }; #define LOCK_FILE "wseplck" static struct wsepsock epsocks[WSA_MAXIMUM_WAIT_EVENTS]; static int mktmpfn(char *dst, int len, const char *src); static int epoll_ctl_add(int epfd, SOCKET fd, struct epoll_event *event); static int epoll_ctl_mod(int epfd, SOCKET fd, struct epoll_event *event); static int epoll_ctl_del(int epfd, SOCKET fd, struct epoll_event *event); static int epoll_wait_init(int *nfds, SOCKET *fds, HANDLE *hEvents); static void epoll_wait_clean(SOCKET *fds, HANDLE *hEvents); int epoll_create(int size) { int i, epfd; char tmpfn[MAX_PATH]; if (!mktmpfn(tmpfn, MAX_PATH, LOCK_FILE)) { return -1; } if (_sopen_s(&epfd, tmpfn, _O_CREAT | _O_TEMPORARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0) { return -1; } if(_locking(epfd, _LK_NBLCK, 1) != 0) { return -1; } for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { epsocks[i].socket = INVALID_SOCKET; epsocks[i].events = 0; } _locking(epfd, _LK_UNLCK, 1); return epfd; } int epoll_ctl(int epfd, int op, SOCKET fd, struct epoll_event *event) { int retval = -1; switch (op) { case EPOLL_CTL_ADD: retval = epoll_ctl_add(epfd, fd, event); break; case EPOLL_CTL_MOD: retval = epoll_ctl_mod(epfd, fd, event); break; case EPOLL_CTL_DEL: retval = epoll_ctl_del(epfd, fd, event); break; } return retval; } int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) { int nfds; SOCKET fds[WSA_MAXIMUM_WAIT_EVENTS]; HANDLE hEvents[WSA_MAXIMUM_WAIT_EVENTS]; DWORD n; if (!epoll_wait_init(&nfds, fds, hEvents)) { epoll_wait_clean(fds, hEvents); return -1; } n = WSAWaitForMultipleEvents(nfds, hEvents, FALSE, timeout, FALSE); if (n == WSA_WAIT_FAILED) { epoll_wait_clean(fds, hEvents); return -1; } else if (n == WSA_WAIT_TIMEOUT) { epoll_wait_clean(fds, hEvents); return 0; } else { SOCKET fd; HANDLE hEvent; WSANETWORKEVENTS ev; n -= WSA_WAIT_EVENT_0; fd = fds[n]; hEvent = hEvents[n]; if (WSAEnumNetworkEvents(fd, hEvent, &ev) < 0) { epoll_wait_clean( fds, hEvents); return -1; } events[0].data.fd = fd; events[0].events = ev.lNetworkEvents; epoll_wait_clean(fds, hEvents); return 1; } } //------------------------------------------------------------------- static int mktmpfn(char *dst, int len, const char *src) { char *buf = alloca(sizeof(char) * len); if (GetTempPathA(len, buf) == 0) { return 0; } if (GetTempFileNameA(buf, src, 0, dst) == 0) { return 0; } return 1; } static int epoll_ctl_add(int epfd, SOCKET fd, struct epoll_event *event) { int i; if(_locking(epfd, _LK_NBLCK, 1) != 0) { return -1; } for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { if (epsocks[i].socket == INVALID_SOCKET) { epsocks[i].socket = fd; epsocks[i].events = event->events; break; } } _locking(epfd, _LK_UNLCK, 1); return (i < WSA_MAXIMUM_WAIT_EVENTS) ? 0 : -1; } static int epoll_ctl_mod(int epfd, SOCKET fd, struct epoll_event *event) { int i; if(_locking(epfd, _LK_NBLCK, 1) != 0) { return -1; } for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { if (epsocks[i].socket == fd) { epsocks[i].events = event->events; break; } } _locking(epfd, _LK_UNLCK, 1); return (i < WSA_MAXIMUM_WAIT_EVENTS) ? 0 : -1; } static int epoll_ctl_del(int epfd, SOCKET fd, struct epoll_event *event) { int i; if(_locking(epfd, _LK_NBLCK, 1) != 0) { return -1; } for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { if (epsocks[i].socket == fd) { epsocks[i].socket = INVALID_SOCKET; epsocks[i].events = 0; break; } } _locking(epfd, _LK_UNLCK, 1); return (i < WSA_MAXIMUM_WAIT_EVENTS) ? 0 : -1; } static int epoll_wait_init(int *nfds, SOCKET *fds, HANDLE *hEvents) { int i; (*nfds) = 0; for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { fds[i] = INVALID_SOCKET; hEvents[i] = NULL; } for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { int n = *nfds; if (epsocks[i].socket == INVALID_SOCKET) { continue; } fds[n] = epsocks[i].socket; hEvents[n] = WSACreateEvent(); if (WSAEventSelect(fds[n], hEvents[n], epsocks[i].events) < 0) { errno = WSAGetLastError(); return 0; } (*nfds)++; } return 1; } static void epoll_wait_clean(SOCKET *fds, HANDLE *hEvents) { int i; for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++) { if (fds[i] != INVALID_SOCKET) { WSAEventSelect(fds[i], NULL, 0); } if (hEvents[i] != NULL) { WSACloseEvent(hEvents[i]); } } }