/src/pnpserver.cxx
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