PageRenderTime 32ms CodeModel.GetById 20ms app.highlight 10ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pnpserver.cxx

http://github.com/foodmike/PTypes
C++ | 185 lines | 129 code | 44 blank | 12 comment | 20 complexity | b51459ac7b27f7b812285a0142c5a2f8 MD5 | raw file
  1/*
  2 *
  3 *  C++ Portable Types Library (PTypes)
  4 *  Version 2.1.1  Released 27-Jun-2007
  5 *
  6 *  Copyright (C) 2001-2007 Hovik Melikyan
  7 *
  8 *  http://www.melikyan.com/ptypes/
  9 *
 10 */
 11
 12#ifdef WIN32
 13#  include <windows.h>
 14#else
 15#  include <sys/time.h>
 16#  include <sys/types.h>
 17#  include <sys/socket.h>
 18#  include <sys/un.h>
 19#  include <unistd.h>
 20#endif
 21
 22#include "pstreams.h"
 23
 24
 25PTYPES_BEGIN
 26
 27
 28npserver::npserver(const string& ipipename)
 29    : pipename(), handle(invhandle), active(false)
 30{
 31    pipename = namedpipe::realpipename(ipipename);
 32}
 33
 34
 35npserver::~npserver()
 36{
 37    close();
 38}
 39
 40
 41void npserver::error(int code, const char* defmsg)
 42{
 43    string msg = unixerrmsg(code);
 44    if (isempty(msg))
 45        msg = defmsg;
 46    msg += " [" + pipename + ']';
 47    throw new estream(nil, code, msg);
 48}
 49
 50
 51#ifdef WIN32
 52
 53void npserver::openinst()
 54{
 55    // called once at startup and then again, after 
 56    // each client connection. strange logic, to say the least...
 57    SECURITY_ATTRIBUTES sa;
 58    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
 59    sa.lpSecurityDescriptor = NULL;
 60    sa.bInheritHandle = TRUE;
 61
 62    handle = (int)CreateNamedPipe(pipename, 
 63        PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
 64        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
 65        PIPE_UNLIMITED_INSTANCES, 
 66        DEF_PIPE_SYSTEM_BUF_SIZE, DEF_PIPE_SYSTEM_BUF_SIZE,
 67        DEF_PIPE_TIMEOUT, &sa);
 68    
 69    if (handle == invhandle)
 70        error(unixerrno(), "Couldn't create");
 71}
 72
 73
 74void npserver::closeinst()
 75{
 76    CloseHandle(HANDLE(pexchange(&handle, invhandle)));
 77}
 78
 79#endif
 80
 81
 82void npserver::open()
 83{
 84    close();
 85
 86#ifdef WIN32
 87
 88    openinst();
 89
 90#else
 91
 92    sockaddr_un sa;
 93    if (!namedpipe::setupsockaddr(pipename, &sa))
 94        error(ERANGE, "Socket name too long");
 95
 96    if ((handle = ::socket(sa.sun_family, SOCK_STREAM, 0)) < 0)
 97        error(unixerrno(), "Couldn't create local socket");
 98
 99    unlink(pipename);
100    if (::bind(handle, (sockaddr*)&sa, sizeof(sa)) != 0)
101        error(unixerrno(), "Couldn't bind local socket");
102    
103    if (::listen(handle, SOMAXCONN) != 0)
104        error(unixerrno(), "Couldn't listen on local socket");
105
106#endif
107
108    active = true;
109}
110
111
112void npserver::close()
113{
114    if (active)
115    {
116        active = false;
117#ifdef WIN32
118        closeinst();
119#else
120        ::close(pexchange(&handle, invhandle));
121        unlink(pipename);
122#endif
123    }
124}
125
126
127bool npserver::serve(namedpipe& client, int timeout)
128{
129    if (!active)
130        open();
131
132    client.cancel();
133
134#ifdef WIN32
135
136    client.ovr.Offset = 0;
137    client.ovr.OffsetHigh = 0;
138    bool result = ConnectNamedPipe(HANDLE(handle), &client.ovr) ?
139        true : (GetLastError() == ERROR_PIPE_CONNECTED);
140
141    if (!result && GetLastError() == ERROR_IO_PENDING)
142    {
143        if (WaitForSingleObject(client.ovr.hEvent, timeout) == WAIT_TIMEOUT)
144            return false;
145        unsigned long ret;
146        if (!GetOverlappedResult(HANDLE(handle), &client.ovr, &ret, false))
147            error(unixerrno(), "Couldn't read");
148        result = true;
149    }
150
151    if (result)
152    {
153        client.svhandle = handle;
154        client.pipename = pipename;
155        openinst();
156        client.open();
157        return true;
158    }
159    else
160        error(unixerrno(), "Couldn't connect to client");
161
162    return false;
163
164#else
165
166    fd_set set;
167    FD_ZERO(&set);
168    FD_SET((uint)handle, &set);
169    timeval t;
170    t.tv_sec = timeout / 1000;
171    t.tv_usec = (timeout % 1000) * 1000;
172    if (::select(FD_SETSIZE, &set, nil, nil, (timeout < 0) ? nil : &t) > 0)
173    {
174        client.svhandle = handle;
175        client.pipename = pipename;
176        client.open();
177        return true;
178    }
179    return false;
180
181#endif
182}
183
184
185PTYPES_END