comparison src/core/ngx_resolver.c @ 6367:5a16d40c63de

Resolver: TCP support. Resend DNS query over TCP once UDP response came truncated.
author Roman Arutyunyan <arut@nginx.com>
date Thu, 28 Jan 2016 15:28:20 +0300
parents 2e5c027f2a98
children d73f77bb5caf
comparison
equal deleted inserted replaced
6366:2e5c027f2a98 6367:5a16d40c63de
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_event.h> 10 #include <ngx_event.h>
11 11
12 12
13 #define NGX_RESOLVER_UDP_SIZE 4096 13 #define NGX_RESOLVER_UDP_SIZE 4096
14
15 #define NGX_RESOLVER_TCP_RSIZE (2 + 65535)
16 #define NGX_RESOLVER_TCP_WSIZE 8192
14 17
15 18
16 typedef struct { 19 typedef struct {
17 u_char ident_hi; 20 u_char ident_hi;
18 u_char ident_lo; 21 u_char ident_lo;
52 (ngx_resolver_node_t *) \ 55 (ngx_resolver_node_t *) \
53 ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) 56 ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
54 57
55 58
56 ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); 59 ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec);
60 ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec);
57 61
58 62
59 static void ngx_resolver_cleanup(void *data); 63 static void ngx_resolver_cleanup(void *data);
60 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); 64 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
61 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, 65 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
62 ngx_resolver_ctx_t *ctx, ngx_str_t *name); 66 ngx_resolver_ctx_t *ctx, ngx_str_t *name);
63 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, 67 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
64 ngx_queue_t *queue); 68 ngx_queue_t *queue);
65 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, 69 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
66 ngx_resolver_node_t *rn); 70 ngx_resolver_node_t *rn);
71 static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r,
72 ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
73 static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r,
74 ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
67 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, 75 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
68 ngx_resolver_node_t *rn, ngx_str_t *name); 76 ngx_resolver_node_t *rn, ngx_str_t *name);
69 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, 77 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
70 ngx_resolver_node_t *rn, ngx_addr_t *addr); 78 ngx_resolver_node_t *rn, ngx_addr_t *addr);
71 static void ngx_resolver_resend_handler(ngx_event_t *ev); 79 static void ngx_resolver_resend_handler(ngx_event_t *ev);
72 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, 80 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
73 ngx_queue_t *queue); 81 ngx_queue_t *queue);
74 static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r); 82 static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r);
75 static void ngx_resolver_read_response(ngx_event_t *rev); 83 static void ngx_resolver_udp_read(ngx_event_t *rev);
84 static void ngx_resolver_tcp_write(ngx_event_t *wev);
85 static void ngx_resolver_tcp_read(ngx_event_t *rev);
76 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, 86 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
77 size_t n); 87 size_t n, ngx_uint_t tcp);
78 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, 88 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
79 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, 89 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
80 ngx_uint_t nan, ngx_uint_t ans); 90 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans);
81 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, 91 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
82 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); 92 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
83 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, 93 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
84 ngx_str_t *name, uint32_t hash); 94 ngx_str_t *name, uint32_t hash);
85 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r, 95 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
163 r->event->data = r; 173 r->event->data = r;
164 r->event->log = &cf->cycle->new_log; 174 r->event->log = &cf->cycle->new_log;
165 r->ident = -1; 175 r->ident = -1;
166 176
167 r->resend_timeout = 5; 177 r->resend_timeout = 5;
178 r->tcp_timeout = 5;
168 r->expire = 30; 179 r->expire = 30;
169 r->valid = 0; 180 r->valid = 0;
170 181
171 r->log = &cf->cycle->new_log; 182 r->log = &cf->cycle->new_log;
172 r->log_level = NGX_LOG_ERR; 183 r->log_level = NGX_LOG_ERR;
239 250
240 for (j = 0; j < u.naddrs; j++) { 251 for (j = 0; j < u.naddrs; j++) {
241 rec[j].sockaddr = u.addrs[j].sockaddr; 252 rec[j].sockaddr = u.addrs[j].sockaddr;
242 rec[j].socklen = u.addrs[j].socklen; 253 rec[j].socklen = u.addrs[j].socklen;
243 rec[j].server = u.addrs[j].name; 254 rec[j].server = u.addrs[j].name;
255 rec[j].resolver = r;
244 } 256 }
245 } 257 }
246 258
247 return r; 259 return r;
248 } 260 }
276 rec = r->connections.elts; 288 rec = r->connections.elts;
277 289
278 for (i = 0; i < r->connections.nelts; i++) { 290 for (i = 0; i < r->connections.nelts; i++) {
279 if (rec[i].udp) { 291 if (rec[i].udp) {
280 ngx_close_connection(rec[i].udp); 292 ngx_close_connection(rec[i].udp);
293 }
294
295 if (rec[i].tcp) {
296 ngx_close_connection(rec[i].tcp);
281 } 297 }
282 } 298 }
283 299
284 ngx_free(r); 300 ngx_free(r);
285 } 301 }
689 if (r->last_connection == r->connections.nelts) { 705 if (r->last_connection == r->connections.nelts) {
690 r->last_connection = 0; 706 r->last_connection = 0;
691 } 707 }
692 708
693 rn->naddrs = (u_short) -1; 709 rn->naddrs = (u_short) -1;
710 rn->tcp = 0;
694 #if (NGX_HAVE_INET6) 711 #if (NGX_HAVE_INET6)
695 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; 712 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
713 rn->tcp6 = 0;
696 #endif 714 #endif
697 715
698 if (ngx_resolver_send_query(r, rn) != NGX_OK) { 716 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
699 goto failed; 717 goto failed;
700 } 718 }
906 if (r->last_connection == r->connections.nelts) { 924 if (r->last_connection == r->connections.nelts) {
907 r->last_connection = 0; 925 r->last_connection = 0;
908 } 926 }
909 927
910 rn->naddrs = (u_short) -1; 928 rn->naddrs = (u_short) -1;
929 rn->tcp = 0;
911 #if (NGX_HAVE_INET6) 930 #if (NGX_HAVE_INET6)
912 rn->naddrs6 = (u_short) -1; 931 rn->naddrs6 = (u_short) -1;
932 rn->tcp6 = 0;
913 #endif 933 #endif
914 934
915 if (ngx_resolver_send_query(r, rn) != NGX_OK) { 935 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
916 goto failed; 936 goto failed;
917 } 937 }
1102 1122
1103 1123
1104 static ngx_int_t 1124 static ngx_int_t
1105 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) 1125 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1106 { 1126 {
1107 ssize_t n; 1127 ngx_int_t rc;
1108 ngx_resolver_connection_t *rec; 1128 ngx_resolver_connection_t *rec;
1109 1129
1110 rec = r->connections.elts; 1130 rec = r->connections.elts;
1111 rec = &rec[rn->last_connection]; 1131 rec = &rec[rn->last_connection];
1112 1132
1113 if (rec->udp == NULL) { 1133 if (rec->log.handler == NULL) {
1114
1115 rec->log = *r->log; 1134 rec->log = *r->log;
1116 rec->log.handler = ngx_resolver_log_error; 1135 rec->log.handler = ngx_resolver_log_error;
1117 rec->log.data = rec; 1136 rec->log.data = rec;
1118 rec->log.action = "resolving"; 1137 rec->log.action = "resolving";
1119 1138 }
1139
1140 if (rn->naddrs == (u_short) -1) {
1141 rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen)
1142 : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen);
1143
1144 if (rc != NGX_OK) {
1145 return rc;
1146 }
1147 }
1148
1149 #if (NGX_HAVE_INET6)
1150
1151 if (rn->query6 && rn->naddrs6 == (u_short) -1) {
1152 rc = rn->tcp6
1153 ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen)
1154 : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen);
1155
1156 if (rc != NGX_OK) {
1157 return rc;
1158 }
1159 }
1160
1161 #endif
1162
1163 return NGX_OK;
1164 }
1165
1166
1167 static ngx_int_t
1168 ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1169 u_char *query, u_short qlen)
1170 {
1171 ssize_t n;
1172
1173 if (rec->udp == NULL) {
1120 if (ngx_udp_connect(rec) != NGX_OK) { 1174 if (ngx_udp_connect(rec) != NGX_OK) {
1121 return NGX_ERROR; 1175 return NGX_ERROR;
1122 } 1176 }
1123 1177
1124 rec->udp->data = r; 1178 rec->udp->data = rec;
1125 rec->udp->read->handler = ngx_resolver_read_response; 1179 rec->udp->read->handler = ngx_resolver_udp_read;
1126 rec->udp->read->resolver = 1; 1180 rec->udp->read->resolver = 1;
1127 } 1181 }
1128 1182
1129 if (rn->naddrs == (u_short) -1) { 1183 n = ngx_send(rec->udp, query, qlen);
1130 n = ngx_send(rec->udp, rn->query, rn->qlen); 1184
1131 1185 if (n == -1) {
1132 if (n == -1) { 1186 return NGX_ERROR;
1187 }
1188
1189 if ((size_t) n != (size_t) qlen) {
1190 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete");
1191 return NGX_ERROR;
1192 }
1193
1194 return NGX_OK;
1195 }
1196
1197
1198 static ngx_int_t
1199 ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1200 u_char *query, u_short qlen)
1201 {
1202 ngx_buf_t *b;
1203 ngx_int_t rc;
1204
1205 rc = NGX_OK;
1206
1207 if (rec->tcp == NULL) {
1208 b = rec->read_buf;
1209
1210 if (b == NULL) {
1211 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1212 if (b == NULL) {
1213 return NGX_ERROR;
1214 }
1215
1216 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE);
1217 if (b->start == NULL) {
1218 return NGX_ERROR;
1219 }
1220
1221 b->end = b->start + NGX_RESOLVER_TCP_RSIZE;
1222
1223 rec->read_buf = b;
1224 }
1225
1226 b->pos = b->start;
1227 b->last = b->start;
1228
1229 b = rec->write_buf;
1230
1231 if (b == NULL) {
1232 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1233 if (b == NULL) {
1234 return NGX_ERROR;
1235 }
1236
1237 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE);
1238 if (b->start == NULL) {
1239 return NGX_ERROR;
1240 }
1241
1242 b->end = b->start + NGX_RESOLVER_TCP_WSIZE;
1243
1244 rec->write_buf = b;
1245 }
1246
1247 b->pos = b->start;
1248 b->last = b->start;
1249
1250 rc = ngx_tcp_connect(rec);
1251 if (rc == NGX_ERROR) {
1133 return NGX_ERROR; 1252 return NGX_ERROR;
1134 } 1253 }
1135 1254
1136 if ((size_t) n != (size_t) rn->qlen) { 1255 rec->tcp->data = rec;
1137 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); 1256 rec->tcp->write->handler = ngx_resolver_tcp_write;
1138 return NGX_ERROR; 1257 rec->tcp->read->handler = ngx_resolver_tcp_read;
1139 } 1258 rec->tcp->read->resolver = 1;
1140 } 1259
1141 1260 ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000));
1142 #if (NGX_HAVE_INET6) 1261 }
1143 if (rn->query6 && rn->naddrs6 == (u_short) -1) { 1262
1144 n = ngx_send(rec->udp, rn->query6, rn->qlen); 1263 b = rec->write_buf;
1145 1264
1146 if (n == -1) { 1265 if (b->end - b->last < 2 + qlen) {
1147 return NGX_ERROR; 1266 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow");
1148 } 1267 return NGX_ERROR;
1149 1268 }
1150 if ((size_t) n != (size_t) rn->qlen) { 1269
1151 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); 1270 *b->last++ = (u_char) (qlen >> 8);
1152 return NGX_ERROR; 1271 *b->last++ = (u_char) qlen;
1153 } 1272 b->last = ngx_cpymem(b->last, query, qlen);
1154 } 1273
1155 #endif 1274 if (rc == NGX_OK) {
1275 ngx_resolver_tcp_write(rec->tcp->write);
1276 }
1156 1277
1157 return NGX_OK; 1278 return NGX_OK;
1158 } 1279 }
1159 1280
1160 1281
1280 && ngx_queue_empty(&r->addr_resend_queue); 1401 && ngx_queue_empty(&r->addr_resend_queue);
1281 } 1402 }
1282 1403
1283 1404
1284 static void 1405 static void
1285 ngx_resolver_read_response(ngx_event_t *rev) 1406 ngx_resolver_udp_read(ngx_event_t *rev)
1286 { 1407 {
1287 ssize_t n; 1408 ssize_t n;
1288 ngx_connection_t *c; 1409 ngx_connection_t *c;
1289 u_char buf[NGX_RESOLVER_UDP_SIZE]; 1410 ngx_resolver_connection_t *rec;
1411 u_char buf[NGX_RESOLVER_UDP_SIZE];
1290 1412
1291 c = rev->data; 1413 c = rev->data;
1414 rec = c->data;
1292 1415
1293 do { 1416 do {
1294 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); 1417 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
1295 1418
1296 if (n < 0) { 1419 if (n < 0) {
1297 return; 1420 return;
1298 } 1421 }
1299 1422
1300 ngx_resolver_process_response(c->data, buf, n); 1423 ngx_resolver_process_response(rec->resolver, buf, n, 0);
1301 1424
1302 } while (rev->ready); 1425 } while (rev->ready);
1303 } 1426 }
1304 1427
1305 1428
1306 static void 1429 static void
1307 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n) 1430 ngx_resolver_tcp_write(ngx_event_t *wev)
1431 {
1432 off_t sent;
1433 ssize_t n;
1434 ngx_buf_t *b;
1435 ngx_resolver_t *r;
1436 ngx_connection_t *c;
1437 ngx_resolver_connection_t *rec;
1438
1439 c = wev->data;
1440 rec = c->data;
1441 b = rec->write_buf;
1442 r = rec->resolver;
1443
1444 if (wev->timedout) {
1445 goto failed;
1446 }
1447
1448 sent = c->sent;
1449
1450 while (wev->ready && b->pos < b->last) {
1451 n = ngx_send(c, b->pos, b->last - b->pos);
1452
1453 if (n == NGX_AGAIN) {
1454 break;
1455 }
1456
1457 if (n == NGX_ERROR) {
1458 goto failed;
1459 }
1460
1461 b->pos += n;
1462 }
1463
1464 if (b->pos != b->start) {
1465 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1466 b->pos = b->start;
1467 }
1468
1469 if (c->sent != sent) {
1470 ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000));
1471 }
1472
1473 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
1474 goto failed;
1475 }
1476
1477 return;
1478
1479 failed:
1480
1481 ngx_close_connection(c);
1482 rec->tcp = NULL;
1483 }
1484
1485
1486 static void
1487 ngx_resolver_tcp_read(ngx_event_t *rev)
1488 {
1489 u_char *p;
1490 size_t size;
1491 ssize_t n;
1492 u_short qlen;
1493 ngx_buf_t *b;
1494 ngx_resolver_t *r;
1495 ngx_connection_t *c;
1496 ngx_resolver_connection_t *rec;
1497
1498 c = rev->data;
1499 rec = c->data;
1500 b = rec->read_buf;
1501 r = rec->resolver;
1502
1503 while (rev->ready) {
1504 n = ngx_recv(c, b->last, b->end - b->last);
1505
1506 if (n == NGX_AGAIN) {
1507 break;
1508 }
1509
1510 if (n == NGX_ERROR || n == 0) {
1511 goto failed;
1512 }
1513
1514 b->last += n;
1515
1516 for ( ;; ) {
1517 p = b->pos;
1518 size = b->last - p;
1519
1520 if (size < 2) {
1521 break;
1522 }
1523
1524 qlen = (u_short) *p++ << 8;
1525 qlen += *p++;
1526
1527 if (size < (size_t) (2 + qlen)) {
1528 break;
1529 }
1530
1531 ngx_resolver_process_response(r, p, qlen, 1);
1532
1533 b->pos += 2 + qlen;
1534 }
1535
1536 if (b->pos != b->start) {
1537 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1538 b->pos = b->start;
1539 }
1540 }
1541
1542 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1543 goto failed;
1544 }
1545
1546 return;
1547
1548 failed:
1549
1550 ngx_close_connection(c);
1551 rec->tcp = NULL;
1552 }
1553
1554
1555 static void
1556 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n,
1557 ngx_uint_t tcp)
1308 { 1558 {
1309 char *err; 1559 char *err;
1310 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, 1560 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc,
1311 qtype, qclass; 1561 qtype, qclass;
1312 #if (NGX_HAVE_INET6) 1562 #if (NGX_HAVE_INET6)
1313 ngx_uint_t qident6; 1563 ngx_uint_t qident6;
1314 #endif 1564 #endif
1315 ngx_queue_t *q; 1565 ngx_queue_t *q;
1325 1575
1326 ident = (response->ident_hi << 8) + response->ident_lo; 1576 ident = (response->ident_hi << 8) + response->ident_lo;
1327 flags = (response->flags_hi << 8) + response->flags_lo; 1577 flags = (response->flags_hi << 8) + response->flags_lo;
1328 nqs = (response->nqs_hi << 8) + response->nqs_lo; 1578 nqs = (response->nqs_hi << 8) + response->nqs_lo;
1329 nan = (response->nan_hi << 8) + response->nan_lo; 1579 nan = (response->nan_hi << 8) + response->nan_lo;
1580 trunc = flags & 0x0200;
1330 1581
1331 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, 1582 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
1332 "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud", 1583 "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud",
1333 ident, flags, nqs, nan, 1584 ident, flags, nqs, nan,
1334 (response->nns_hi << 8) + response->nns_lo, 1585 (response->nns_hi << 8) + response->nns_lo,
1335 (response->nar_hi << 8) + response->nar_lo); 1586 (response->nar_hi << 8) + response->nar_lo);
1336 1587
1337 /* response to a standard query */ 1588 /* response to a standard query */
1338 if ((flags & 0xf870) != 0x8000) { 1589 if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) {
1339 ngx_log_error(r->log_level, r->log, 0, 1590 ngx_log_error(r->log_level, r->log, 0,
1340 "invalid DNS response %ui fl:%04Xui", ident, flags); 1591 "invalid %s DNS response %ui fl:%04Xui",
1592 tcp ? "TCP" : "UDP", ident, flags);
1341 return; 1593 return;
1342 } 1594 }
1343 1595
1344 code = flags & 0xf; 1596 code = flags & 0xf;
1345 1597
1425 case NGX_RESOLVE_A: 1677 case NGX_RESOLVE_A:
1426 #if (NGX_HAVE_INET6) 1678 #if (NGX_HAVE_INET6)
1427 case NGX_RESOLVE_AAAA: 1679 case NGX_RESOLVE_AAAA:
1428 #endif 1680 #endif
1429 1681
1430 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, 1682 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc,
1431 i + sizeof(ngx_resolver_qs_t)); 1683 i + sizeof(ngx_resolver_qs_t));
1432 1684
1433 break; 1685 break;
1434 1686
1435 case NGX_RESOLVE_PTR: 1687 case NGX_RESOLVE_PTR:
1474 1726
1475 1727
1476 static void 1728 static void
1477 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, 1729 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
1478 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, 1730 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
1479 ngx_uint_t nan, ngx_uint_t ans) 1731 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans)
1480 { 1732 {
1481 char *err; 1733 char *err;
1482 u_char *cname; 1734 u_char *cname;
1483 size_t len; 1735 size_t len;
1484 int32_t ttl; 1736 int32_t ttl;
1485 uint32_t hash; 1737 uint32_t hash;
1486 in_addr_t *addr; 1738 in_addr_t *addr;
1487 ngx_str_t name; 1739 ngx_str_t name;
1488 ngx_addr_t *addrs; 1740 ngx_addr_t *addrs;
1489 ngx_uint_t type, class, qident, naddrs, a, i, n, start; 1741 ngx_uint_t type, class, qident, naddrs, a, i, n, start;
1490 #if (NGX_HAVE_INET6) 1742 #if (NGX_HAVE_INET6)
1491 struct in6_addr *addr6; 1743 struct in6_addr *addr6;
1492 #endif 1744 #endif
1493 ngx_resolver_an_t *an; 1745 ngx_resolver_an_t *an;
1494 ngx_resolver_ctx_t *ctx, *next; 1746 ngx_resolver_ctx_t *ctx, *next;
1495 ngx_resolver_node_t *rn; 1747 ngx_resolver_node_t *rn;
1748 ngx_resolver_connection_t *rec;
1496 1749
1497 if (ngx_resolver_copy(r, &name, buf, 1750 if (ngx_resolver_copy(r, &name, buf,
1498 buf + sizeof(ngx_resolver_hdr_t), buf + last) 1751 buf + sizeof(ngx_resolver_hdr_t), buf + last)
1499 != NGX_OK) 1752 != NGX_OK)
1500 { 1753 {
1526 "unexpected response for %V", &name); 1779 "unexpected response for %V", &name);
1527 ngx_resolver_free(r, name.data); 1780 ngx_resolver_free(r, name.data);
1528 goto failed; 1781 goto failed;
1529 } 1782 }
1530 1783
1784 if (trunc && rn->tcp6) {
1785 ngx_resolver_free(r, name.data);
1786 goto failed;
1787 }
1788
1531 qident = (rn->query6[0] << 8) + rn->query6[1]; 1789 qident = (rn->query6[0] << 8) + rn->query6[1];
1532 1790
1533 break; 1791 break;
1534 #endif 1792 #endif
1535 1793
1536 default: /* NGX_RESOLVE_A */ 1794 default: /* NGX_RESOLVE_A */
1537 1795
1538 if (rn->query == NULL || rn->naddrs != (u_short) -1) { 1796 if (rn->query == NULL || rn->naddrs != (u_short) -1) {
1539 ngx_log_error(r->log_level, r->log, 0, 1797 ngx_log_error(r->log_level, r->log, 0,
1540 "unexpected response for %V", &name); 1798 "unexpected response for %V", &name);
1799 ngx_resolver_free(r, name.data);
1800 goto failed;
1801 }
1802
1803 if (trunc && rn->tcp) {
1541 ngx_resolver_free(r, name.data); 1804 ngx_resolver_free(r, name.data);
1542 goto failed; 1805 goto failed;
1543 } 1806 }
1544 1807
1545 qident = (rn->query[0] << 8) + rn->query[1]; 1808 qident = (rn->query[0] << 8) + rn->query[1];
1552 ngx_resolver_free(r, name.data); 1815 ngx_resolver_free(r, name.data);
1553 goto failed; 1816 goto failed;
1554 } 1817 }
1555 1818
1556 ngx_resolver_free(r, name.data); 1819 ngx_resolver_free(r, name.data);
1820
1821 if (trunc) {
1822
1823 ngx_queue_remove(&rn->queue);
1824
1825 if (rn->waiting == NULL) {
1826 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1827 ngx_resolver_free_node(r, rn);
1828 goto next;
1829 }
1830
1831 rec = r->connections.elts;
1832 rec = &rec[rn->last_connection];
1833
1834 switch (qtype) {
1835
1836 #if (NGX_HAVE_INET6)
1837 case NGX_RESOLVE_AAAA:
1838
1839 rn->tcp6 = 1;
1840
1841 (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen);
1842
1843 break;
1844 #endif
1845
1846 default: /* NGX_RESOLVE_A */
1847
1848 rn->tcp = 1;
1849
1850 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
1851 }
1852
1853 rn->expire = ngx_time() + r->resend_timeout;
1854
1855 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
1856
1857 goto next;
1858 }
1557 1859
1558 if (code == 0 && rn->code) { 1860 if (code == 0 && rn->code) {
1559 code = rn->code; 1861 code = rn->code;
1560 } 1862 }
1561 1863
3184 ngx_close_connection(c); 3486 ngx_close_connection(c);
3185 rec->udp = NULL; 3487 rec->udp = NULL;
3186 3488
3187 return NGX_ERROR; 3489 return NGX_ERROR;
3188 } 3490 }
3491
3492
3493 ngx_int_t
3494 ngx_tcp_connect(ngx_resolver_connection_t *rec)
3495 {
3496 int rc;
3497 ngx_int_t event;
3498 ngx_err_t err;
3499 ngx_uint_t level;
3500 ngx_socket_t s;
3501 ngx_event_t *rev, *wev;
3502 ngx_connection_t *c;
3503
3504 s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0);
3505
3506 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s);
3507
3508 if (s == (ngx_socket_t) -1) {
3509 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3510 ngx_socket_n " failed");
3511 return NGX_ERROR;
3512 }
3513
3514 c = ngx_get_connection(s, &rec->log);
3515
3516 if (c == NULL) {
3517 if (ngx_close_socket(s) == -1) {
3518 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3519 ngx_close_socket_n "failed");
3520 }
3521
3522 return NGX_ERROR;
3523 }
3524
3525 if (ngx_nonblocking(s) == -1) {
3526 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3527 ngx_nonblocking_n " failed");
3528
3529 goto failed;
3530 }
3531
3532 rev = c->read;
3533 wev = c->write;
3534
3535 rev->log = &rec->log;
3536 wev->log = &rec->log;
3537
3538 rec->tcp = c;
3539
3540 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
3541
3542 if (ngx_add_conn) {
3543 if (ngx_add_conn(c) == NGX_ERROR) {
3544 goto failed;
3545 }
3546 }
3547
3548 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
3549 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
3550
3551 rc = connect(s, rec->sockaddr, rec->socklen);
3552
3553 if (rc == -1) {
3554 err = ngx_socket_errno;
3555
3556
3557 if (err != NGX_EINPROGRESS
3558 #if (NGX_WIN32)
3559 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
3560 && err != NGX_EAGAIN
3561 #endif
3562 )
3563 {
3564 if (err == NGX_ECONNREFUSED
3565 #if (NGX_LINUX)
3566 /*
3567 * Linux returns EAGAIN instead of ECONNREFUSED
3568 * for unix sockets if listen queue is full
3569 */
3570 || err == NGX_EAGAIN
3571 #endif
3572 || err == NGX_ECONNRESET
3573 || err == NGX_ENETDOWN
3574 || err == NGX_ENETUNREACH
3575 || err == NGX_EHOSTDOWN
3576 || err == NGX_EHOSTUNREACH)
3577 {
3578 level = NGX_LOG_ERR;
3579
3580 } else {
3581 level = NGX_LOG_CRIT;
3582 }
3583
3584 ngx_log_error(level, c->log, err, "connect() to %V failed",
3585 &rec->server);
3586
3587 ngx_close_connection(c);
3588 rec->tcp = NULL;
3589
3590 return NGX_ERROR;
3591 }
3592 }
3593
3594 if (ngx_add_conn) {
3595 if (rc == -1) {
3596
3597 /* NGX_EINPROGRESS */
3598
3599 return NGX_AGAIN;
3600 }
3601
3602 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
3603
3604 wev->ready = 1;
3605
3606 return NGX_OK;
3607 }
3608
3609 if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
3610
3611 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno,
3612 "connect(): %d", rc);
3613
3614 if (ngx_blocking(s) == -1) {
3615 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3616 ngx_blocking_n " failed");
3617 goto failed;
3618 }
3619
3620 /*
3621 * FreeBSD's aio allows to post an operation on non-connected socket.
3622 * NT does not support it.
3623 *
3624 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
3625 */
3626
3627 rev->ready = 1;
3628 wev->ready = 1;
3629
3630 return NGX_OK;
3631 }
3632
3633 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
3634
3635 /* kqueue */
3636
3637 event = NGX_CLEAR_EVENT;
3638
3639 } else {
3640
3641 /* select, poll, /dev/poll */
3642
3643 event = NGX_LEVEL_EVENT;
3644 }
3645
3646 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
3647 goto failed;
3648 }
3649
3650 if (rc == -1) {
3651
3652 /* NGX_EINPROGRESS */
3653
3654 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
3655 goto failed;
3656 }
3657
3658 return NGX_AGAIN;
3659 }
3660
3661 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
3662
3663 wev->ready = 1;
3664
3665 return NGX_OK;
3666
3667 failed:
3668
3669 ngx_close_connection(c);
3670 rec->tcp = NULL;
3671
3672 return NGX_ERROR;
3673 }