tcp.c 29 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
 */

Witold Krecicki's avatar
netmgr:    
Witold Krecicki committed
12
#include <libgen.h>
13
#include <unistd.h>
14
15
16
17
18
#include <uv.h>

#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
Evan Hunt's avatar
Evan Hunt committed
19
#include <isc/log.h>
20
21
22
23
24
25
26
27
28
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
29
#include <isc/stdtime.h>
30
31
32
33
#include <isc/thread.h>
#include <isc/util.h>

#include "netmgr-int.h"
34
#include "uv-compat.h"
35

36
37
38
static atomic_uint_fast32_t last_tcpquota_log = ATOMIC_VAR_INIT(0);

static bool
39
can_log_tcp_quota(void) {
40
41
42
43
44
45
46
47
48
49
50
	isc_stdtime_t now, last;

	isc_stdtime_get(&now);
	last = atomic_exchange_relaxed(&last_tcpquota_log, now);
	if (now != last) {
		return (true);
	}

	return (false);
}

Ondřej Surý's avatar
Ondřej Surý committed
51
52
static int
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
53

Ondřej Surý's avatar
Ondřej Surý committed
54
55
static void
tcp_close_direct(isc_nmsocket_t *sock);
56

Ondřej Surý's avatar
Ondřej Surý committed
57
58
59
60
static isc_result_t
tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
static void
tcp_connect_cb(uv_connect_t *uvreq, int status);
61

Ondřej Surý's avatar
Ondřej Surý committed
62
63
static void
tcp_connection_cb(uv_stream_t *server, int status);
64

Ondřej Surý's avatar
Ondřej Surý committed
65
66
static void
read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
67

Ondřej Surý's avatar
Ondřej Surý committed
68
69
static void
tcp_close_cb(uv_handle_t *uvhandle);
70

Ondřej Surý's avatar
Ondřej Surý committed
71
72
static void
tcp_listenclose_cb(uv_handle_t *handle);
73
74
static isc_result_t
accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota);
75

Witold Krecicki's avatar
Witold Krecicki committed
76
77
78
static void
quota_accept_cb(isc_quota_t *quota, void *sock0);

79
static int
Evan Hunt's avatar
Evan Hunt committed
80
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
Evan Hunt's avatar
Evan Hunt committed
81
	isc__networker_t *worker = NULL;
Evan Hunt's avatar
Evan Hunt committed
82
	int r;
83
84
85
86
87
88
89

	REQUIRE(isc__nm_in_netthread());

	worker = &sock->mgr->workers[isc_nm_tid()];

	r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
	if (r != 0) {
90
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
Evan Hunt's avatar
Evan Hunt committed
91
92
93
94
		/* Socket was never opened; no need for tcp_close_direct() */
		atomic_store(&sock->closed, true);
		sock->result = isc__nm_uverr2result(r);
		atomic_store(&sock->connect_error, true);
95
96
97
98
99
100
		return (r);
	}

	if (req->local.length != 0) {
		r = uv_tcp_bind(&sock->uv_handle.tcp, &req->local.type.sa, 0);
		if (r != 0) {
101
102
			isc__nm_incstats(sock->mgr,
					 sock->statsindex[STATID_BINDFAIL]);
Evan Hunt's avatar
Evan Hunt committed
103
104
			sock->result = isc__nm_uverr2result(r);
			atomic_store(&sock->connect_error, true);
105
106
107
108
			tcp_close_direct(sock);
			return (r);
		}
	}
Evan Hunt's avatar
Evan Hunt committed
109

110
	uv_handle_set_data(&sock->uv_handle.handle, sock);
111
112
	r = uv_tcp_connect(&req->uv_req.connect, &sock->uv_handle.tcp,
			   &req->peer.type.sa, tcp_connect_cb);
Evan Hunt's avatar
Evan Hunt committed
113
114
115
116
117
118
119
	if (r != 0) {
		isc__nm_incstats(sock->mgr,
				 sock->statsindex[STATID_CONNECTFAIL]);
		sock->result = isc__nm_uverr2result(r);
		atomic_store(&sock->connect_error, true);
		tcp_close_direct(sock);
	}
120
121
122
123
	return (r);
}

void
Evan Hunt's avatar
Evan Hunt committed
124
isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
125
	isc__netievent_tcpconnect_t *ievent =
126
		(isc__netievent_tcpconnect_t *)ev0;
Evan Hunt's avatar
Evan Hunt committed
127
	isc_nmsocket_t *sock = ievent->sock;
128
	isc__nm_uvreq_t *req = ievent->req;
Evan Hunt's avatar
Evan Hunt committed
129
	int r;
130

Evan Hunt's avatar
Evan Hunt committed
131
	UNUSED(worker);
132
133
134
135
136

	r = tcp_connect_direct(sock, req);
	if (r != 0) {
		/* We need to issue callbacks ourselves */
		tcp_connect_cb(&req->uv_req.connect, r);
Evan Hunt's avatar
Evan Hunt committed
137
		goto done;
138
	}
Evan Hunt's avatar
Evan Hunt committed
139
140
141
142
143
144
145

	atomic_store(&sock->connected, true);

done:
	LOCK(&sock->lock);
	SIGNAL(&sock->cond);
	UNLOCK(&sock->lock);
146
147
148
}

