OLD | NEW |
| (Empty) |
1 #ifdef _WINDOWS | |
2 | |
3 /* Licensed to the Apache Software Foundation (ASF) under one or more | |
4 * contributor license agreements. See the NOTICE file distributed with | |
5 * this work for additional information regarding copyright ownership. | |
6 * The ASF licenses this file to You under the Apache License, Version 2.0 | |
7 * (the "License"); you may not use this file except in compliance with | |
8 * the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0 | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 | |
19 /** NT Pipes network wrapper | |
20 * | |
21 * @author Mladen Turk | |
22 * @version $Id: ntpipe.c 1442587 2013-02-05 13:49:48Z rjung $ | |
23 */ | |
24 | |
25 | |
26 #ifndef _WIN32_WINNT | |
27 #define _WIN32_WINNT 0x0500 | |
28 #endif | |
29 #define STRICT | |
30 #include <winsock2.h> | |
31 #include <mswsock.h> | |
32 #include <ws2tcpip.h> | |
33 #include <sddl.h> | |
34 | |
35 #include "tcn.h" | |
36 #include "apr_thread_mutex.h" | |
37 #include "apr_poll.h" | |
38 | |
39 #ifdef TCN_DO_STATISTICS | |
40 #include "apr_atomic.h" | |
41 | |
42 static volatile apr_uint32_t ntp_created = 0; | |
43 static volatile apr_uint32_t ntp_closed = 0; | |
44 static volatile apr_uint32_t ntp_cleared = 0; | |
45 static volatile apr_uint32_t ntp_accepted = 0; | |
46 | |
47 void ntp_network_dump_statistics() | |
48 { | |
49 fprintf(stderr, "NT Network Statistics ..\n"); | |
50 fprintf(stderr, "Sockets created : %d\n", ntp_created); | |
51 fprintf(stderr, "Sockets accepted : %d\n", ntp_accepted); | |
52 fprintf(stderr, "Sockets closed : %d\n", ntp_closed); | |
53 fprintf(stderr, "Sockets cleared : %d\n", ntp_cleared); | |
54 } | |
55 | |
56 #endif | |
57 | |
58 #define DEFNAME "\\\\.\\PIPE\\TOMCATNATIVEPIPE" | |
59 #define DEFNAME_FMT "\\\\.\\PIPE\\TOMCATNATIVEPIPE%08X%08X" | |
60 #define DEFSIZE 8192 | |
61 #define DEFTIMEOUT 60000 | |
62 | |
63 #define TCN_NTP_UNKNOWN 0 | |
64 #define TCN_NTP_CLIENT 1 | |
65 #define TCN_NTP_SERVER 2 | |
66 | |
67 typedef struct { | |
68 apr_pool_t *pool; | |
69 apr_socket_t *sock; /* Dummy socket */ | |
70 OVERLAPPED rd_o; | |
71 OVERLAPPED wr_o; | |
72 HANDLE h_pipe; | |
73 HANDLE rd_event; | |
74 HANDLE wr_event; | |
75 DWORD timeout; | |
76 int mode; /* Client or server mode */ | |
77 int nmax; | |
78 DWORD sndbuf; | |
79 DWORD rcvbuf; | |
80 char name[MAX_PATH+1]; | |
81 SECURITY_ATTRIBUTES sa; | |
82 } tcn_ntp_conn_t; | |
83 | |
84 static const char *NTSD_STRING = "D:" /* Discretionary ACL */ | |
85 "(D;OICI;GA;;;BG)" /* Deny access to Built-in Guests */ | |
86 "(D;OICI;GA;;;AN)" /* Deny access to Anonymous Logon */ | |
87 "(A;OICI;GRGWGX;;;AU)" /* Allow read/write/execute to Authent
icated Users */ | |
88 "(A;OICI;GA;;;BA)" /* Allow full control to Administrator
s */ | |
89 "(A;OICI;GA;;;LS)" /* Allow full control to Local service
account */ | |
90 "(A;OICI;GA;;;SY)"; /* Allow full control to Local system
*/ | |
91 | |
92 | |
93 | |
94 static apr_status_t APR_THREAD_FUNC | |
95 ntp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) | |
96 { | |
97 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock; | |
98 if (t < 0) | |
99 con->timeout = INFINITE; | |
100 else | |
101 con->timeout = (DWORD)(apr_time_as_msec(t)); | |
102 return APR_SUCCESS; | |
103 } | |
104 | |
105 static apr_status_t APR_THREAD_FUNC | |
106 ntp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) | |
107 { | |
108 tcn_ntp_conn_t *con = (tcn_ntp_conn_t*)sock; | |
109 if (con->timeout == INFINITE) | |
110 *t = -1; | |
111 else | |
112 *t = con->timeout * 1000; | |
113 return APR_SUCCESS; | |
114 } | |
115 | |
116 static APR_INLINE apr_status_t APR_THREAD_FUNC | |
117 ntp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on) | |
118 { | |
119 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock; | |
120 apr_status_t rv = APR_SUCCESS; | |
121 switch (opt) { | |
122 case APR_SO_SNDBUF: | |
123 con->sndbuf = (DWORD)on; | |
124 break; | |
125 case APR_SO_RCVBUF: | |
126 con->rcvbuf = (DWORD)on; | |
127 break; | |
128 default: | |
129 rv = APR_EINVAL; | |
130 break; | |
131 } | |
132 return rv; | |
133 } | |
134 | |
135 static APR_INLINE apr_status_t APR_THREAD_FUNC | |
136 ntp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on) | |
137 { | |
138 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock; | |
139 apr_status_t rv = APR_SUCCESS; | |
140 switch (opt) { | |
141 case APR_SO_SNDBUF: | |
142 *on = con->sndbuf; | |
143 break; | |
144 case APR_SO_RCVBUF: | |
145 *on = con->rcvbuf; | |
146 break; | |
147 default: | |
148 rv = APR_EINVAL; | |
149 break; | |
150 } | |
151 return rv; | |
152 } | |
153 | |
154 static apr_status_t ntp_cleanup(void *data) | |
155 { | |
156 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)data; | |
157 | |
158 if (con) { | |
159 if (con->h_pipe) { | |
160 FlushFileBuffers(con->h_pipe); | |
161 CloseHandle(con->h_pipe); | |
162 con->h_pipe = NULL; | |
163 } | |
164 if (con->rd_event) { | |
165 CloseHandle(con->rd_event); | |
166 con->rd_event = NULL; | |
167 } | |
168 if (con->wr_event) { | |
169 CloseHandle(con->wr_event); | |
170 con->wr_event= NULL; | |
171 } | |
172 } | |
173 | |
174 #ifdef TCN_DO_STATISTICS | |
175 apr_atomic_inc32(&ntp_cleared); | |
176 #endif | |
177 return APR_SUCCESS; | |
178 } | |
179 | |
180 static apr_status_t APR_THREAD_FUNC | |
181 ntp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how) | |
182 { | |
183 UNREFERENCED(how); | |
184 return ntp_cleanup(sock);; | |
185 } | |
186 | |
187 static apr_status_t APR_THREAD_FUNC | |
188 ntp_socket_close(apr_socket_t *sock) | |
189 { | |
190 #ifdef TCN_DO_STATISTICS | |
191 apr_atomic_inc32(&ntp_closed); | |
192 #endif | |
193 return ntp_cleanup(sock);; | |
194 } | |
195 | |
196 static apr_status_t APR_THREAD_FUNC | |
197 ntp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) | |
198 { | |
199 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock; | |
200 DWORD readed; | |
201 | |
202 if (!ReadFile(con->h_pipe, buf, (DWORD)*len, &readed, &con->rd_o)) { | |
203 DWORD err = GetLastError(); | |
204 if (err == ERROR_IO_PENDING) { | |
205 DWORD r = WaitForSingleObject(con->rd_event, con->timeout); | |
206 if (r == WAIT_TIMEOUT) | |
207 return APR_TIMEUP; | |
208 else if (r != WAIT_OBJECT_0) | |
209 return APR_EOF; | |
210 } | |
211 else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) { | |
212 /* Server closed the pipe */ | |
213 return APR_EOF; | |
214 } | |
215 GetOverlappedResult(con->h_pipe, &con->rd_o, &readed, FALSE); | |
216 } | |
217 *len = readed; | |
218 return APR_SUCCESS; | |
219 } | |
220 | |
221 static apr_status_t APR_THREAD_FUNC | |
222 ntp_socket_send(apr_socket_t *sock, const char *buf, | |
223 apr_size_t *len) | |
224 { | |
225 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock; | |
226 DWORD written; | |
227 | |
228 if (!WriteFile(con->h_pipe, buf, (DWORD)*len, &written, &con->wr_o)) { | |
229 DWORD err = GetLastError(); | |
230 if (err == ERROR_IO_PENDING) { | |
231 DWORD r = WaitForSingleObject(con->wr_event, con->timeout); | |
232 if (r == WAIT_TIMEOUT) | |
233 return APR_TIMEUP; | |
234 else if (r != WAIT_OBJECT_0) | |
235 return APR_EOF; | |
236 } | |
237 else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) { | |
238 /* Server closed the pipe */ | |
239 return APR_EOF; | |
240 } | |
241 GetOverlappedResult(con->h_pipe, &con->wr_o, &written, FALSE); | |
242 } | |
243 *len = written; | |
244 return APR_SUCCESS; | |
245 } | |
246 | |
247 static apr_status_t APR_THREAD_FUNC | |
248 ntp_socket_sendv(apr_socket_t *sock, | |
249 const struct iovec *vec, | |
250 apr_int32_t nvec, apr_size_t *len) | |
251 { | |
252 tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock; | |
253 apr_status_t rv; | |
254 apr_size_t written = 0; | |
255 apr_int32_t i; | |
256 | |
257 for (i = 0; i < nvec; i++) { | |
258 apr_size_t rd = vec[i].iov_len; | |
259 if ((rv = ntp_socket_send((apr_socket_t *)con, | |
260 vec[i].iov_base, &rd)) != APR_SUCCESS) { | |
261 *len = written; | |
262 return rv; | |
263 } | |
264 written += rd; | |
265 } | |
266 *len = written; | |
267 return APR_SUCCESS; | |
268 } | |
269 | |
270 static apr_status_t ntp_socket_cleanup(void *data) | |
271 { | |
272 tcn_socket_t *s = (tcn_socket_t *)data; | |
273 | |
274 if (s->net->cleanup) { | |
275 (*s->net->cleanup)(s->opaque); | |
276 s->net->cleanup = NULL; | |
277 } | |
278 #ifdef TCN_DO_STATISTICS | |
279 apr_atomic_inc32(&ntp_cleared); | |
280 #endif | |
281 return APR_SUCCESS; | |
282 } | |
283 | |
284 static tcn_nlayer_t ntp_socket_layer = { | |
285 TCN_SOCKET_NTPIPE, | |
286 ntp_cleanup, | |
287 ntp_socket_close, | |
288 ntp_socket_shutdown, | |
289 ntp_socket_opt_get, | |
290 ntp_socket_opt_set, | |
291 ntp_socket_timeout_get, | |
292 ntp_socket_timeout_set, | |
293 ntp_socket_send, | |
294 ntp_socket_sendv, | |
295 ntp_socket_recv | |
296 }; | |
297 | |
298 static BOOL create_DACL(LPSECURITY_ATTRIBUTES psa) | |
299 { | |
300 | |
301 return ConvertStringSecurityDescriptorToSecurityDescriptor( | |
302 NTSD_STRING, | |
303 SDDL_REVISION_1, | |
304 &(psa->lpSecurityDescriptor), | |
305 NULL); | |
306 } | |
307 | |
308 TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name, | |
309 jlong pool) | |
310 { | |
311 apr_pool_t *p = J2P(pool, apr_pool_t *); | |
312 tcn_socket_t *s = NULL; | |
313 tcn_ntp_conn_t *con = NULL; | |
314 TCN_ALLOC_CSTRING(name); | |
315 | |
316 UNREFERENCED(o); | |
317 TCN_ASSERT(pool != 0); | |
318 | |
319 #ifdef TCN_DO_STATISTICS | |
320 ntp_created++; | |
321 #endif | |
322 con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t)); | |
323 con->pool = p; | |
324 con->mode = TCN_NTP_UNKNOWN; | |
325 con->nmax = PIPE_UNLIMITED_INSTANCES; | |
326 con->timeout = DEFTIMEOUT; | |
327 con->sndbuf = DEFSIZE; | |
328 con->rcvbuf = DEFSIZE; | |
329 if (J2S(name)) { | |
330 strncpy(con->name, J2S(name), MAX_PATH); | |
331 con->name[MAX_PATH] = '\0'; | |
332 TCN_FREE_CSTRING(name); | |
333 } | |
334 else | |
335 strcpy(con->name, DEFNAME); | |
336 con->sa.nLength = sizeof(con->sa); | |
337 con->sa.bInheritHandle = TRUE; | |
338 if (!create_DACL(&con->sa)) { | |
339 tcn_ThrowAPRException(e, apr_get_os_error()); | |
340 return 0; | |
341 } | |
342 | |
343 s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t)); | |
344 s->pool = p; | |
345 s->net = &ntp_socket_layer; | |
346 s->opaque = con; | |
347 apr_pool_cleanup_register(p, (const void *)s, | |
348 ntp_socket_cleanup, | |
349 apr_pool_cleanup_null); | |
350 | |
351 fflush(stderr); | |
352 return P2J(s); | |
353 | |
354 } | |
355 | |
356 TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock, | |
357 jlong sa) | |
358 { | |
359 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
360 UNREFERENCED_STDARGS; | |
361 UNREFERENCED(sa); | |
362 TCN_ASSERT(sock != 0); | |
363 if (s->net->type == TCN_SOCKET_NTPIPE) { | |
364 tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque; | |
365 c->mode = TCN_NTP_SERVER; | |
366 return APR_SUCCESS; | |
367 } | |
368 else | |
369 return APR_EINVAL; | |
370 } | |
371 | |
372 TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock, | |
373 jint backlog) | |
374 { | |
375 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
376 UNREFERENCED_STDARGS; | |
377 | |
378 TCN_ASSERT(sock != 0); | |
379 if (s->net->type == TCN_SOCKET_NTPIPE) { | |
380 tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque; | |
381 c->mode = TCN_NTP_SERVER; | |
382 if (backlog > 0) | |
383 c->nmax = backlog; | |
384 else | |
385 c->nmax = PIPE_UNLIMITED_INSTANCES; | |
386 return APR_SUCCESS; | |
387 } | |
388 else | |
389 return APR_EINVAL; | |
390 } | |
391 | |
392 TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock) | |
393 { | |
394 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
395 apr_pool_t *p = NULL; | |
396 tcn_socket_t *a = NULL; | |
397 tcn_ntp_conn_t *con = NULL; | |
398 | |
399 UNREFERENCED(o); | |
400 TCN_ASSERT(sock != 0); | |
401 | |
402 TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p); | |
403 if (s->net->type == TCN_SOCKET_NTPIPE) { | |
404 tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque; | |
405 con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t)); | |
406 con->pool = p; | |
407 con->mode = TCN_NTP_SERVER; | |
408 con->nmax = c->nmax; | |
409 con->timeout = c->timeout; | |
410 strcpy(con->name, c->name); | |
411 con->h_pipe = CreateNamedPipe(con->name, | |
412 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, | |
413 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE
_WAIT, | |
414 con->nmax, | |
415 con->sndbuf, | |
416 con->rcvbuf, | |
417 con->timeout, | |
418 &c->sa); | |
419 if (con->h_pipe == INVALID_HANDLE_VALUE) { | |
420 tcn_ThrowAPRException(e, apr_get_os_error()); | |
421 goto cleanup; | |
422 } | |
423 /* Block until a client connects */ | |
424 if (!ConnectNamedPipe(con->h_pipe, NULL)) { | |
425 DWORD err = GetLastError(); | |
426 if (err != ERROR_PIPE_CONNECTED) { | |
427 CloseHandle(con->h_pipe); | |
428 tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(err)); | |
429 goto cleanup; | |
430 } | |
431 } | |
432 /* Create overlapped events */ | |
433 con->rd_event = CreateEvent(NULL, TRUE, FALSE, NULL); | |
434 con->rd_o.hEvent = con->rd_event; | |
435 con->wr_event = CreateEvent(NULL, TRUE, FALSE, NULL); | |
436 con->wr_o.hEvent = con->wr_event; | |
437 } | |
438 else { | |
439 tcn_ThrowAPRException(e, APR_ENOTIMPL); | |
440 goto cleanup; | |
441 } | |
442 if (con) { | |
443 #ifdef TCN_DO_STATISTICS | |
444 apr_atomic_inc32(&ntp_accepted); | |
445 #endif | |
446 a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t)); | |
447 a->pool = p; | |
448 a->net = &ntp_socket_layer; | |
449 a->opaque = con; | |
450 apr_pool_cleanup_register(p, (const void *)a, | |
451 ntp_socket_cleanup, | |
452 apr_pool_cleanup_null); | |
453 } | |
454 return P2J(a); | |
455 cleanup: | |
456 if (p) | |
457 apr_pool_destroy(p); | |
458 return 0; | |
459 } | |
460 | |
461 TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock, | |
462 jlong sa) | |
463 { | |
464 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
465 apr_pool_t *p = NULL; | |
466 tcn_socket_t *a = NULL; | |
467 tcn_ntp_conn_t *con = NULL; | |
468 | |
469 UNREFERENCED(o); | |
470 UNREFERENCED(sa); | |
471 TCN_ASSERT(sock != 0); | |
472 if (s->net->type != TCN_SOCKET_NTPIPE) | |
473 return APR_ENOTSOCK; | |
474 con = (tcn_ntp_conn_t *)s->opaque; | |
475 if (con->mode == TCN_NTP_SERVER) | |
476 return APR_EINVAL; | |
477 con->mode = TCN_NTP_CLIENT; | |
478 | |
479 while (TRUE) { | |
480 con->h_pipe = CreateFile(con->name, | |
481 GENERIC_WRITE | GENERIC_READ, | |
482 FILE_SHARE_READ | FILE_SHARE_WRITE , | |
483 NULL, | |
484 OPEN_EXISTING, | |
485 FILE_FLAG_OVERLAPPED, | |
486 NULL); | |
487 if (con->h_pipe != INVALID_HANDLE_VALUE) | |
488 break; | |
489 if (GetLastError() == ERROR_PIPE_BUSY) { | |
490 /* All pipe instances are busy, so wait for | |
491 * timeout value specified by the server process in | |
492 * the CreateNamedPipe function. | |
493 */ | |
494 if (!WaitNamedPipe(con->name, NMPWAIT_USE_DEFAULT_WAIT)) | |
495 return apr_get_os_error(); | |
496 } | |
497 else | |
498 return apr_get_os_error(); | |
499 } | |
500 | |
501 /* Create overlapped events */ | |
502 con->rd_event = CreateEvent(NULL, TRUE, FALSE, NULL); | |
503 con->rd_o.hEvent = con->rd_event; | |
504 con->wr_event = CreateEvent(NULL, TRUE, FALSE, NULL); | |
505 con->wr_o.hEvent = con->wr_event; | |
506 | |
507 return APR_SUCCESS; | |
508 } | |
509 | |
510 #endif | |
511 | |
OLD | NEW |