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