static void
Evan Hunt's avatar
Evan Hunt committed
149
tcp_connect_cb(uv_connect_t *uvreq, int status) {
150
	isc__nm_uvreq_t *req = (isc__nm_uvreq_t *)uvreq->data;
Evan Hunt's avatar
Evan Hunt committed
151
	isc_nmsocket_t *sock = NULL;
152

153
	sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
154
155
156
157

	REQUIRE(VALID_UVREQ(req));

	if (status == 0) {
Evan Hunt's avatar
Evan Hunt committed
158
		isc_result_t result;
159
		struct sockaddr_storage ss;
160
		isc_nmhandle_t *handle = NULL;
161

Evan Hunt's avatar
Evan Hunt committed
162
		sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
163
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
164
165
		uv_tcp_getpeername(&sock->uv_handle.tcp, (struct sockaddr *)&ss,
				   &(int){ sizeof(ss) });
166
		result = isc_sockaddr_fromsockaddr(&sock->peer,
167
						   (struct sockaddr *)&ss);
168
169
170
171
		RUNTIME_CHECK(result == ISC_R_SUCCESS);

		handle = isc__nmhandle_get(sock, NULL, NULL);
		req->cb.connect(handle, ISC_R_SUCCESS, req->cbarg);
172
173
174
175
176
177
178
179
180
181
182
183
184

		isc__nm_uvreq_put(&req, sock);

		/*
		 * The sock is now attached to the handle.
		 */
		isc__nmsocket_detach(&sock);

		/*
		 * If the connect callback wants to hold on to the handle,
		 * it needs to attach to it.
		 */
		isc_nmhandle_unref(handle);
185
	} else {
Evan Hunt's avatar
Evan Hunt committed
186
187
188
189
190
		/*
		 * TODO:
		 * Handle the connect error properly and free the socket.
		 */
		req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
191
		isc__nm_uvreq_put(&req, sock);
192
193
194
	}
}

Evan Hunt's avatar
Evan Hunt committed
195
196
197
isc_result_t
isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
		  isc_nm_cb_t cb, void *cbarg, size_t extrahandlesize) {
198
	isc_nmsocket_t *nsock = NULL, *tmp = NULL;
Evan Hunt's avatar
Evan Hunt committed
199
200
	isc__netievent_tcpconnect_t *ievent = NULL;
	isc__nm_uvreq_t *req = NULL;
201
	isc_result_t result = ISC_R_SUCCESS;
Evan Hunt's avatar
Evan Hunt committed
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

	REQUIRE(VALID_NM(mgr));

	nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
	isc__nmsocket_init(nsock, mgr, isc_nm_tcpsocket, local);
	nsock->extrahandlesize = extrahandlesize;
	nsock->result = ISC_R_SUCCESS;

	req = isc__nm_uvreq_get(mgr, nsock);
	req->cb.connect = cb;
	req->cbarg = cbarg;
	req->peer = peer->addr;

	ievent = isc__nm_get_ievent(mgr, netievent_tcpconnect);
	ievent->sock = nsock;
	ievent->req = req;

219
220
221
222
223
224
	/*
	 * Async callbacks can dereference the socket in the meantime,
	 * we need to hold an additional reference to it.
	 */
	isc__nmsocket_attach(nsock, &tmp);

Evan Hunt's avatar
Evan Hunt committed
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
	if (isc__nm_in_netthread()) {
		nsock->tid = isc_nm_tid();
		isc__nm_async_tcpconnect(&mgr->workers[nsock->tid],
					 (isc__netievent_t *)ievent);
		isc__nm_put_ievent(mgr, ievent);
	} else {
		nsock->tid = isc_random_uniform(mgr->nworkers);
		isc__nm_enqueue_ievent(&mgr->workers[nsock->tid],
				       (isc__netievent_t *)ievent);

		LOCK(&nsock->lock);
		while (!atomic_load(&nsock->connected) &&
		       !atomic_load(&nsock->connect_error)) {
			WAIT(&nsock->cond, &nsock->lock);
		}
		UNLOCK(&nsock->lock);
	}

	if (nsock->result != ISC_R_SUCCESS) {
244
		result = nsock->result;
Evan Hunt's avatar
Evan Hunt committed
245
246
247
		isc__nmsocket_detach(&nsock);
	}

248
249
250
	isc__nmsocket_detach(&tmp);

	return (result);
Evan Hunt's avatar
Evan Hunt committed
251
252
}

