echod_winsock.c

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

#define ECHO_PORT 7
#define MAX_BACKLOG 5
#define RCVBUFSIZE 256

#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, WSADATA *wsaData) {
  int n;

  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(SOCKET sock) {
  while (1) {
    char buf[RCVBUFSIZE + 1];
    size_t len;

    if ((len = recv(sock, buf, RCVBUFSIZE, 0)) < 0) {
      die("recv(): %d\n", WSAGetLastError());
    }

    if (len == 0) { break; }

    buf[len] = '\0';
    debug("recv: %s", buf);

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

  closesocket(sock);
}


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

  wsa_startup(MAKEWORD(2, 0), &wsaData);

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

  while(1) {
    len = sizeof(caddr);

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

    debug("accepted.\n");
    echo(s);
    debug("closed.\n");
  }

  WSACleanup();
  return 0;
}