echod_winsock_poll.c

書くことは書いたけど、ws2_32.dllのバージョンが古くて動かず。

#include <stdio.h>
#include <winsock2.h>

#define ECHO_PORT 7
#define MAX_BACKLOG 5
#define MAX_NFDS 64
#define RCVBUFSIZE 256
#define POLL_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", sock, buf);

  if (send(sock, buf, len, 0) < 0) {
    error("send(): %d\n", WSAGetLastError());
    return -1;
  }

  return len;
}


int main() {
  int i;
  SOCKET sock;
  SOCKET ss[MAX_NFDS];
  struct sockaddr_in addr;

  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());
  }

  for (i = 0; i < FD_SETSIZE; i++) { ss[i] = INVALID_SOCKET; }
  ss[0] = sock;

  while(1) {
    int i, nfds = 0;
    struct pollfd fds[MAX_NFDS];

    for (i = 0; i < MAX_NFDS; i++) {
      if (ss[i] != INVALID_SOCKET) {
        fds[nfds].fd = ss[i];
        fds[nfds].events = POLLIN;
        nfds++;
      }
    }

    if (WSAPoll(fds, nfds, POLL_TIMEOUT) < 0) {
      die("WSAPoll(): %d\n", WSAGetLastError());
    }

    for (i = 0; i < MAX_NFDS; i++) {
      int j;
      SOCKET fd = ss[i];

      if (fd == INVALID_SOCKET || !(fds[i].revents & POLLIN)) { continue; }

      if (sock == fd) {
        SOCKET s;
        struct sockaddr_in caddr;
        int len = sizeof(caddr);

        if ((s = accept(sock, (struct sockaddr *) &caddr, &len)) == INVALID_SOCKET) {
          die("accepr(): %d\n", WSAGetLastError());
        }

        error("accepted.\n");

        for (j = 0; j < MAX_NFDS; j++) {
          if (ss[j] == INVALID_SOCKET) {
            ss[j] = s;
            break;
          }
        }

        if (j >= MAX_NFDS) {
          closesocket(s);
        }
      } else {
        if (echo(fd) < 1) {
          for (j = 0; j < MAX_NFDS; j++) {
            if (ss[j] == fd) {
              ss[j] = INVALID_SOCKET;
              break;
            }
          }

          closesocket(fd);
        }
      }
    }
  }

  WSACleanup();
  return 0;
}