253
isc_result_t
Evan Hunt's avatar
Evan Hunt committed
254
255
256
257
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
		 isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
		 size_t extrahandlesize, int backlog, isc_quota_t *quota,
		 isc_nmsocket_t **sockp) {
Evan Hunt's avatar
Evan Hunt committed
258
	isc_nmsocket_t *nsock = NULL;
Evan Hunt's avatar
Evan Hunt committed
259
	isc__netievent_tcplisten_t *ievent = NULL;
260
261
262
263

	REQUIRE(VALID_NM(mgr));

	nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
264
	isc__nmsocket_init(nsock, mgr, isc_nm_tcplistener, iface);
Evan Hunt's avatar
Evan Hunt committed
265
266
	nsock->accept_cb.accept = accept_cb;
	nsock->accept_cbarg = accept_cbarg;
267
	nsock->extrahandlesize = extrahandlesize;
268
	nsock->backlog = backlog;
269
	nsock->result = ISC_R_SUCCESS;
270
271
	if (quota != NULL) {
		/*
272
		 * We don't attach to quota, just assign - to avoid
273
		 * increasing quota unnecessarily.
274
		 */
275
		nsock->pquota = quota;
276
	}
Witold Krecicki's avatar
Witold Krecicki committed
277
	isc_quota_cb_init(&nsock->quotacb, quota_accept_cb, nsock);
278

279
	ievent = isc__nm_get_ievent(mgr, netievent_tcplisten);
280
	ievent->sock = nsock;
281
282
283
	if (isc__nm_in_netthread()) {
		nsock->tid = isc_nm_tid();
		isc__nm_async_tcplisten(&mgr->workers[nsock->tid],
284
					(isc__netievent_t *)ievent);
285
286
287
288
		isc__nm_put_ievent(mgr, ievent);
	} else {
		nsock->tid = isc_random_uniform(mgr->nworkers);
		isc__nm_enqueue_ievent(&mgr->workers[nsock->tid],
289
				       (isc__netievent_t *)ievent);
290
291

		LOCK(&nsock->lock);
Evan Hunt's avatar
Evan Hunt committed
292
293
		while (!atomic_load(&nsock->listening) &&
		       !atomic_load(&nsock->listen_error)) {
294
295
			WAIT(&nsock->cond, &nsock->lock);
		}
296
297
		UNLOCK(&nsock->lock);
	}
298

299
300
301
302
303
	if (nsock->result == ISC_R_SUCCESS) {
		*sockp = nsock;
		return (ISC_R_SUCCESS);
	} else {
		isc_result_t result = nsock->result;
304
		isc__nmsocket_detach(&nsock);
305
306
		return (result);
	}
307
308
}

309
/*
310
311
312
313
 * For multi-threaded TCP listening, we create a single socket,
 * bind to it, and start listening. On an incoming connection we accept
 * it, and then pass the accepted socket using the uv_export/uv_import
 * mechanism to a child thread.
314
 */
315
void
Evan Hunt's avatar
Evan Hunt committed
316
isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
317
	isc__netievent_tcplisten_t *ievent = (isc__netievent_tcplisten_t *)ev0;
Evan Hunt's avatar
Evan Hunt committed
318
319
320
	isc_nmsocket_t *sock = ievent->sock;
	struct sockaddr_storage sname;
	int r, flags = 0, snamelen = sizeof(sname);
321
322
323
324
325
326

	REQUIRE(isc__nm_in_netthread());
	REQUIRE(sock->type == isc_nm_tcplistener);

	r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
	if (r != 0) {
327
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
Evan Hunt's avatar
Evan Hunt committed
328
		/* The socket was never opened, so no need for uv_close() */
329
330
		atomic_store(&sock->closed, true);
		sock->result = isc__nm_uverr2result(r);
Evan Hunt's avatar
Evan Hunt committed
331
		atomic_store(&sock->listen_error, true);
Evan Hunt's avatar
Evan Hunt committed
332
		goto done;
333
	}
334
335
336

	isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPEN]);

Evan Hunt's avatar
Evan Hunt committed
337
338
339
	if (sock->iface->addr.type.sa.sa_family == AF_INET6) {
		flags = UV_TCP_IPV6ONLY;
	}
340

341
342
	r = uv_tcp_bind(&sock->uv_handle.tcp, &sock->iface->addr.type.sa,
			flags);
343
	if (r != 0) {
344
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
345
346
		uv_close(&sock->uv_handle.handle, tcp_close_cb);
		sock->result = isc__nm_uverr2result(r);
Evan Hunt's avatar
Evan Hunt committed
347
		atomic_store(&sock->listen_error, true);
Evan Hunt's avatar
Evan Hunt committed
348
		goto done;
349
	}
Evan Hunt's avatar
Evan Hunt committed
350

351
	/*
352
353
354
355
	 * By doing this now, we can find out immediately whether bind()
	 * failed, and quit if so. (uv_bind() uses a delayed error,
	 * initially returning success even if bind() fails, and this
	 * could cause a deadlock later if we didn't check first.)
356
	 */
357
358
	r = uv_tcp_getsockname(&sock->uv_handle.tcp, (struct sockaddr *)&sname,
			       &snamelen);
359
360
361
	if (r != 0) {
		uv_close(&sock->uv_handle.handle, tcp_close_cb);
		sock->result = isc__nm_uverr2result(r);
Evan Hunt's avatar
Evan Hunt committed
362
		atomic_store(&sock->listen_error, true);
363
364
		goto done;
	}
Evan Hunt's avatar
Evan Hunt committed
365

366
	/*
367
368
	 * The callback will run in the same thread uv_listen() was called
	 * from, so a race with tcp_connection_cb() isn't possible.
369
	 */
370
371
372
373
374
375
376
377
378
379
380
	r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
		      tcp_connection_cb);
	if (r != 0) {
		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
			      ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
			      "uv_listen failed: %s",
			      isc_result_totext(isc__nm_uverr2result(r)));
		uv_close(&sock->uv_handle.handle, tcp_close_cb);
		sock->result = isc__nm_uverr2result(r);
		atomic_store(&sock->listen_error, true);
		goto done;
381
382
	}

383
384
	uv_handle_set_data(&sock->uv_handle.handle, sock);

385
386
	atomic_store(&sock->listening, true);

387
done:
388
389
390
	LOCK(&sock->lock);
	SIGNAL(&sock->cond);
	UNLOCK(&sock->lock);
391
392
393
	return;
}

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
static void
tcp_connection_cb(uv_stream_t *server, int status) {
	isc_nmsocket_t *psock = uv_handle_get_data((uv_handle_t *)server);
	isc_result_t result;

	UNUSED(status);

	result = accept_connection(psock, NULL);
	if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
		if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
		    can_log_tcp_quota()) {
			isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
				      ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
				      "TCP connection failed: %s",
				      isc_result_totext(result));
		}
	}
}

