00001
00002
00003
00004
00005 static const char rcsid[] =
00006 "$Id: net.c,v 1.3 2007/02/12 08:32:27 tho Exp $";
00007
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <errno.h>
00011 #include <unistd.h>
00012 #include <string.h>
00013
00014 #include <toolbox/net.h>
00015 #include <toolbox/uri.h>
00016 #include <toolbox/carpal.h>
00017 #include <toolbox/misc.h>
00018 #include <toolbox/memory.h>
00019 #include <u/missing.h>
00020
00021 static int u_net_sock_tcp4 (u_net_addr_t *a, int mode);
00022 static int u_net_sock_tcp6 (u_net_addr_t *a, int mode);
00023
00055 int u_net_sock (const char *uri, int mode)
00056 {
00057 int sd = -1;
00058 u_net_addr_t *addr = NULL;
00059
00060 dbg_return_if (uri == NULL, -1);
00061 dbg_return_if (mode != U_NET_SSOCK && mode != U_NET_CSOCK, -1);
00062
00063 dbg_err_if (u_net_uri2addr(uri, &addr));
00064
00065 switch (addr->type)
00066 {
00067 case U_NET_TCP4:
00068 #ifndef NO_IPV6
00069 case U_NET_TCP6:
00070 #endif
00071 sd = u_net_sock_tcp(addr, mode);
00072 break;
00073 #ifndef NO_UNIXSOCK
00074 case U_NET_UNIX:
00075 sd = u_net_sock_unix(addr, mode);
00076 break;
00077 #endif
00078 case U_NET_UDP4:
00079 case U_NET_UDP6:
00080 default:
00081 warn_err("access method not implemented");
00082 }
00083
00084 dbg_if (sd == -1);
00085 u_net_addr_free(addr);
00086 return sd;
00087
00088 err:
00089 if (addr)
00090 u_net_addr_free(addr);
00091 return -1;
00092 }
00093
00094 static int u_net_sock_tcp4 (u_net_addr_t *a, int mode)
00095 {
00096 dbg_return_if (a == NULL, -1);
00097 dbg_return_if (a->type != U_NET_TCP4 && a->type != U_NET_TCP6, -1);
00098
00099 switch (mode)
00100 {
00101 case U_NET_CSOCK:
00102 return u_net_tcp4_csock(&a->sa.sin);
00103 case U_NET_SSOCK:
00104 return u_net_tcp4_ssock(&a->sa.sin, 0, U_NET_BACKLOG);
00105 default:
00106
00107 return -1;
00108 }
00109 }
00110
00111 #ifndef NO_IPV6
00112 static int u_net_sock_tcp6 (u_net_addr_t *a, int mode)
00113 {
00114 dbg_return_if (a == NULL, -1);
00115 dbg_return_if (a->type != U_NET_TCP4 && a->type != U_NET_TCP6, -1);
00116
00117 switch (mode)
00118 {
00119 case U_NET_CSOCK:
00120 return u_net_tcp6_csock(&a->sa.sin6);
00121 case U_NET_SSOCK:
00122 return u_net_tcp6_ssock(&a->sa.sin6, 0, U_NET_BACKLOG);
00123 default:
00124 warn("unknown socket mode");
00125 return -1;
00126 }
00127 }
00128 #endif
00129
00130 int u_net_sock_tcp (u_net_addr_t *a, int mode)
00131 {
00132 dbg_return_if (a == NULL, -1);
00133 dbg_return_if (a->type != U_NET_TCP4 && a->type != U_NET_TCP6, -1);
00134
00135 switch (a->type)
00136 {
00137 case U_NET_TCP4:
00138 return u_net_sock_tcp4(a, mode);
00139 #ifndef NO_IPV6
00140 case U_NET_TCP6:
00141 return u_net_sock_tcp6(a, mode);
00142 #endif
00143 default:
00144 warn("unknown or unsupported socket type");
00145 return -1;
00146 }
00147 }
00148
00149 #ifndef NO_UNIXSOCK
00150 int u_net_sock_unix (u_net_addr_t *a, int mode)
00151 {
00152 dbg_return_if (a == NULL, -1);
00153 dbg_return_if (a->type != U_NET_UNIX, -1);
00154
00155 switch (mode)
00156 {
00157 case U_NET_CSOCK:
00158 return u_net_unix_csock(&a->sa.sun);
00159 case U_NET_SSOCK:
00160 return u_net_unix_ssock(&a->sa.sun, U_NET_BACKLOG);
00161 default:
00162 warn("unknown socket mode");
00163 return -1;
00164 }
00165 }
00166
00167 int u_net_unix_csock (struct sockaddr_un *sad)
00168 {
00169 int rv, csd = -1;
00170
00171 dbg_return_if (sad == NULL, -1);
00172
00173 csd = socket(AF_UNIX, SOCK_STREAM, 0);
00174 dbg_err_if (csd == -1);
00175
00176 rv = connect(csd, (struct sockaddr *) sad, sizeof *sad);
00177 dbg_err_if (rv == -1);
00178
00179 return csd;
00180 err:
00181 dbg_strerror(errno);
00182 U_CLOSE(csd);
00183 return -1;
00184 }
00185
00186 int u_net_unix_ssock (struct sockaddr_un *sad, int backlog)
00187 {
00188 int rv, lsd = -1;
00189
00190 dbg_return_if (sad == NULL, -1);
00191
00192 rv = unlink(sad->sun_path);
00193 dbg_err_if (rv == -1 && errno != ENOENT);
00194
00195 lsd = socket(AF_UNIX, SOCK_STREAM, 0);
00196 dbg_err_if (lsd == -1);
00197
00198 rv = bind(lsd, (struct sockaddr *) sad, sizeof *sad);
00199 dbg_err_if (rv == -1);
00200
00201 rv = listen(lsd, backlog);
00202 dbg_err_if (rv == -1);
00203
00204 return lsd;
00205 err:
00206 dbg_strerror(errno);
00207 U_CLOSE(lsd);
00208 return -1;
00209 }
00210
00211 #endif
00212
00213 int u_net_sock_udp (u_net_addr_t *a, int mode)
00214 {
00215 dbg_return_if (a == NULL, -1);
00216 dbg_return_if (a->type != U_NET_UDP4 && a->type != U_NET_UDP6, -1);
00217 switch (mode) { default: break; }
00218 return -1;
00219 }
00220
00221 #ifndef NO_IPV6
00222 int u_net_tcp6_ssock (struct sockaddr_in6 *sad, int reuse, int backlog)
00223 {
00224 int rv, lsd = -1;
00225 int on = reuse ? 1 : 0;
00226
00227 dbg_return_if (sad == NULL, -1);
00228
00229 lsd = socket(AF_INET6, SOCK_STREAM, 0);
00230 dbg_err_if (lsd == -1);
00231
00232 rv = setsockopt(lsd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
00233 dbg_err_if (rv == -1);
00234
00235 rv = bind(lsd, (struct sockaddr *) sad, sizeof *sad);
00236 dbg_err_if (rv == -1);
00237
00238 rv = listen(lsd, backlog);
00239 dbg_err_if (rv == -1);
00240
00241 return lsd;
00242
00243 err:
00244 dbg_strerror(errno);
00245 U_CLOSE(lsd);
00246 return -1;
00247 }
00248
00249 int u_net_tcp6_csock (struct sockaddr_in6 *sad)
00250 {
00251 int csd = -1;
00252 int rv;
00253
00254 dbg_return_if (sad == NULL, -1);
00255
00256 csd = socket(AF_INET6, SOCK_STREAM, 0);
00257 dbg_err_if (csd == -1);
00258
00259 rv = connect(csd, (struct sockaddr *) sad, sizeof *sad);
00260 dbg_err_if (rv == -1);
00261
00262 return csd;
00263
00264 err:
00265 dbg_strerror(errno);
00266 U_CLOSE(csd);
00267 return -1;
00268 }
00269 #endif
00270
00271 int u_net_tcp4_ssock (struct sockaddr_in *sad, int reuse, int backlog)
00272 {
00273 int rv, lsd = -1;
00274 int on = reuse ? 1 : 0;
00275
00276 dbg_return_if (sad == NULL, -1);
00277
00278 lsd = socket(AF_INET, SOCK_STREAM, 0);
00279 dbg_err_if (lsd == -1);
00280
00281 rv = setsockopt(lsd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof on);
00282 dbg_err_if (rv == -1);
00283
00284 rv = bind(lsd, (struct sockaddr *) sad, sizeof *sad);
00285 dbg_err_if (rv == -1);
00286
00287 rv = listen(lsd, backlog);
00288 dbg_err_if (rv == -1);
00289
00290 return lsd;
00291
00292 err:
00293 dbg_strerror(errno);
00294 U_CLOSE(lsd);
00295 return -1;
00296 }
00297
00298 int u_net_tcp4_csock (struct sockaddr_in *sad)
00299 {
00300 int csd = -1;
00301
00302 dbg_return_if (sad == NULL, -1);
00303
00304 csd = socket(AF_INET, SOCK_STREAM, 0);
00305 dbg_err_if (csd == -1);
00306
00307 dbg_err_if (connect(csd, (struct sockaddr *) sad, sizeof *sad) == -1);
00308
00309 return csd;
00310
00311 err:
00312 dbg_strerror(errno);
00313 U_CLOSE(csd);
00314 return -1;
00315 }
00316
00317 int u_net_uri2addr (const char *uri, u_net_addr_t **pa)
00318 {
00319 u_uri_t *u = NULL;
00320 u_net_addr_t *a = NULL;
00321
00322 dbg_return_if (uri == NULL, ~0);
00323 dbg_return_if (pa == NULL, ~0);
00324
00325 *pa = NULL;
00326
00327 dbg_err_if (u_uri_parse(uri, &u));
00328
00329 if (!strcasecmp(u->scheme, "tcp4"))
00330 {
00331 dbg_err_if (u_net_addr_new(U_NET_TCP4, &a));
00332 dbg_err_if (u_net_uri2sin(u, &a->sa.sin));
00333 }
00334 #ifndef NO_UNIXSOCK
00335 else if (!strcasecmp(u->scheme, "unix"))
00336 {
00337 dbg_err_if (u_net_addr_new(U_NET_UNIX, &a));
00338 dbg_err_if (u_net_uri2sun(uri, &a->sa.sun));
00339 }
00340 #endif
00341 else
00342 warn_err("unsupported URI scheme: %s", u->scheme);
00343
00344 *pa = a;
00345 u_uri_free(u);
00346 return 0;
00347 err:
00348 if (a) u_net_addr_free(a);
00349 if (u) u_uri_free(u);
00350 return ~0;
00351 }
00352
00353 #ifndef NO_UNIXSOCK
00354 int u_net_uri2sun (const char *uri, struct sockaddr_un *sad)
00355 {
00356 dbg_return_if (uri == NULL, ~0);
00357 dbg_return_if (sad == NULL, ~0);
00358
00359 sad->sun_family = AF_UNIX;
00360 strlcpy(sad->sun_path, uri + strlen("unix://"), sizeof sad->sun_path);
00361
00362 return 0;
00363 }
00364 #endif
00365
00366 int u_net_addr_new (int type, u_net_addr_t **pa)
00367 {
00368 u_net_addr_t *a = NULL;
00369
00370 dbg_return_if (pa == NULL, ~0);
00371 dbg_return_if (type <= U_NET_TYPE_MIN || type >= U_NET_TYPE_MAX, ~0);
00372
00373 a = u_zalloc(sizeof(u_net_addr_t));
00374 dbg_err_if (a == NULL);
00375 a->type = type;
00376 *pa = a;
00377
00378 return 0;
00379
00380 err:
00381 if (a) u_net_addr_free(a);
00382 return ~0;
00383 }
00384
00385 void u_net_addr_free (u_net_addr_t *a)
00386 {
00387 U_FREE(a);
00388 return;
00389 }
00390
00391
00392 int u_net_uri2sin (u_uri_t *uri, struct sockaddr_in *sad)
00393 {
00394 struct hostent *hp = NULL;
00395 in_addr_t saddr;
00396
00397 dbg_return_if (uri == NULL, ~0);
00398 dbg_return_if (sad == NULL, ~0);
00399
00400 memset((char *) sad, 0, sizeof(struct sockaddr_in));
00401 sad->sin_port = htons(uri->port);
00402 sad->sin_family = AF_INET;
00403
00404 hp = gethostbyname(uri->host);
00405
00406 if (hp && hp->h_addrtype == AF_INET)
00407 memcpy(&sad->sin_addr.s_addr, hp->h_addr, sizeof(in_addr_t));
00408 else if ((saddr = inet_addr(uri->host)) != INADDR_NONE)
00409 sad->sin_addr.s_addr = saddr;
00410 else
00411 warn_err("invalid host name: \'%s\'", uri->host);
00412
00413 return 0;
00414 err:
00415 return ~0;
00416 }
00417
00418