Paste details

full server threaded

markand

cpp

month

#define WIN32_LEAN_AND_MEAN
#define NOMINMAX

#include <climits>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_map>
#include <utility>

#include <Windows.h>

namespace
{

// Fake dispatch table...
const std::unordered_map<std::string_view, std::string_view> commands
{
  {"users", "nicola, ludwig, boris, oli, marc"},
  {"login", "success"}
};

// Temporary: excuse my C.
void die(const char *fmt, ...)
{
  va_list ap;

  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  va_end(ap);
  exit(1);
}

std::string getPath()
{
  std::ostringstream oss;

#if 1
  oss << "\\\\.\\pipe\\dscp." << GetCurrentProcessId();
#else
  oss << "\\\\.\\pipe\\dscp";
#endif

  return oss.str();
}

HANDLE doBind(const std::string& path)
{
  auto h = CreateNamedPipeA(
    path.c_str(),
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES,
    BUFSIZ,
    BUFSIZ,
    0,
    nullptr
  );

  if (h == INVALID_HANDLE_VALUE)
    die("CreateNamedPipe: %d\n", GetLastError());

  return h;
}

void accept(HANDLE pipe)
{
  std::cout << "waiting for someone to connect...\n";

  if (!ConnectNamedPipe(pipe, nullptr))
    die("ConnectNamedPipe: %d\n", GetLastError());
}

std::string read(HANDLE pipe)
{
  std::string buffer;
  DWORD nbread = 0;

  buffer.resize(BUFSIZ);

  // Try first initial read.
  if (!ReadFile(pipe, &buffer[0], static_cast<DWORD>(buffer.size()), &nbread, nullptr))
  {
    // There is more data to read.
    if (GetLastError() == ERROR_MORE_DATA)
    {
      DWORD available;
      std::string remaining;

      // Get message length.
      if (!PeekNamedPipe(pipe, nullptr, 0, nullptr, &available, nullptr))
        die("PeekNamedPipe: %d\n", GetLastError());

      remaining.resize(available);
      nbread = 0;

      // Read the remaining message.
      if (!ReadFile(pipe, &remaining[0], static_cast<DWORD>(remaining.size()), &nbread, nullptr))
        die("ReadFile: %d\n", GetLastError());

      remaining.resize(nbread);
      buffer += remaining;
    }
    else
    {
      die("ReadFile: %d\n", GetLastError());
    }
  }
  else
  {
    buffer.resize(nbread);
  }

  return buffer;
}

void process(HANDLE pipe)
{
  std::cout << "client ready, waiting for request\n";

  const auto input = read(pipe);

  std::cout << "command: [" << input << "]\n";

  // ICI on fait l'appel à la commande JSON.
  if (const auto it = commands.find(input); it != commands.end())
  {
    // On renvoie sa réponse...
    if (!WriteFile(pipe, it->second.data(), (DWORD)it->second.size(), nullptr, nullptr))
      die("WriteFile: %d\n", GetLastError());
  }
  else
    std::cout << "command not found..." << std::endl;

  FlushFileBuffers(pipe);
  DisconnectNamedPipe(pipe);
  CloseHandle(pipe);
}

} // !namespace

int main()
{
  puts("DSCP.exe starting");

  auto jesus_returns = false;
  auto path = getPath();

  while (!jesus_returns)
  {
    auto pipe = doBind(path);

    accept(pipe);

    // not very cool to detach but...
    std::thread th{process, pipe};

    th.detach();
  }

  return 0;
}