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/types.h>
16 #  include <sys/socket.h>
17 #  include <sys/un.h>
18 #endif
19 
20 #include "pstreams.h"
21 
22 
23 PTYPES_BEGIN
24 
25 
26 #ifdef WIN32
27 
realpipename(const string & pipename,const string & svrname)28 string ptdecl namedpipe::realpipename(const string& pipename, const string& svrname)
29 {
30     if (isempty(pipename))
31         return nullstring;
32     string realname = pipename;
33     if (*pconst(pipename) == '/')
34     {
35         int i = rpos('/', realname);
36         del(realname, 0, i + 1);
37     }
38     string s;
39     if (isempty(svrname))
40         s = '.';
41     else
42         s = svrname;
43     return "\\\\" + s + "\\pipe\\" + realname;
44 }
45 
46 
47 #else
48 
49 string ptdecl namedpipe::realpipename(const string& pipename)
50 {
51     if (isempty(pipename))
52         return nullstring;
53     if (*pconst(pipename) == '/')
54         return pipename;
55     else
56         return DEF_NAMED_PIPES_DIR + pipename;
57 }
58 
59 
60 bool namedpipe::setupsockaddr(const string& pipename, void* isa)
61 {
62     sockaddr_un* sa = (sockaddr_un*)isa;
63     memset(sa, 0, sizeof(sockaddr_un));
64     sa->sun_family = AF_UNIX;
65 #ifdef __FreeBSD__
66     sa->sun_len = length(pipename);
67 #endif
68 
69     // copy the path name into the sockaddr structure, 108 chars max (?)
70     if (length(pipename) + 1 > (int)sizeof(sa->sun_path))
71         return false;
72     strcpy(sa->sun_path, pipename);
73     return true;
74 }
75 
76 #endif
77 
78 
namedpipe()79 namedpipe::namedpipe()
80     : fdxstm(), pipename(), svhandle(invhandle)
81 {
82     initovr();
83 }
84 
85 
namedpipe(const string & ipipename)86 namedpipe::namedpipe(const string& ipipename)
87     : fdxstm(), pipename(), svhandle(invhandle)
88 {
89     pipename = realpipename(ipipename);
90     initovr();
91 }
92 
93 
94 #ifdef WIN32
95 
namedpipe(const string & ipipename,const string & servername)96 namedpipe::namedpipe(const string& ipipename, const string& servername)
97     : fdxstm(), pipename(), svhandle(invhandle)
98 {
99     pipename = realpipename(ipipename, servername);
100     initovr();
101 }
102 
103 
initovr()104 void namedpipe::initovr()
105 {
106     ovr.hEvent = CreateEvent(0, false, false, 0);
107 }
108 
109 
110 #endif
111 
112 
~namedpipe()113 namedpipe::~namedpipe()
114 {
115     cancel();
116 #ifdef WIN32
117     CloseHandle(ovr.hEvent);
118 #endif
119 }
120 
121 
classid()122 int namedpipe::classid()
123 {
124     return CLASS3_NPIPE;
125 }
126 
127 
get_streamname()128 string namedpipe::get_streamname()
129 {
130     return pipename;
131 }
132 
133 
set_pipename(const string & newvalue)134 void namedpipe::set_pipename(const string& newvalue)
135 {
136     close();
137     pipename = realpipename(newvalue);
138 }
139 
140 
set_pipename(const char * newvalue)141 void namedpipe::set_pipename(const char* newvalue)
142 {
143     close();
144     pipename = realpipename(newvalue);
145 }
146 
147 
doseek(large,ioseekmode)148 large namedpipe::doseek(large, ioseekmode)
149 {
150     return -1;
151 }
152 
153 
doopen()154 void namedpipe::doopen()
155 {
156 
157 #ifdef WIN32
158 
159     if (svhandle != invhandle)
160         handle = svhandle;
161     else
162     {
163         int tries = DEF_PIPE_OPEN_RETRY;
164         int delay = DEF_PIPE_OPEN_TIMEOUT / 2;
165 retry:
166         SECURITY_ATTRIBUTES sa;
167         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
168         sa.lpSecurityDescriptor = NULL;
169         sa.bInheritHandle = TRUE;
170 
171         handle = int(CreateFile(pipename, GENERIC_READ | GENERIC_WRITE,
172             0, &sa, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0));
173         if (handle == invhandle)
174         {
175             if (GetLastError() == ERROR_PIPE_BUSY)
176             {
177                 if (--tries > 0)
178                 {
179                     delay *= 2;
180                     Sleep(delay);
181                     goto retry;
182                 }
183                 else
184                     error(EIO, "Pipe busy");
185             }
186             else
187                 error(uerrno(), "Couldn't open named pipe");
188         }
189     }
190 
191 #else
192     if (svhandle != invhandle)
193     {
194 	if ((handle = ::accept(svhandle, 0, 0)) < 0)
195 	    error(uerrno(), "Couldn't create local socket");
196     }
197 
198     else
199     {
200         sockaddr_un sa;
201 	if (!setupsockaddr(pipename, &sa))
202     	    error(ERANGE, "Socket name too long");
203 
204         // cteate a client socket
205 	if ((handle = ::socket(sa.sun_family, SOCK_STREAM, 0)) < 0)
206     	    error(uerrno(), "Couldn't create local socket");
207 
208         // ... and connect to the local socket
209 	if (::connect(handle, (sockaddr*)&sa, sizeof(sa)) < 0)
210 	{
211     	    int e = uerrno();
212             doclose();
213 	    error(e, "Couldn't connect to local socket");
214         }
215     }
216 
217 #endif
218 }
219 
220 
221 #ifdef WIN32
222 
dorawread(char * buf,int count)223 int namedpipe::dorawread(char* buf, int count)
224 {
225     unsigned long ret = uint(-1);
226     ovr.Offset = 0;
227     ovr.OffsetHigh = 0;
228     if (!ReadFile(HANDLE(handle), buf, count, &ret, &ovr))
229     {
230         if (GetLastError() == ERROR_IO_PENDING)
231         {
232             if (WaitForSingleObject(ovr.hEvent, DEF_PIPE_TIMEOUT) == WAIT_TIMEOUT)
233                 error(EIO, "Timed out");
234             if (!GetOverlappedResult(HANDLE(handle), &ovr, &ret, false))
235                 error(uerrno(), "Couldn't read");
236         }
237         else
238             error(uerrno(), "Couldn't read");
239     }
240     return ret;
241 }
242 
243 
dorawwrite(const char * buf,int count)244 int namedpipe::dorawwrite(const char* buf, int count)
245 {
246     unsigned long ret = uint(-1);
247     ovr.Offset = 0;
248     ovr.OffsetHigh = 0;
249     if (!WriteFile(HANDLE(handle), buf, count, &ret, &ovr))
250     {
251         if (GetLastError() == ERROR_IO_PENDING)
252         {
253             if (WaitForSingleObject(ovr.hEvent, DEF_PIPE_TIMEOUT) == WAIT_TIMEOUT)
254                 error(EIO, "Timed out");
255             if (!GetOverlappedResult(HANDLE(handle), &ovr, &ret, false))
256                 error(uerrno(), "Couldn't write");
257         }
258         else
259             error(uerrno(), "Couldn't write");
260     }
261     return ret;
262 }
263 
264 
265 #endif
266 
267 
doclose()268 void namedpipe::doclose()
269 {
270 #ifdef WIN32
271     if (svhandle != invhandle)
272         DisconnectNamedPipe(HANDLE(handle));
273 #endif
274     svhandle = invhandle;
275     fdxstm::doclose();
276 }
277 
278 
flush()279 void namedpipe::flush()
280 {
281 #ifdef WIN32
282     if (!cancelled)
283         FlushFileBuffers(HANDLE(handle));
284 #endif
285     fdxstm::flush();
286 }
287 
288 
289 
290 PTYPES_END
291