/src/pnpserver.cxx
http://github.com/foodmike/PTypes · C++ · 185 lines · 129 code · 44 blank · 12 comment · 20 complexity · b51459ac7b27f7b812285a0142c5a2f8 MD5 · raw file
- /*
- *
- * C++ Portable Types Library (PTypes)
- * Version 2.1.1 Released 27-Jun-2007
- *
- * Copyright (C) 2001-2007 Hovik Melikyan
- *
- * http://www.melikyan.com/ptypes/
- *
- */
- #ifdef WIN32
- # include <windows.h>
- #else
- # include <sys/time.h>
- # include <sys/types.h>
- # include <sys/socket.h>
- # include <sys/un.h>
- # include <unistd.h>
- #endif
- #include "pstreams.h"
- PTYPES_BEGIN
- npserver::npserver(const string& ipipename)
- : pipename(), handle(invhandle), active(false)
- {
- pipename = namedpipe::realpipename(ipipename);
- }
- npserver::~npserver()
- {
- close();
- }
- void npserver::error(int code, const char* defmsg)
- {
- string msg = unixerrmsg(code);
- if (isempty(msg))
- msg = defmsg;
- msg += " [" + pipename + ']';
- throw new estream(nil, code, msg);
- }
- #ifdef WIN32
- void npserver::openinst()
- {
- // called once at startup and then again, after
- // each client connection. strange logic, to say the least...
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
- handle = (int)CreateNamedPipe(pipename,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- DEF_PIPE_SYSTEM_BUF_SIZE, DEF_PIPE_SYSTEM_BUF_SIZE,
- DEF_PIPE_TIMEOUT, &sa);
-
- if (handle == invhandle)
- error(unixerrno(), "Couldn't create");
- }
- void npserver::closeinst()
- {
- CloseHandle(HANDLE(pexchange(&handle, invhandle)));
- }
- #endif
- void npserver::open()
- {
- close();
- #ifdef WIN32
- openinst();
- #else
- sockaddr_un sa;
- if (!namedpipe::setupsockaddr(pipename, &sa))
- error(ERANGE, "Socket name too long");
- if ((handle = ::socket(sa.sun_family, SOCK_STREAM, 0)) < 0)
- error(unixerrno(), "Couldn't create local socket");
- unlink(pipename);
- if (::bind(handle, (sockaddr*)&sa, sizeof(sa)) != 0)
- error(unixerrno(), "Couldn't bind local socket");
-
- if (::listen(handle, SOMAXCONN) != 0)
- error(unixerrno(), "Couldn't listen on local socket");
- #endif
- active = true;
- }
- void npserver::close()
- {
- if (active)
- {
- active = false;
- #ifdef WIN32
- closeinst();
- #else
- ::close(pexchange(&handle, invhandle));
- unlink(pipename);
- #endif
- }
- }
- bool npserver::serve(namedpipe& client, int timeout)
- {
- if (!active)
- open();
- client.cancel();
- #ifdef WIN32
- client.ovr.Offset = 0;
- client.ovr.OffsetHigh = 0;
- bool result = ConnectNamedPipe(HANDLE(handle), &client.ovr) ?
- true : (GetLastError() == ERROR_PIPE_CONNECTED);
- if (!result && GetLastError() == ERROR_IO_PENDING)
- {
- if (WaitForSingleObject(client.ovr.hEvent, timeout) == WAIT_TIMEOUT)
- return false;
- unsigned long ret;
- if (!GetOverlappedResult(HANDLE(handle), &client.ovr, &ret, false))
- error(unixerrno(), "Couldn't read");
- result = true;
- }
- if (result)
- {
- client.svhandle = handle;
- client.pipename = pipename;
- openinst();
- client.open();
- return true;
- }
- else
- error(unixerrno(), "Couldn't connect to client");
- return false;
- #else
- fd_set set;
- FD_ZERO(&set);
- FD_SET((uint)handle, &set);
- timeval t;
- t.tv_sec = timeout / 1000;
- t.tv_usec = (timeout % 1000) * 1000;
- if (::select(FD_SETSIZE, &set, nil, nil, (timeout < 0) ? nil : &t) > 0)
- {
- client.svhandle = handle;
- client.pipename = pipename;
- client.open();
- return true;
- }
- return false;
- #endif
- }
- PTYPES_END