OLD | NEW |
| (Empty) |
1 #ifndef _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 /** UNIX AF_LOCAL network wrapper | |
20 * | |
21 * @author Mladen Turk | |
22 * @version $Id: uxpipe.c 1442587 2013-02-05 13:49:48Z rjung $ | |
23 */ | |
24 | |
25 | |
26 #include "tcn.h" | |
27 #include "apr_thread_mutex.h" | |
28 #include "apr_poll.h" | |
29 | |
30 /* ### should be tossed in favor of APR */ | |
31 #include <sys/stat.h> | |
32 #include <sys/un.h> /* for sockaddr_un */ | |
33 | |
34 #ifdef TCN_DO_STATISTICS | |
35 #include "apr_atomic.h" | |
36 | |
37 static volatile apr_uint32_t uxp_created = 0; | |
38 static volatile apr_uint32_t uxp_closed = 0; | |
39 static volatile apr_uint32_t uxp_cleared = 0; | |
40 static volatile apr_uint32_t uxp_accepted = 0; | |
41 | |
42 void uxp_network_dump_statistics() | |
43 { | |
44 fprintf(stderr, "NT Network Statistics ..\n"); | |
45 fprintf(stderr, "Sockets created : %d\n", uxp_created); | |
46 fprintf(stderr, "Sockets accepted : %d\n", uxp_accepted); | |
47 fprintf(stderr, "Sockets closed : %d\n", uxp_closed); | |
48 fprintf(stderr, "Sockets cleared : %d\n", uxp_cleared); | |
49 } | |
50 | |
51 #endif | |
52 | |
53 #define DEFNAME "/var/run/tomcatnativesock" | |
54 #define DEFNAME_FMT "/var/run/tomcatnativesock%08x%08x" | |
55 #define DEFSIZE 8192 | |
56 #define DEFTIMEOUT 60000 | |
57 | |
58 #define TCN_UXP_UNKNOWN 0 | |
59 #define TCN_UXP_CLIENT 1 | |
60 #define TCN_UXP_ACCEPTED 2 | |
61 #define TCN_UXP_SERVER 3 | |
62 | |
63 #define TCN_UNIX_MAXPATH 1024 | |
64 typedef struct { | |
65 apr_pool_t *pool; | |
66 apr_socket_t *sock; /* APR socket */ | |
67 int sd; | |
68 struct sockaddr_un uxaddr; | |
69 int timeout; | |
70 int mode; /* Client or server mode */ | |
71 char name[TCN_UNIX_MAXPATH+1]; | |
72 } tcn_uxp_conn_t; | |
73 | |
74 static apr_status_t APR_THREAD_FUNC | |
75 uxp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) | |
76 { | |
77 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
78 if (t < 0) | |
79 con->timeout = -1; | |
80 else | |
81 con->timeout = (int)(apr_time_as_msec(t)); | |
82 return APR_SUCCESS; | |
83 } | |
84 | |
85 static apr_status_t APR_THREAD_FUNC | |
86 uxp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) | |
87 { | |
88 tcn_uxp_conn_t *con = (tcn_uxp_conn_t*)sock; | |
89 if (con->timeout < 0) | |
90 *t = -1; | |
91 else | |
92 *t = con->timeout * 1000; | |
93 return APR_SUCCESS; | |
94 } | |
95 | |
96 static APR_INLINE apr_status_t APR_THREAD_FUNC | |
97 uxp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on) | |
98 { | |
99 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
100 return apr_socket_opt_set(con->sock, opt, on); | |
101 } | |
102 | |
103 static APR_INLINE apr_status_t APR_THREAD_FUNC | |
104 uxp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on) | |
105 { | |
106 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
107 return apr_socket_opt_get(con->sock, opt, on); | |
108 } | |
109 | |
110 static apr_status_t uxp_cleanup(void *data) | |
111 { | |
112 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)data; | |
113 | |
114 if (con) { | |
115 if (con->sock) { | |
116 apr_socket_close(con->sock); | |
117 con->sock = NULL; | |
118 } | |
119 if (con->mode == TCN_UXP_SERVER) { | |
120 unlink(con->name); | |
121 con->mode = TCN_UXP_UNKNOWN; | |
122 } | |
123 } | |
124 | |
125 #ifdef TCN_DO_STATISTICS | |
126 apr_atomic_inc32(&uxp_cleared); | |
127 #endif | |
128 return APR_SUCCESS; | |
129 } | |
130 | |
131 static apr_status_t APR_THREAD_FUNC | |
132 uxp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how) | |
133 { | |
134 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
135 return apr_socket_shutdown(con->sock, how); | |
136 } | |
137 | |
138 static apr_status_t APR_THREAD_FUNC | |
139 uxp_socket_close(apr_socket_t *sock) | |
140 { | |
141 #ifdef TCN_DO_STATISTICS | |
142 apr_atomic_inc32(&uxp_closed); | |
143 #endif | |
144 return uxp_cleanup(sock); | |
145 } | |
146 | |
147 static apr_status_t APR_THREAD_FUNC | |
148 uxp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) | |
149 { | |
150 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
151 return apr_socket_recv(con->sock, buf, len); | |
152 } | |
153 | |
154 | |
155 static apr_status_t APR_THREAD_FUNC | |
156 uxp_socket_send(apr_socket_t *sock, const char *buf, | |
157 apr_size_t *len) | |
158 { | |
159 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
160 return apr_socket_send(con->sock, buf, len); | |
161 } | |
162 | |
163 static apr_status_t APR_THREAD_FUNC | |
164 uxp_socket_sendv(apr_socket_t *sock, | |
165 const struct iovec *vec, | |
166 apr_int32_t nvec, apr_size_t *len) | |
167 { | |
168 tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock; | |
169 return apr_socket_sendv(con->sock, vec, nvec, len); | |
170 } | |
171 | |
172 static apr_status_t uxp_socket_cleanup(void *data) | |
173 { | |
174 tcn_socket_t *s = (tcn_socket_t *)data; | |
175 | |
176 if (s->net->cleanup) { | |
177 (*s->net->cleanup)(s->opaque); | |
178 s->net->cleanup = NULL; | |
179 } | |
180 #ifdef TCN_DO_STATISTICS | |
181 apr_atomic_inc32(&uxp_cleared); | |
182 #endif | |
183 return APR_SUCCESS; | |
184 } | |
185 | |
186 static tcn_nlayer_t uxp_socket_layer = { | |
187 TCN_SOCKET_UNIX, | |
188 uxp_cleanup, | |
189 uxp_socket_close, | |
190 uxp_socket_shutdown, | |
191 uxp_socket_opt_get, | |
192 uxp_socket_opt_set, | |
193 uxp_socket_timeout_get, | |
194 uxp_socket_timeout_set, | |
195 uxp_socket_send, | |
196 uxp_socket_sendv, | |
197 uxp_socket_recv | |
198 }; | |
199 | |
200 TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name, | |
201 jlong pool) | |
202 { | |
203 apr_pool_t *p = J2P(pool, apr_pool_t *); | |
204 tcn_socket_t *s = NULL; | |
205 tcn_uxp_conn_t *con = NULL; | |
206 int sd; | |
207 TCN_ALLOC_CSTRING(name); | |
208 | |
209 UNREFERENCED(o); | |
210 TCN_ASSERT(pool != 0); | |
211 | |
212 if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { | |
213 tcn_ThrowAPRException(e, apr_get_netos_error()); | |
214 return 0; | |
215 } | |
216 #ifdef TCN_DO_STATISTICS | |
217 uxp_created++; | |
218 #endif | |
219 con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t)); | |
220 con->pool = p; | |
221 con->mode = TCN_UXP_UNKNOWN; | |
222 con->timeout = DEFTIMEOUT; | |
223 con->sd = sd; | |
224 con->uxaddr.sun_family = AF_UNIX; | |
225 if (J2S(name)) { | |
226 strcpy(con->uxaddr.sun_path, J2S(name)); | |
227 TCN_FREE_CSTRING(name); | |
228 } | |
229 else | |
230 strcpy(con->uxaddr.sun_path, DEFNAME); | |
231 s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t)); | |
232 s->pool = p; | |
233 s->net = &uxp_socket_layer; | |
234 s->opaque = con; | |
235 apr_pool_cleanup_register(p, (const void *)s, | |
236 uxp_socket_cleanup, | |
237 apr_pool_cleanup_null); | |
238 | |
239 apr_os_sock_put(&(con->sock), &(con->sd), p); | |
240 | |
241 return P2J(s); | |
242 | |
243 } | |
244 | |
245 TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock, | |
246 jlong sa) | |
247 { | |
248 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
249 UNREFERENCED_STDARGS; | |
250 UNREFERENCED(sa); | |
251 TCN_ASSERT(sock != 0); | |
252 if (s->net->type == TCN_SOCKET_UNIX) { | |
253 int rc; | |
254 tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque; | |
255 c->mode = TCN_UXP_SERVER; | |
256 rc = bind(c->sd, (struct sockaddr *)&(c->uxaddr), sizeof(c->uxaddr)); | |
257 if (rc < 0) | |
258 return errno; | |
259 else | |
260 return APR_SUCCESS; | |
261 } | |
262 else | |
263 return APR_EINVAL; | |
264 } | |
265 | |
266 TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock, | |
267 jint backlog) | |
268 { | |
269 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
270 UNREFERENCED_STDARGS; | |
271 | |
272 TCN_ASSERT(sock != 0); | |
273 if (s->net->type == TCN_SOCKET_UNIX) { | |
274 tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque; | |
275 c->mode = TCN_UXP_SERVER; | |
276 return apr_socket_listen(c->sock, (apr_int32_t)backlog); | |
277 } | |
278 else | |
279 return APR_EINVAL; | |
280 } | |
281 | |
282 TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock) | |
283 { | |
284 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
285 apr_pool_t *p = NULL; | |
286 tcn_socket_t *a = NULL; | |
287 tcn_uxp_conn_t *con = NULL; | |
288 | |
289 UNREFERENCED(o); | |
290 TCN_ASSERT(sock != 0); | |
291 | |
292 TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p); | |
293 if (s->net->type == TCN_SOCKET_UNIX) { | |
294 apr_socklen_t len; | |
295 tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque; | |
296 con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t)); | |
297 con->pool = p; | |
298 con->mode = TCN_UXP_ACCEPTED; | |
299 con->timeout = c->timeout; | |
300 len = sizeof(c->uxaddr); | |
301 /* Block until a client connects */ | |
302 con->sd = accept(c->sd, (struct sockaddr *)&(con->uxaddr), &len); | |
303 if (con->sd < 0) { | |
304 tcn_ThrowAPRException(e, apr_get_os_error()); | |
305 goto cleanup; | |
306 } | |
307 } | |
308 else { | |
309 tcn_ThrowAPRException(e, APR_ENOTIMPL); | |
310 goto cleanup; | |
311 } | |
312 if (con) { | |
313 #ifdef TCN_DO_STATISTICS | |
314 apr_atomic_inc32(&uxp_accepted); | |
315 #endif | |
316 a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t)); | |
317 a->pool = p; | |
318 a->net = &uxp_socket_layer; | |
319 a->opaque = con; | |
320 apr_pool_cleanup_register(p, (const void *)a, | |
321 uxp_socket_cleanup, | |
322 apr_pool_cleanup_null); | |
323 apr_os_sock_put(&(con->sock), &(con->sd), p); | |
324 } | |
325 return P2J(a); | |
326 cleanup: | |
327 if (p) | |
328 apr_pool_destroy(p); | |
329 return 0; | |
330 } | |
331 | |
332 TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock, | |
333 jlong sa) | |
334 { | |
335 tcn_socket_t *s = J2P(sock, tcn_socket_t *); | |
336 tcn_uxp_conn_t *con = NULL; | |
337 int rc; | |
338 | |
339 UNREFERENCED(o); | |
340 UNREFERENCED(sa); | |
341 TCN_ASSERT(sock != 0); | |
342 if (s->net->type != TCN_SOCKET_UNIX) | |
343 return APR_ENOTSOCK; | |
344 con = (tcn_uxp_conn_t *)s->opaque; | |
345 if (con->mode != TCN_UXP_UNKNOWN) | |
346 return APR_EINVAL; | |
347 do { | |
348 rc = connect(con->sd, (const struct sockaddr *)&(con->uxaddr), | |
349 sizeof(con->uxaddr)); | |
350 } while (rc == -1 && errno == EINTR); | |
351 | |
352 if (rc == -1 && errno != EISCONN) | |
353 return errno; | |
354 con->mode = TCN_UXP_CLIENT; | |
355 | |
356 return APR_SUCCESS; | |
357 } | |
358 | |
359 #endif | |
360 | |
OLD | NEW |