echoサーバを書いてみた

例外使わないと、どうしてもCっぽくなるなー。

#include <string>
#include <iostream>
#include <winsock2.h>

namespace wsa {
  int cleanup() {
    return WSACleanup();
  }

  void startup(WORD version) {
    using namespace std;

    WSADATA wsa_data;
    int n;

    if ((n = WSAStartup(version, &wsa_data)) != 0) {
      cerr << "WASStartup(): " << n << "\n";
      cleanup();
      exit(1);
    }

    if (version != wsa_data.wVersion) {
      cerr << "WASStartup(): WinSock version " << LOWORD(version) << "." << HIWORD(version) << " not supported\n";
      cleanup();
      exit(1);
    }
  }
}

class EchoServer {
  static const int BACKLOG = 5;
  static const int RCVBUFSIZE = 256;

  int port;
  SOCKET socket;
  sockaddr_in addr;
  void echo(SOCKET &s);
public:
  EchoServer(int port = 7);
  void create_socket();
  void bind();
  void listen();
  void start();
};

void EchoServer::echo(SOCKET &s) {
  while (true) {
    char buf[RCVBUFSIZE];
    size_t len = ::recv(s, buf, RCVBUFSIZE, 0);

    if (len < 0) {
      std::cerr << "recv(): " << WSAGetLastError() << "\n";
      wsa::cleanup();
      exit(1);
    }

    if (len == 0) {
      break;
    }

    std::cout << std::string(buf, len) /*<< "\n"*/;

    if (::send(s, buf, len, 0) < 0) {
      std::cerr << "send(): " << WSAGetLastError() << "\n";
      wsa::cleanup();
      exit(1);
    }
  }
}

EchoServer::EchoServer(int port) : port(port) {
}

void EchoServer::create_socket() {
  socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  if (socket == INVALID_SOCKET) {
    std::cerr << "socket(): " <<  WSAGetLastError() << "\n";
    wsa::cleanup();
    exit(1);
  }

  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.S_un.S_addr = INADDR_ANY;
}

void EchoServer::bind() {
  if (::bind(socket, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) != 0) {
    std::cerr << "bind(): " << WSAGetLastError() << "\n";
    wsa::cleanup();
    exit(1);
  }
}

void EchoServer::listen() {
  if (::listen(socket, BACKLOG) != 0) {
    std::cerr << "listen(): " << WSAGetLastError() << "\n";
    wsa::cleanup();
    exit(1);
  }
}

void EchoServer::start() {
  while(true) {
    sockaddr_in caddr;
    int len = sizeof(caddr);

    std::cerr << "wait...";

    SOCKET s = accept(socket, reinterpret_cast<sockaddr *>(&caddr), &len);

    if (s == INVALID_SOCKET) {
      std::cerr << "accept(): " << WSAGetLastError() << "\n";
      wsa::cleanup();
      exit(1);
    }

    std::cerr << "accepted.\n";

    echo(s);
    closesocket(s);
  }
}

int main() {
  wsa::startup(MAKEWORD(2, 0));

  EchoServer echod;
  echod.create_socket();
  echod.bind();
  echod.listen();
  echod.start();

  wsa::cleanup();
  return 0;
}