413
void
414
415
416
417
418
419
420
421
422
isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
	isc__netievent_tcpchildaccept_t *ievent =
		(isc__netievent_tcpchildaccept_t *)ev0;
	isc_nmsocket_t *ssock = ievent->sock;
	isc_nmsocket_t *csock = NULL;
	isc_nmhandle_t *handle;
	isc_result_t result;
	struct sockaddr_storage ss;
	isc_sockaddr_t local;
Evan Hunt's avatar
Evan Hunt committed
423
	int r;
424
425

	REQUIRE(isc__nm_in_netthread());
426
	REQUIRE(ssock->type == isc_nm_tcplistener);
427

428
429
430
431
	csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
	isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
	csock->tid = isc_nm_tid();
	csock->extrahandlesize = ssock->extrahandlesize;
432

433
434
435
436
437
438
439
	csock->quota = ievent->quota;
	ievent->quota = NULL;

	worker = &ssock->mgr->workers[isc_nm_tid()];
	uv_tcp_init(&worker->loop, &csock->uv_handle.tcp);

	r = isc_uv_import(&csock->uv_handle.stream, &ievent->streaminfo);
Witold Krecicki's avatar
netmgr:    
Witold Krecicki committed
440
441
442
443
444
	if (r != 0) {
		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
			      ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
			      "uv_import failed: %s",
			      isc_result_totext(isc__nm_uverr2result(r)));
445
446
		result = isc__nm_uverr2result(r);
		goto error;
Witold Krecicki's avatar
netmgr:    
Witold Krecicki committed
447
	}
Evan Hunt's avatar
Evan Hunt committed
448

449
450
451
452
453
454
	r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
			       &(int){ sizeof(ss) });
	if (r != 0) {
		result = isc__nm_uverr2result(r);
		goto error;
	}
455

456
457
458
459
460
461
462
463
	result = isc_sockaddr_fromsockaddr(&csock->peer,
					   (struct sockaddr *)&ss);
	if (result != ISC_R_SUCCESS) {
		goto error;
	}

	r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
			       &(int){ sizeof(ss) });
464
	if (r != 0) {
465
466
467
468
469
470
471
		result = isc__nm_uverr2result(r);
		goto error;
	}

	result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss);
	if (result != ISC_R_SUCCESS) {
		goto error;
472
	}
473

474
	isc__nmsocket_attach(ssock, &csock->server);
475
476
477

	handle = isc__nmhandle_get(csock, NULL, &local);

478
	INSIST(ssock->accept_cb.accept != NULL);
479
	csock->read_timeout = ssock->mgr->init;
480
481
482
483
484
	ssock->accept_cb.accept(handle, ISC_R_SUCCESS, ssock->accept_cbarg);

	/*
	 * csock is now attached to the handle.
	 */
485
	isc__nmsocket_detach(&csock);
486
487
488
489
490
491

	/*
	 * If the accept callback wants to hold on to the handle,
	 * it needs to attach to it.
	 */
	isc_nmhandle_unref(handle);
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
	return;

error:
	/*
	 * Detach the quota early to make room for other connections;
	 * otherwise it'd be detached later asynchronously, and clog
	 * the quota unnecessarily.
	 */
	if (csock->quota != NULL) {
		isc_quota_detach(&csock->quota);
	}
	isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
		      ISC_LOG_ERROR, "Accepting TCP connection failed: %s",
		      isc_result_totext(result));

	/*
	 * Detach the socket properly to make sure uv_close() is called.
	 */
510
	isc__nmsocket_detach(&csock);
511
512
}

513
void
514
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) {
Evan Hunt's avatar
Evan Hunt committed
515
	isc__netievent_tcpstop_t *ievent = NULL;
516
517
518
519

	REQUIRE(VALID_NMSOCK(sock));
	REQUIRE(!isc__nm_in_netthread());

Evan Hunt's avatar
Evan Hunt committed
520
	ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpstop);
521
	isc__nmsocket_attach(sock, &ievent->sock);
522
	isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
523
			       (isc__netievent_t *)ievent);
524
525
}

526
void
Evan Hunt's avatar
Evan Hunt committed
527
isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0) {
528
	isc__netievent_tcpstop_t *ievent = (isc__netievent_tcpstop_t *)ev0;
Evan Hunt's avatar
Evan Hunt committed
529
	isc_nmsocket_t *sock = ievent->sock;
530
531
532
533
534
535
536
537
538
539
540

	UNUSED(worker);

	REQUIRE(isc__nm_in_netthread());
	REQUIRE(VALID_NMSOCK(sock));
	REQUIRE(sock->type == isc_nm_tcplistener);

	/*
	 * If network manager is interlocked, re-enqueue the event for later.
	 */
	if (!isc__nm_acquire_interlocked(sock->mgr)) {
Evan Hunt's avatar
Evan Hunt committed
541
		isc__netievent_tcpstop_t *event = NULL;
542

543
		event = isc__nm_get_ievent(sock->mgr, netievent_tcpstop);
544
545
		event->sock = sock;
		isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
546
				       (isc__netievent_t *)event);
547
	} else {
548
549
		uv_close((uv_handle_t *)&sock->uv_handle.tcp,
			 tcp_listenclose_cb);
550
551
552
553
554
		isc__nm_drop_interlocked(sock->mgr);
	}
}

