Skip to content

Instantly share code, notes, and snippets.

@linusyang
Last active March 6, 2018 21:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save linusyang/98c46cb4015f346594b4bf4b1b5a39fc to your computer and use it in GitHub Desktop.
Save linusyang/98c46cb4015f346594b4bf4b1b5a39fc to your computer and use it in GitHub Desktop.
/**
* http://d.hatena.ne.jp/odz/20070507/1178558340
*/
// x86_64-w64-mingw32-gcc echo.c wepoll.c -O0 -o echo -g -lws2_32 -static
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ws2spi.h>
#include "wepoll.h"
#define close(fd) closesocket(fd)
#else
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#endif
#define SERVER_PORT 10007
#define MAX_EVENTS 10
#define BACKLOG 10
static int _listener;
static int epfd;
#ifdef _WIN32
static const GUID AFD_PROVIDER_GUID_LIST[] = {
/* MSAFD Tcpip [TCP+UDP+RAW / IP] */
{0xe70f1aa0, 0xab8b, 0x11cf,
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
/* MSAFD Tcpip [TCP+UDP+RAW / IPv6] */
{0xf9eab0c0, 0x26d4, 0x11d0,
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
/* MSAFD RfComm [Bluetooth] */
{0x9fc48064, 0x7298, 0x43e4,
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}},
/* MSAFD Irda [IrDA] */
{0x3972523d, 0x2af1, 0x11d1,
{0xb6, 0x55, 0x00, 0x80, 0x5f, 0x36, 0x42, 0xcc}}};
#define perror(msg) myerror(msg)
#define array_count(a) (sizeof(a) / (sizeof((a)[0])))
static void myerror(const char *s)
{
LPVOID *msg = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, WSAGetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&msg, 0, NULL);
if (msg != NULL) {
char *str = (char *) msg;
size_t ln = strlen(str) - 1;
if (ln >= 0 && str[ln] == '\n')
str[ln] = '\0';
fprintf(stderr, "%s: %s", s, (char *)str);
LocalFree(msg);
}
}
#endif
static void
die (const char* msg)
{
perror (msg);
exit (EXIT_FAILURE);
}
static void
setnonblocking (int sock)
{
#if defined _WIN32
u_long iMode = 1;
ioctlsocket(sock, FIONBIO, &iMode);
#else
int flag = fcntl (sock, F_GETFL, 0);
fcntl (sock, F_SETFL, flag | O_NONBLOCK);
#endif
}
static int
setup_socket ()
{
int sock = -1;
struct sockaddr_in sin;
#ifdef _WIN32
// We need to use the original MSAFD provider.
WSAPROTOCOL_INFOW* info, chainInfo;
DWORD szInfo = 0;
int err = 0;
int count = WSCEnumProtocols( 0, info, &szInfo, &err );
if( count == SOCKET_ERROR && err != WSAENOBUFS ) die("WSCEnumProtocols");
info = (WSAPROTOCOL_INFOW*) malloc(szInfo);
count = WSCEnumProtocols( 0, info, &szInfo, &err );
int id = -1;
for(int i = 0; i < count; i++ )
{
if( info[i].iAddressFamily == AF_INET &&
info[i].iProtocol == IPPROTO_TCP )
{
for (int j = 0; j < array_count(AFD_PROVIDER_GUID_LIST); j++) {
if (memcmp(&info[i].ProviderId,
&AFD_PROVIDER_GUID_LIST[j],
sizeof info[i].ProviderId) == 0) {
id = i;
break;
}
}
if (id != -1) break;
}
}
if (id != -1){
sock = WSASocketW(PF_INET,
SOCK_STREAM,
IPPROTO_TCP,
&info[id],
0,
0);
}
free(info);
if (sock < 0) die("socket");
#else
if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
die ("socket");
}
#endif
setnonblocking (sock);
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(SERVER_PORT);
if (bind (sock, (struct sockaddr *) &sin, sizeof sin) < 0)
{
close (sock);
die ("bind");
}
if (listen (sock, BACKLOG) < 0)
{
close (sock);
die ("listen");
}
return sock;
}
int
main ()
{
#if defined _WIN32
WSADATA wsadata;
int rc = WSAStartup(MAKEWORD(2,2), &wsadata);
if (rc) return 1;
#endif
struct epoll_event ev;
struct epoll_event events[MAX_EVENTS];
char buffer[1024];
if ((epfd = epoll_create (MAX_EVENTS)) < 0)
{
die ("epoll_create");
}
_listener = setup_socket ();
puts("Listening...");
memset(&ev, 0, sizeof ev);
memset(events, 0, sizeof events);
ev.events = EPOLLIN;
ev.data.fd = _listener;
epoll_ctl (epfd, EPOLL_CTL_ADD, _listener, &ev);
for (;;)
{
int i;
int nfd = epoll_wait (epfd, events, MAX_EVENTS, -1);
printf("OK: %d\n", nfd);
for (i = 0; i < nfd; i++)
{
if (events[i].data.fd == _listener)
{
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof client_addr;
int client = accept (_listener, (struct sockaddr *) &client_addr,
&client_addr_len);
if (client < 0)
{
perror ("accept");
continue;
}
puts("New connection.");
setnonblocking (client);
memset(&ev, 0, sizeof ev);
ev.events = EPOLLIN;
ev.data.fd = client;
epoll_ctl (epfd, EPOLL_CTL_ADD, client, &ev);
}
else
{
int client = events[i].data.fd;
int n = recv (client, buffer, sizeof buffer, 0);
if (n < 0)
{
perror ("read");
epoll_ctl (epfd, EPOLL_CTL_DEL, client, &ev);
close (client);
}
else if (n == 0)
{
epoll_ctl (epfd, EPOLL_CTL_DEL, client, &ev);
close (client);
puts("Connection closed.");
}
else
{
printf("Received: ");
fwrite(buffer, n, 1, stdout);
send (client, buffer, n, 0);
}
}
}
}
#if (defined WIN32 || defined _WIN32)
WSACleanup();
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment