| 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 |