/*
555
 * This callback is used for closing listening sockets.
556
557
 */
static void
Evan Hunt's avatar
Evan Hunt committed
558
tcp_listenclose_cb(uv_handle_t *handle) {
559
	isc_nmsocket_t *sock = uv_handle_get_data(handle);
Evan Hunt's avatar
Evan Hunt committed
560

561
	LOCK(&sock->lock);
562
563
564
	atomic_store(&sock->closed, true);
	atomic_store(&sock->listening, false);
	sock->pquota = NULL;
565
	UNLOCK(&sock->lock);
Evan Hunt's avatar
Evan Hunt committed
566

567
	isc__nmsocket_detach(&sock);
568
569
}

Witold Kręcicki's avatar
Witold Kręcicki committed
570
static void
Evan Hunt's avatar
Evan Hunt committed
571
readtimeout_cb(uv_timer_t *handle) {
572
	isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
Witold Kręcicki's avatar
Witold Kręcicki committed
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592

	REQUIRE(VALID_NMSOCK(sock));
	REQUIRE(sock->tid == isc_nm_tid());

	/*
	 * Socket is actively processing something, so restart the timer
	 * and return.
	 */
	if (atomic_load(&sock->processing)) {
		uv_timer_start(handle, readtimeout_cb, sock->read_timeout, 0);
		return;
	}

	/*
	 * Timeout; stop reading and process whatever we have.
	 */
	uv_read_stop(&sock->uv_handle.stream);
	if (sock->quota) {
		isc_quota_detach(&sock->quota);
	}
593
	if (sock->rcb.recv != NULL) {
594
595
		sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL,
			       sock->rcbarg);
596
		isc__nmsocket_clearcb(sock);
597
	}
Witold Kręcicki's avatar
Witold Kręcicki committed
598
599
}

600
isc_result_t
601
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
Evan Hunt's avatar
Evan Hunt committed
602
	isc_nmsocket_t *sock = NULL;
Witold Kręcicki's avatar
Witold Kręcicki committed
603
	isc__netievent_startread_t *ievent = NULL;
604
605
606
607
608
609

	REQUIRE(VALID_NMHANDLE(handle));
	REQUIRE(VALID_NMSOCK(handle->sock));

	sock = handle->sock;
	sock->rcb.recv = cb;
Witold Kręcicki's avatar
Witold Kręcicki committed
610
611
612
613
614
	sock->rcbarg = cbarg;

	ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpstartread);
	ievent->sock = sock;

615
	if (sock->tid == isc_nm_tid()) {
616
617
		isc__nm_async_tcp_startread(&sock->mgr->workers[sock->tid],
					    (isc__netievent_t *)ievent);
Witold Kręcicki's avatar
Witold Kręcicki committed
618
		isc__nm_put_ievent(sock->mgr, ievent);
619
620
	} else {
		isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
621
				       (isc__netievent_t *)ievent);
622
623
624
625
626
627
	}

	return (ISC_R_SUCCESS);
}

void
628
isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
629
	isc__netievent_startread_t *ievent = (isc__netievent_startread_t *)ev0;
Evan Hunt's avatar
Evan Hunt committed
630
631
	isc_nmsocket_t *sock = ievent->sock;
	int r;
632
633

	REQUIRE(worker->id == isc_nm_tid());
Witold Kręcicki's avatar
Witold Kręcicki committed
634
635
636
	if (sock->read_timeout != 0) {
		if (!sock->timer_initialized) {
			uv_timer_init(&worker->loop, &sock->timer);
637
			uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
Witold Kręcicki's avatar
Witold Kręcicki committed
638
639
			sock->timer_initialized = true;
		}
640
641
		uv_timer_start(&sock->timer, readtimeout_cb, sock->read_timeout,
			       0);
Witold Kręcicki's avatar
Witold Kręcicki committed
642
	}
643

644
645
646
647
	r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, read_cb);
	if (r != 0) {
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
	}
648
649
650
}

isc_result_t
651
isc__nm_tcp_pauseread(isc_nmsocket_t *sock) {
Witold Kręcicki's avatar
Witold Kręcicki committed
652
653
	isc__netievent_pauseread_t *ievent = NULL;

654
655
	REQUIRE(VALID_NMSOCK(sock));

656
657
658
659
660
	if (atomic_load(&sock->readpaused)) {
		return (ISC_R_SUCCESS);
	}

	atomic_store(&sock->readpaused, true);
Witold Kręcicki's avatar
Witold Kręcicki committed
661
662
	ievent = isc__nm_get_ievent(sock->mgr, netievent_tcppauseread);
	ievent->sock = sock;
663

664
	if (sock->tid == isc_nm_tid()) {
665
666
		isc__nm_async_tcp_pauseread(&sock->mgr->workers[sock->tid],
					    (isc__netievent_t *)ievent);
Witold Kręcicki's avatar
Witold Kręcicki committed
667
		isc__nm_put_ievent(sock->mgr, ievent);
668
669
	} else {
		isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
670
				       (isc__netievent_t *)ievent);
671
672
673
674
675
676
	}

	return (ISC_R_SUCCESS);
}

void
677
isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
678
	isc__netievent_pauseread_t *ievent = (isc__netievent_pauseread_t *)ev0;
Evan Hunt's avatar
Evan Hunt committed
679
	isc_nmsocket_t *sock = ievent->sock;
680

Witold Kręcicki's avatar
Witold Kręcicki committed
681
	REQUIRE(VALID_NMSOCK(sock));
