WinSock: socketにfgetsを使えない… と思ったら出来た

_open_osfhandleしてfdopenすれば使えると思ったのに。
追ってみると、ReadFileでコケてるみたい。
ひょっとしてサーバ側だと使えないのかな?うーん…

socketじゃなくてWSASocketを使ったらできた!

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define ECHO_PORT 7
#define MAX_BACKLOG 5
#define RCVBUFSIZE 255

#define die(...) do { fprintf(stderr, __VA_ARGS__); WSACleanup(); exit(1); } while(0)
#define debug(...) 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));
  }
}

void echo(FILE *f) {
  while (1) {
    char buf[RCVBUFSIZE + 1];

    if (fgets(buf, RCVBUFSIZE + 1, f) == NULL) {
      break;
    }

    debug("recv: %s\n", buf);

    errno = 0;
    if (fputs(buf, f) == EOF) {
      if (errno != 0) {
        die("fputs()\n");
      }
    }
  }
}

int main() {
  SOCKET sock, s;
  struct sockaddr_in addr, caddr;
  int len;

  wsa_startup(MAKEWORD(2, 0));

  if ((sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == 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());
  }

  while(1) {
    int fd;
    FILE *f;
    len = sizeof(caddr);

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

    debug("accepted.\n");

    if ((fd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) {
      die("_open_osfhandle()\n");
    }

    if ((f = _fdopen(fd, "rb+")) == NULL) {
      die("_fdopen()\n");
    }

    setvbuf(f, NULL, _IONBF, 0);
    echo(f);
    closesocket(s);
    debug("closed.\n");
  }

  WSACleanup();
  return 0;
}