nginx 0.4.11
[nginx-catap.git] / src / core / ngx_inet.c
blob6b2c2721f44772728698fa89bbbc9a734e7dee64
2 /*
3 * Copyright (C) Igor Sysoev
4 */
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10 #include <ngx_event_connect.h>
14 * ngx_sock_ntop() and ngx_inet_ntop() may be implemented as
15 * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", however,
16 * they had been implemented long before the ngx_sprintf() had appeared
17 * and they are faster by 1.5-2.5 times, so it is worth to keep them.
19 * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times
20 * than using FreeBSD libc's snprintf().
24 static ngx_inline size_t
25 ngx_sprint_uchar(u_char *text, u_char c, size_t len)
27 size_t n;
28 ngx_uint_t c1, c2;
30 n = 0;
32 if (len == n) {
33 return n;
36 c1 = c / 100;
38 if (c1) {
39 *text++ = (u_char) (c1 + '0');
40 n++;
42 if (len == n) {
43 return n;
47 c2 = (c % 100) / 10;
49 if (c1 || c2) {
50 *text++ = (u_char) (c2 + '0');
51 n++;
53 if (len == n) {
54 return n;
58 c2 = c % 10;
60 *text++ = (u_char) (c2 + '0');
61 n++;
63 return n;
67 /* AF_INET only */
69 size_t
70 ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len)
72 u_char *p;
73 size_t n;
74 ngx_uint_t i;
75 struct sockaddr_in *sin;
77 if (len == 0) {
78 return 0;
81 if (family != AF_INET) {
82 return 0;
85 sin = (struct sockaddr_in *) sa;
86 p = (u_char *) &sin->sin_addr;
88 if (len > INET_ADDRSTRLEN) {
89 len = INET_ADDRSTRLEN;
92 n = ngx_sprint_uchar(text, p[0], len);
94 i = 1;
96 do {
97 if (len == n) {
98 text[n - 1] = '\0';
99 return n;
102 text[n++] = '.';
104 if (len == n) {
105 text[n - 1] = '\0';
106 return n;
109 n += ngx_sprint_uchar(&text[n], p[i++], len - n);
111 } while (i < 4);
113 if (len == n) {
114 text[n] = '\0';
115 return n;
118 text[n] = '\0';
120 return n;
123 size_t
124 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
126 u_char *p;
127 size_t n;
128 ngx_uint_t i;
130 if (len == 0) {
131 return 0;
134 if (family != AF_INET) {
135 return 0;
138 p = (u_char *) addr;
140 if (len > INET_ADDRSTRLEN) {
141 len = INET_ADDRSTRLEN;
144 n = ngx_sprint_uchar(text, p[0], len);
146 i = 1;
148 do {
149 if (len == n) {
150 text[n - 1] = '\0';
151 return n;
154 text[n++] = '.';
156 if (len == n) {
157 text[n - 1] = '\0';
158 return n;
161 n += ngx_sprint_uchar(&text[n], p[i++], len - n);
163 } while (i < 4);
165 if (len == n) {
166 text[n] = '\0';
167 return n;
170 text[n] = '\0';
172 return n;
176 /* AF_INET only */
178 ngx_int_t
179 ngx_ptocidr(ngx_str_t *text, void *cidr)
181 ngx_int_t m;
182 ngx_uint_t i;
183 ngx_inet_cidr_t *in_cidr;
185 in_cidr = cidr;
187 for (i = 0; i < text->len; i++) {
188 if (text->data[i] == '/') {
189 break;
193 if (i == text->len) {
194 return NGX_ERROR;
197 text->data[i] = '\0';
198 in_cidr->addr = inet_addr((char *) text->data);
199 text->data[i] = '/';
200 if (in_cidr->addr == INADDR_NONE) {
201 return NGX_ERROR;
204 m = ngx_atoi(&text->data[i + 1], text->len - (i + 1));
205 if (m == NGX_ERROR) {
206 return NGX_ERROR;
209 if (m == 0) {
211 /* the x86 compilers use the shl instruction that shifts by modulo 32 */
213 in_cidr->mask = 0;
214 return NGX_OK;
217 in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - m))));
219 return NGX_OK;
223 ngx_int_t
224 ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u)
226 u_char *p, *host;
227 size_t len;
228 ngx_int_t port;
229 ngx_uint_t i;
230 struct hostent *h;
231 #if (NGX_HAVE_UNIX_DOMAIN)
232 struct sockaddr_un *saun;
233 #endif
235 len = u->url.len;
236 p = u->url.data;
238 if (ngx_strncasecmp(p, "unix:", 5) == 0) {
240 #if (NGX_HAVE_UNIX_DOMAIN)
242 u->type = NGX_PARSE_URL_UNIX;
244 p += 5;
245 len -= 5;
247 u->uri.len = len;
248 u->uri.data = p;
250 if (u->uri_part) {
251 for (i = 0; i < len; i++) {
253 if (p[i] == ':') {
254 len = i;
256 u->uri.len -= len + 1;
257 u->uri.data += len + 1;
259 break;
264 if (len == 0) {
265 u->err = "no path in the unix domain socket";
266 return NGX_ERROR;
269 if (len + 1 > sizeof(saun->sun_path)) {
270 u->err = "too long path in the unix domain socket";
271 return NGX_ERROR;
274 u->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t));
275 if (u->peers == NULL) {
276 return NGX_ERROR;
279 saun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un));
280 if (saun == NULL) {
281 return NGX_ERROR;
284 u->peers->number = 1;
286 saun->sun_family = AF_UNIX;
287 (void) ngx_cpystrn((u_char *) saun->sun_path, p, len + 1);
289 u->peers->peer[0].sockaddr = (struct sockaddr *) saun;
290 u->peers->peer[0].socklen = sizeof(struct sockaddr_un);
291 u->peers->peer[0].name.len = len + 5;
292 u->peers->peer[0].name.data = u->url.data;
293 u->peers->peer[0].uri_separator = ":";
295 u->host_header.len = sizeof("localhost") - 1;
296 u->host_header.data = (u_char *) "localhost";
298 return NGX_OK;
300 #else
301 u->err = "the unix domain sockets are not supported on this platform";
303 return NGX_ERROR;
305 #endif
308 if ((p[0] == ':' || p[0] == '/') && !u->listen) {
309 u->err = "invalid host";
310 return NGX_ERROR;
313 u->type = NGX_PARSE_URL_INET;
315 u->host.data = p;
316 u->host_header.len = len;
317 u->host_header.data = p;
319 for (i = 0; i < len; i++) {
321 if (p[i] == ':') {
322 u->port.data = &p[i + 1];
323 u->host.len = i;
325 if (!u->uri_part) {
326 u->port.len = &p[len] - u->port.data;
327 break;
331 if (p[i] == '/') {
332 u->uri.len = len - i;
333 u->uri.data = &p[i];
334 u->host_header.len = i;
336 if (u->host.len == 0) {
337 u->host.len = i;
340 if (u->port.data == NULL) {
341 u->default_port = 1;
342 goto port;
345 u->port.len = &p[i] - u->port.data;
347 if (u->port.len == 0) {
348 u->err = "invalid port";
349 return NGX_ERROR;
352 break;
356 if (u->port.data) {
358 if (u->port.len == 0) {
359 u->port.len = &p[i] - u->port.data;
361 if (u->port.len == 0) {
362 u->err = "invalid port";
363 return NGX_ERROR;
367 port = ngx_atoi(u->port.data, u->port.len);
369 if (port == NGX_ERROR || port < 1 || port > 65536) {
370 u->err = "invalid port";
371 return NGX_ERROR;
374 } else {
375 port = ngx_atoi(p, len);
377 if (port == NGX_ERROR) {
378 u->default_port = 1;
379 u->host.len = len;
381 goto port;
384 u->port.len = len;
385 u->port.data = p;
386 u->wildcard = 1;
389 u->portn = (in_port_t) port;
391 port:
393 if (u->listen) {
394 if (u->portn == 0) {
395 if (u->default_portn == 0) {
396 u->err = "no port";
397 return NGX_ERROR;
400 u->portn = u->default_portn;
403 if (u->host.len == 1 && u->host.data[0] == '*') {
404 u->host.len = 0;
407 /* AF_INET only */
409 if (u->host.len) {
411 host = ngx_palloc(cf->temp_pool, u->host.len + 1);
412 if (host == NULL) {
413 return NGX_ERROR;
416 (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
418 u->addr.in_addr = inet_addr((const char *) host);
420 if (u->addr.in_addr == INADDR_NONE) {
421 h = gethostbyname((const char *) host);
423 if (h == NULL || h->h_addr_list[0] == NULL) {
424 u->err = "host not found";
425 return NGX_ERROR;
428 u->addr.in_addr = *(in_addr_t *)(h->h_addr_list[0]);
431 } else {
432 u->addr.in_addr = INADDR_ANY;
435 return NGX_OK;
438 if (u->default_port) {
440 if (u->upstream) {
441 return NGX_OK;
444 if (u->default_portn == 0) {
445 u->err = "no port";
446 return NGX_ERROR;
449 u->portn = u->default_portn;
451 u->port.data = ngx_palloc(cf->pool, sizeof("65536") - 1);
452 if (u->port.data == NULL) {
453 return NGX_ERROR;
456 u->port.len = ngx_sprintf(u->port.data, "%d", u->portn) - u->port.data;
458 } else if (u->portn) {
459 if (u->portn == u->default_portn) {
460 u->default_port = 1;
463 } else {
464 u->err = "no port";
465 return NGX_ERROR;
468 if (u->host.len == 0) {
469 u->err = "no host";
470 return NGX_ERROR;
473 u->peers = ngx_inet_resolve_peer(cf, &u->host, u->portn);
475 if (u->peers == NULL) {
476 return NGX_ERROR;
479 if (u->peers == NGX_CONF_ERROR) {
480 u->err = "host not found";
481 return NGX_ERROR;
484 return NGX_OK;
488 ngx_peers_t *
489 ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, in_port_t port)
491 u_char *host;
492 size_t len;
493 in_addr_t in_addr;
494 ngx_uint_t i;
495 ngx_peers_t *peers;
496 struct hostent *h;
497 struct sockaddr_in *sin;
499 host = ngx_palloc(cf->temp_pool, name->len + 1);
500 if (host == NULL) {
501 return NULL;
504 (void) ngx_cpystrn(host, name->data, name->len + 1);
506 /* AF_INET only */
508 in_addr = inet_addr((char *) host);
510 if (in_addr == INADDR_NONE) {
511 h = gethostbyname((char *) host);
513 if (h == NULL || h->h_addr_list[0] == NULL) {
514 return NGX_CONF_ERROR;
517 for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
519 /* MP: ngx_shared_palloc() */
521 peers = ngx_pcalloc(cf->pool,
522 sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1));
523 if (peers == NULL) {
524 return NULL;
527 peers->number = i;
529 for (i = 0; h->h_addr_list[i] != NULL; i++) {
531 sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in));
532 if (sin == NULL) {
533 return NULL;
536 sin->sin_family = AF_INET;
537 sin->sin_port = htons(port);
538 sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
540 peers->peer[i].sockaddr = (struct sockaddr *) sin;
541 peers->peer[i].socklen = sizeof(struct sockaddr_in);
543 len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1;
545 peers->peer[i].name.data = ngx_palloc(cf->pool, len);
546 if (peers->peer[i].name.data == NULL) {
547 return NULL;
550 len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin,
551 peers->peer[i].name.data, len);
553 peers->peer[i].name.len =
554 ngx_sprintf(&peers->peer[i].name.data[len],
555 ":%d", port)
556 - peers->peer[i].name.data;
558 peers->peer[i].uri_separator = "";
560 peers->peer[i].weight = NGX_CONF_UNSET_UINT;
561 peers->peer[i].max_fails = NGX_CONF_UNSET_UINT;
562 peers->peer[i].fail_timeout = NGX_CONF_UNSET;
565 } else {
567 /* MP: ngx_shared_palloc() */
569 peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t));
570 if (peers == NULL) {
571 return NULL;
574 sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in));
575 if (sin == NULL) {
576 return NULL;
579 peers->number = 1;
581 sin->sin_family = AF_INET;
582 sin->sin_port = htons(port);
583 sin->sin_addr.s_addr = in_addr;
585 peers->peer[0].sockaddr = (struct sockaddr *) sin;
586 peers->peer[0].socklen = sizeof(struct sockaddr_in);
588 peers->peer[0].name.data = ngx_palloc(cf->pool,
589 name->len + sizeof(":65536") - 1);
590 if (peers->peer[0].name.data == NULL) {
591 return NULL;
594 peers->peer[0].name.len = ngx_sprintf(peers->peer[0].name.data, "%V:%d",
595 name, port)
596 - peers->peer[0].name.data;
598 peers->peer[0].uri_separator = "";
601 return peers;