682
683
	REQUIRE(worker->id == isc_nm_tid());

Witold Kręcicki's avatar
Witold Kręcicki committed
684
685
686
	if (sock->timer_initialized) {
		uv_timer_stop(&sock->timer);
	}
687
688
689
690
	uv_read_stop(&sock->uv_handle.stream);
}

isc_result_t
691
isc__nm_tcp_resumeread(isc_nmsocket_t *sock) {
Witold Kręcicki's avatar
Witold Kręcicki committed
692
693
	isc__netievent_startread_t *ievent = NULL;

694
	REQUIRE(VALID_NMSOCK(sock));
695
696
697
	if (sock->rcb.recv == NULL) {
		return (ISC_R_CANCELED);
	}
698

699
700
701
702
703
704
	if (!atomic_load(&sock->readpaused)) {
		return (ISC_R_SUCCESS);
	}

	atomic_store(&sock->readpaused, false);

Witold Kręcicki's avatar
Witold Kręcicki committed
705
706
707
	ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpstartread);
	ievent->sock = sock;

708
	if (sock->tid == isc_nm_tid()) {
709
710
		isc__nm_async_tcp_startread(&sock->mgr->workers[sock->tid],
					    (isc__netievent_t *)ievent);
Witold Kręcicki's avatar
Witold Kręcicki committed
711
		isc__nm_put_ievent(sock->mgr, ievent);
712
713
	} else {
		isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
714
				       (isc__netievent_t *)ievent);
715
716
717
718
719
720
	}

	return (ISC_R_SUCCESS);
}

static void
Evan Hunt's avatar
Evan Hunt committed
721
read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
722
	isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream);
723
724
725
726
727

	REQUIRE(VALID_NMSOCK(sock));
	REQUIRE(buf != NULL);

	if (nread >= 0) {
728
729
		isc_region_t region = { .base = (unsigned char *)buf->base,
					.length = nread };
730

731
		if (sock->rcb.recv != NULL) {
732
733
			sock->rcb.recv(sock->tcphandle, ISC_R_SUCCESS, &region,
				       sock->rcbarg);
734
		}
735

736
		sock->read_timeout = (atomic_load(&sock->keepalive)
737
738
					      ? sock->mgr->keepalive
					      : sock->mgr->idle);
739

Witold Kręcicki's avatar
Witold Kręcicki committed
740
741
742
743
744
		if (sock->timer_initialized && sock->read_timeout != 0) {
			/* The timer will be updated */
			uv_timer_start(&sock->timer, readtimeout_cb,
				       sock->read_timeout, 0);
		}
745

746
747
748
749
750
		isc__nm_free_uvbuf(sock, buf);
		return;
	}

	isc__nm_free_uvbuf(sock, buf);
751

752
	/*
753
754
	 * This might happen if the inner socket is closing.  It means that
	 * it's detached, so the socket will be closed.
755
756
	 */
	if (sock->rcb.recv != NULL) {
757
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
758
		sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg);
759
		isc__nmsocket_clearcb(sock);
760
	}
761

762
	/*
Evan Hunt's avatar
Evan Hunt committed
763
764
765
	 * We don't need to clean up now; the socket will be closed and
	 * resources and quota reclaimed when handle is freed in
	 * isc__nm_tcp_close().
766
767
768
	 */
}

769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
static void
quota_accept_cb(isc_quota_t *quota, void *sock0) {
	isc_nmsocket_t *sock = (isc_nmsocket_t *)sock0;
	isc__netievent_tcpaccept_t *ievent = NULL;

	REQUIRE(VALID_NMSOCK(sock));

	/*
	 * Create a tcpaccept event and pass it using the async channel.
	 */
	ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpaccept);
	ievent->sock = sock;
	ievent->quota = quota;
	isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
			       (isc__netievent_t *)ievent);
}

/*
 * This is called after we get a quota_accept_cb() callback.
 */
void
isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
	isc_result_t result;
	isc__netievent_tcpaccept_t *ievent = (isc__netievent_tcpaccept_t *)ev0;

	REQUIRE(worker->id == ievent->sock->tid);

	result = accept_connection(ievent->sock, ievent->quota);
	if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
		if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
		    can_log_tcp_quota()) {
			isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
				      ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
				      "TCP connection failed: %s",
				      isc_result_totext(result));
		}
	}

	/*
	 * The socket was attached just before we called isc_quota_attach_cb().
	 */
810
	isc__nmsocket_detach(&ievent->sock);
811
812
813
814
815
816
817
818
819
820
821
}

/*
 * Close callback for uv_tcp_t strutures created in accept_connection().
 */
static void
free_uvtcpt(uv_handle_t *uvs) {
	isc_mem_t *mctx = (isc_mem_t *)uv_handle_get_data(uvs);
	isc_mem_putanddetach(&mctx, uvs, sizeof(uv_tcp_t));
}

822
static isc_result_t
823
accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
Evan Hunt's avatar
Evan Hunt committed
824
	isc_result_t result;
825
	isc__netievent_tcpchildaccept_t *event = NULL;
Evan Hunt's avatar
Evan Hunt committed
826
	isc__networker_t *worker = NULL;
827
828
829
	uv_tcp_t *uvstream = NULL;
	isc_mem_t *mctx = NULL;
	int r, w;
830
831
832
833

	REQUIRE(VALID_NMSOCK(ssock));
	REQUIRE(ssock->tid == isc_nm_tid());

Evan Hunt's avatar
Evan Hunt committed
834
	if (!atomic_load_relaxed(&ssock->active) ||
Evan Hunt's avatar
Evan Hunt committed
835
836
	    atomic_load_relaxed(&ssock->mgr->closing))
	{
837
		/* We're closing, bail */
838
839
840
		if (quota != NULL) {
			isc_quota_detach(&quota);
		}
841
842
843
		return (ISC_R_CANCELED);
	}

844
845
	/* We can be called directly or as a callback from quota */
	if (ssock->pquota != NULL && quota == NULL) {
846
		/*
847
848
849
		 * We need to attach to ssock, because it might be queued
		 * waiting for a TCP quota slot.  If so, then we'll detach it
		 * later when the connection is accepted. (XXX: This may be
Witold Krecicki's avatar
Witold Krecicki committed
850
851
		 * suboptimal, it might be better not to attach unless
		 * we need to - but we risk a race then.)
852
		 */
853
		isc_nmsocket_t *tsock = NULL;
854
		isc__nmsocket_attach(ssock, &tsock);
855
856
857
858
859
860
		result = isc_quota_attach_cb(ssock->pquota, &quota,
					     &ssock->quotacb);
		if (result == ISC_R_QUOTA) {
			isc__nm_incstats(ssock->mgr,
					 ssock->statsindex[STATID_ACCEPTFAIL]);
			return (result);
861
		}
862
863
864

		/*
		 * We're under quota, so there's no need to wait;
Witold Krecicki's avatar
Witold Krecicki committed
865
		 * Detach the socket.
866
		 */
867
		isc__nmsocket_detach(&tsock);
868
869
	}

870
871
	isc__nm_incstats(ssock->mgr, ssock->statsindex[STATID_ACCEPT]);

872
	worker = &ssock->mgr->workers[isc_nm_tid()];
873
	uvstream = isc_mem_get(ssock->mgr->mctx, sizeof(uv_tcp_t));
874

875
876
877
	isc_mem_attach(ssock->mgr->mctx, &mctx);
	uv_handle_set_data((uv_handle_t *)uvstream, mctx);
	mctx = NULL; /* Detached later in free_uvtcpt() */
878

879
	uv_tcp_init(&worker->loop, uvstream);
880

881
	r = uv_accept(&ssock->uv_handle.stream, (uv_stream_t *)uvstream);
882
883
	if (r != 0) {
		result = isc__nm_uverr2result(r);
884
885
886
		uv_close((uv_handle_t *)uvstream, free_uvtcpt);
		isc_quota_detach(&quota);
		return (result);
887
888
	}

889
890
891
892
893
	/* We have an accepted TCP socket, pass it to a random worker */
	w = isc_random_uniform(ssock->mgr->nworkers);
	event = isc__nm_get_ievent(ssock->mgr, netievent_tcpchildaccept);
	event->sock = ssock;
	event->quota = quota;
894

895
896
	r = isc_uv_export((uv_stream_t *)uvstream, &event->streaminfo);
	RUNTIME_CHECK(r == 0);
897

898
	uv_close((uv_handle_t *)uvstream, free_uvtcpt);
899

900
901
902
903
904
905
906
	if (w == isc_nm_tid()) {
		isc__nm_async_tcpchildaccept(&ssock->mgr->workers[w],
					     (isc__netievent_t *)event);
		isc__nm_put_ievent(ssock->mgr, event);
	} else {
		isc__nm_enqueue_ievent(&ssock->mgr->workers[w],
				       (isc__netievent_t *)event);
907
	}
908

909
	return (ISC_R_SUCCESS);
910
911
912
}

isc_result_t
913
isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
Evan Hunt's avatar
Evan Hunt committed
914
915
		 void *cbarg) {
	isc_nmsocket_t *sock = handle->sock;
916
	isc__netievent_tcpsend_t *ievent = NULL;
Evan Hunt's avatar
Evan Hunt committed
917
	isc__nm_uvreq_t *uvreq = NULL;
918
919
920
921

	REQUIRE(sock->type == isc_nm_tcpsocket);

	uvreq = isc__nm_uvreq_get(sock->mgr, sock);
922
	uvreq->uvbuf.base = (char *)region->base;
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
	uvreq->uvbuf.len = region->length;
	uvreq->handle = handle;
	isc_nmhandle_ref(uvreq->handle);
	uvreq->cb.send = cb;
	uvreq->cbarg = cbarg;

	if (sock->tid == isc_nm_tid()) {
		/*
		 * If we're in the same thread as the socket we can send the
		 * data directly
		 */
		return (tcp_send_direct(sock, uvreq));
	} else {
		/*
		 * We need to create an event and pass it using async channel
		 */
		ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpsend);
		ievent->sock = sock;
		ievent->req = uvreq;
		isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
943
				       (isc__netievent_t *)ievent);
944
945
946
947
948
949
950
		return (ISC_R_SUCCESS);
	}

	return (ISC_R_UNEXPECTED);
}

static void
Evan Hunt's avatar
Evan Hunt committed
951
952
tcp_send_cb(uv_write_t *req, int status) {
	isc_result_t result = ISC_R_SUCCESS;
953
	isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
Evan Hunt's avatar
Evan Hunt committed
954
	isc_nmsocket_t *sock = NULL;
955
956
957
958
959
960

	REQUIRE(VALID_UVREQ(uvreq));
	REQUIRE(VALID_NMHANDLE(uvreq->handle));

	if (status < 0) {
		result = isc__nm_uverr2result(status);
961
962
		isc__nm_incstats(uvreq->sock->mgr,
				 uvreq->sock->statsindex[STATID_SENDFAIL]);
963
964
965
	}

	uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
Evan Hunt's avatar
Evan Hunt committed
966
967

	sock = uvreq->handle->sock;
968
	isc_nmhandle_unref(uvreq->handle);
Evan Hunt's avatar
Evan Hunt committed
969
	isc__nm_uvreq_put(&uvreq, sock);
970
971
972
973
974
975
}

/*
 * Handle 'tcpsend' async event - send a packet on the socket
 */
void
Evan Hunt's avatar
Evan Hunt committed
976
977
isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
	isc_result_t result;
978
	isc__netievent_tcpsend_t *ievent = (isc__netievent_tcpsend_t *)ev0;
979
980
981
982
983
984
985
986
987

	REQUIRE(worker->id == ievent->sock->tid);

	if (!atomic_load(&ievent->sock->active)) {
		return;
	}

	result = tcp_send_direct(ievent->sock, ievent->req);
	if (result != ISC_R_SUCCESS) {
988
989
		ievent->req->cb.send(ievent->req->handle, result,
				     ievent->req->cbarg);
990
991
992
993
994
		isc__nm_uvreq_put(&ievent->req, ievent->req->handle->sock);
	}
}

static isc_result_t
Evan Hunt's avatar
Evan Hunt committed
995
tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
996
997
998
999
1000
1001
	int r;

	REQUIRE(sock->tid == isc_nm_tid());
	REQUIRE(sock->type == isc_nm_tcpsocket);

	isc_nmhandle_ref(req->handle);
1002
1003
	r = uv_write(&req->uv_req.write, &sock->uv_handle.stream, &req->uvbuf,
		     1, tcp_send_cb);
1004
	if (r < 0) {
1005
		isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]);
1006
1007
1008
1009
1010
1011
1012
1013
1014
		req->cb.send(NULL, isc__nm_uverr2result(r), req->cbarg);
		isc__nm_uvreq_put(&req, sock);
		return (isc__nm_uverr2result(r));
	}

	return (ISC_R_SUCCESS);
}

static void
Evan Hunt's avatar
Evan Hunt committed
1015
tcp_close_cb(uv_handle_t *uvhandle) {
1016
	isc_nmsocket_t *sock = uv_handle_get_data(uvhandle);
1017
1018
1019

	REQUIRE(VALID_NMSOCK(sock));

1020
	isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CLOSE]);
1021
	atomic_store(&sock->closed, true);
Evan Hunt's avatar
Evan Hunt committed
1022
	atomic_store(&sock->connected, false);
1023
1024
1025
	isc__nmsocket_prep_destroy(sock);
}

Witold Kręcicki's avatar
Witold Kręcicki committed
1026
static void
Evan Hunt's avatar
Evan Hunt committed
1027
timer_close_cb(uv_handle_t *uvhandle) {
1028
	isc_nmsocket_t *sock = uv_handle_get_data(uvhandle);
Witold Kręcicki's avatar
Witold Kręcicki committed
1029
1030
1031

	REQUIRE(VALID_NMSOCK(sock));

1032
1033
1034
	if (sock->server != NULL) {
		isc__nmsocket_detach(&sock->server);
	}
Witold Kręcicki's avatar
Witold Kręcicki committed
1035
1036
1037
	uv_close(&sock->uv_handle.handle, tcp_close_cb);
}

1038
static void
Evan Hunt's avatar
Evan Hunt committed
1039
tcp_close_direct(isc_nmsocket_t *sock) {
1040
1041
1042
1043
1044
	REQUIRE(VALID_NMSOCK(sock));
	REQUIRE(sock->tid == isc_nm_tid());
	REQUIRE(sock->type == isc_nm_tcpsocket);
	if (sock->quota != NULL) {
		isc_quota_detach(&sock->quota);
1045
	}
Witold Kręcicki's avatar
Witold Kręcicki committed
1046
1047
	if (sock->timer_initialized) {
		sock->timer_initialized = false;
1048
1049
		uv_timer_stop(&sock->timer);
		uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
Witold Kręcicki's avatar
Witold Kręcicki committed
1050
	} else {
1051
		if (sock->server != NULL) {
1052
			isc__nmsocket_detach(&sock->server);
1053
		}
Witold Kręcicki's avatar
Witold Kręcicki committed
1054
1055
		uv_close(&sock->uv_handle.handle, tcp_close_cb);
	}
1056
1057
1058
}

void
Evan Hunt's avatar
Evan Hunt committed
1059
isc__nm_tcp_close(isc_nmsocket_t *sock) {
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
	REQUIRE(VALID_NMSOCK(sock));
	REQUIRE(sock->type == isc_nm_tcpsocket);

	if (sock->tid == isc_nm_tid()) {
		tcp_close_direct(sock);
	} else {
		/*
		 * We need to create an event and pass it using async channel
		 */
		isc__netievent_tcpclose_t *ievent =
			isc__nm_get_ievent(sock->mgr, netievent_tcpclose);

		ievent->sock = sock;
		isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
1074
				       (isc__netievent_t *)ievent);
1075
1076
1077
1078
	}
}

void
Evan Hunt's avatar
Evan Hunt committed
1079
isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0) {
1080
	isc__netievent_tcpclose_t *ievent = (isc__netievent_tcpclose_t *)ev0;
1081
1082
1083
1084
1085

	REQUIRE(worker->id == ievent->sock->tid);

	tcp_close_direct(ievent->sock);
}