1e18a033bSKonstantin Ananyev/*
2e18a033bSKonstantin Ananyev * Copyright (c) 2017  Intel Corporation.
3e18a033bSKonstantin Ananyev * All rights reserved.
4e18a033bSKonstantin Ananyev *
5e18a033bSKonstantin Ananyev * Redistribution and use in source and binary forms, with or without
6e18a033bSKonstantin Ananyev * modification, are permitted provided that the following conditions
7e18a033bSKonstantin Ananyev * are met:
8e18a033bSKonstantin Ananyev * 1. Redistributions of source code must retain the above copyright
9e18a033bSKonstantin Ananyev *    notice, this list of conditions and the following disclaimer.
10e18a033bSKonstantin Ananyev * 2. Redistributions in binary form must reproduce the above copyright
11e18a033bSKonstantin Ananyev *    notice, this list of conditions and the following disclaimer in the
12e18a033bSKonstantin Ananyev *    documentation and/or other materials provided with the distribution.
13e18a033bSKonstantin Ananyev *
14e18a033bSKonstantin Ananyev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15e18a033bSKonstantin Ananyev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16e18a033bSKonstantin Ananyev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17e18a033bSKonstantin Ananyev * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18e18a033bSKonstantin Ananyev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19e18a033bSKonstantin Ananyev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20e18a033bSKonstantin Ananyev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21e18a033bSKonstantin Ananyev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22e18a033bSKonstantin Ananyev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23e18a033bSKonstantin Ananyev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24e18a033bSKonstantin Ananyev * SUCH DAMAGE.
25e18a033bSKonstantin Ananyev */
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyev#include <ngx_tldk.h>
28e18a033bSKonstantin Ananyev#include <tldk_sock.h>
29e18a033bSKonstantin Ananyev
30e18a033bSKonstantin Ananyev#include <rte_malloc.h>
31e18a033bSKonstantin Ananyev#include <rte_errno.h>
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyevstruct tldk_sock_stat {
34e18a033bSKonstantin Ananyev	uint64_t nb_accept;
35e18a033bSKonstantin Ananyev	uint64_t nb_close;
36e18a033bSKonstantin Ananyev	uint64_t nb_readv;
37e18a033bSKonstantin Ananyev	uint64_t nb_recv;
38e18a033bSKonstantin Ananyev	uint64_t nb_setopts;
39e18a033bSKonstantin Ananyev	uint64_t nb_shutdown;
40e18a033bSKonstantin Ananyev	uint64_t nb_writev;
41e18a033bSKonstantin Ananyev};
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyevstatic struct tldk_sock_stat sock_stat;
44e18a033bSKonstantin Ananyev
45e18a033bSKonstantin Ananyev/* One socket/file table per worker */
46e18a033bSKonstantin Ananyevstruct tldk_stbl stbl = {
47e18a033bSKonstantin Ananyev	.snum = 0,
48e18a033bSKonstantin Ananyev};
49e18a033bSKonstantin Ananyev
50e18a033bSKonstantin Ananyevstatic int (*real_accept4)(int, struct sockaddr *, socklen_t *, int);
51e18a033bSKonstantin Ananyevstatic int (*real_close)(int);
52e18a033bSKonstantin Ananyevstatic ssize_t (*real_readv)(int, const struct iovec *, int);
53e18a033bSKonstantin Ananyevstatic ssize_t (*real_recv)(int, void *, size_t, int);
54e18a033bSKonstantin Ananyevstatic int (*real_setsockopt)(int, int, int, const void *, socklen_t);
55e18a033bSKonstantin Ananyevstatic int (*real_shutdown)(int, int);
56e18a033bSKonstantin Ananyevstatic ssize_t (*real_writev)(int, const struct iovec *, int);
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyevstatic inline uint32_t
59e18a033bSKonstantin Ananyevget_socks(struct tldk_sock_list *list, struct tldk_sock *rs[],
60e18a033bSKonstantin Ananyev	uint32_t num)
61e18a033bSKonstantin Ananyev{
62e18a033bSKonstantin Ananyev	struct tldk_sock *s;
63e18a033bSKonstantin Ananyev	uint32_t i, n;
64e18a033bSKonstantin Ananyev
65e18a033bSKonstantin Ananyev	n = RTE_MIN(list->num, num);
66e18a033bSKonstantin Ananyev	for (i = 0, s = LIST_FIRST(&list->head);
67e18a033bSKonstantin Ananyev			i != n;
68e18a033bSKonstantin Ananyev			i++, s = LIST_NEXT(s, link)) {
69e18a033bSKonstantin Ananyev		rs[i] = s;
70e18a033bSKonstantin Ananyev	}
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyev	/* we retrieved all free entries */
73e18a033bSKonstantin Ananyev	if (s == NULL)
74e18a033bSKonstantin Ananyev		LIST_INIT(&list->head);
75e18a033bSKonstantin Ananyev	else
76e18a033bSKonstantin Ananyev		LIST_FIRST(&list->head) = s;
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev	list->num -= n;
79e18a033bSKonstantin Ananyev	return n;
80e18a033bSKonstantin Ananyev}
81e18a033bSKonstantin Ananyev
82e18a033bSKonstantin Ananyevstatic inline struct tldk_sock *
83e18a033bSKonstantin Ananyevget_sock(struct tldk_sock_list *list)
84e18a033bSKonstantin Ananyev{
85e18a033bSKonstantin Ananyev	struct tldk_sock *s;
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev	if (get_socks(list, &s, 1) != 1)
88e18a033bSKonstantin Ananyev		return NULL;
89e18a033bSKonstantin Ananyev
90e18a033bSKonstantin Ananyev	return s;
91e18a033bSKonstantin Ananyev}
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyevstatic inline void
94e18a033bSKonstantin Ananyevput_socks(struct tldk_sock_list *list, struct tldk_sock *fs[], uint32_t num)
95e18a033bSKonstantin Ananyev{
96e18a033bSKonstantin Ananyev	uint32_t i;
97e18a033bSKonstantin Ananyev
98e18a033bSKonstantin Ananyev	for (i = 0; i != num; i++)
99e18a033bSKonstantin Ananyev		LIST_INSERT_HEAD(&list->head, fs[i], link);
100e18a033bSKonstantin Ananyev	list->num += num;
101e18a033bSKonstantin Ananyev}
102e18a033bSKonstantin Ananyev
103e18a033bSKonstantin Ananyevstatic inline void
104e18a033bSKonstantin Ananyevput_sock(struct tldk_sock_list *list, struct tldk_sock *s)
105e18a033bSKonstantin Ananyev{
106e18a033bSKonstantin Ananyev	put_socks(list, &s, 1);
107e18a033bSKonstantin Ananyev}
108e18a033bSKonstantin Ananyev
109e18a033bSKonstantin Ananyevstatic inline void
110e18a033bSKonstantin Ananyevrem_sock(struct tldk_sock_list *list, struct tldk_sock *s)
111e18a033bSKonstantin Ananyev{
112e18a033bSKonstantin Ananyev	LIST_REMOVE(s, link);
113e18a033bSKonstantin Ananyev	list->num--;
114e18a033bSKonstantin Ananyev}
115e18a033bSKonstantin Ananyev
116e18a033bSKonstantin Ananyevstatic void
117e18a033bSKonstantin Ananyevterm_sock(struct tldk_sock *ts)
118e18a033bSKonstantin Ananyev{
119e18a033bSKonstantin Ananyev	tle_event_idle(ts->erev);
120e18a033bSKonstantin Ananyev	tle_event_idle(ts->rxev);
121e18a033bSKonstantin Ananyev	tle_event_idle(ts->txev);
122e18a033bSKonstantin Ananyev	tle_tcp_stream_close(ts->s);
123e18a033bSKonstantin Ananyev	ts->s = NULL;
124e18a033bSKonstantin Ananyev	ts->posterr = 0;
125e18a033bSKonstantin Ananyev}
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyevstatic int32_t
128e18a033bSKonstantin Ananyevclose_sock(struct tldk_sock *ts)
129e18a033bSKonstantin Ananyev{
130e18a033bSKonstantin Ananyev	if (ts->s == NULL)
131e18a033bSKonstantin Ananyev		return EBADF;
132e18a033bSKonstantin Ananyev	term_sock(ts);
133e18a033bSKonstantin Ananyev	rem_sock(&stbl.use, ts);
134e18a033bSKonstantin Ananyev	put_sock(&stbl.free, ts);
135e18a033bSKonstantin Ananyev	return 0;
136e18a033bSKonstantin Ananyev}
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyevstatic void
139e18a033bSKonstantin Ananyevdump_sock_stats(void)
140e18a033bSKonstantin Ananyev{
141e18a033bSKonstantin Ananyev	RTE_LOG(NOTICE, USER1, "%s(worker=%lu)={\n"
142e18a033bSKonstantin Ananyev		"nb_accept=%" PRIu64 ";\n"
143e18a033bSKonstantin Ananyev		"nb_close=%" PRIu64 ";\n"
144e18a033bSKonstantin Ananyev		"nb_readv=%" PRIu64 ";\n"
145e18a033bSKonstantin Ananyev		"nb_recv=%" PRIu64 ";\n"
146e18a033bSKonstantin Ananyev		"nb_setopts=%" PRIu64 ";\n"
147e18a033bSKonstantin Ananyev		"nb_shutdown=%" PRIu64 ";\n"
148e18a033bSKonstantin Ananyev		"nb_writev=%" PRIu64 ";\n"
149e18a033bSKonstantin Ananyev		"};\n",
150e18a033bSKonstantin Ananyev		__func__,
151e18a033bSKonstantin Ananyev		ngx_worker,
152e18a033bSKonstantin Ananyev		sock_stat.nb_accept,
153e18a033bSKonstantin Ananyev		sock_stat.nb_close,
154e18a033bSKonstantin Ananyev		sock_stat.nb_readv,
155e18a033bSKonstantin Ananyev		sock_stat.nb_recv,
156e18a033bSKonstantin Ananyev		sock_stat.nb_setopts,
157e18a033bSKonstantin Ananyev		sock_stat.nb_shutdown,
158e18a033bSKonstantin Ananyev		sock_stat.nb_writev);
159e18a033bSKonstantin Ananyev}
160e18a033bSKonstantin Ananyev
161e18a033bSKonstantin Ananyevvoid
162e18a033bSKonstantin Ananyevtldk_stbl_fini(void)
163e18a033bSKonstantin Ananyev{
164e18a033bSKonstantin Ananyev	dump_sock_stats();
165e18a033bSKonstantin Ananyev	tldk_dump_event_stats();
166e18a033bSKonstantin Ananyev	rte_free(stbl.sd);
167e18a033bSKonstantin Ananyev	tle_evq_destroy(stbl.txeq);
168e18a033bSKonstantin Ananyev	tle_evq_destroy(stbl.rxeq);
169e18a033bSKonstantin Ananyev	tle_evq_destroy(stbl.ereq);
170e18a033bSKonstantin Ananyev	tle_evq_destroy(stbl.syneq);
171e18a033bSKonstantin Ananyev}
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev#define INIT_FUNC(func) do { \
174e18a033bSKonstantin Ananyev	real_##func = dlsym(RTLD_NEXT, #func); \
175e18a033bSKonstantin Ananyev	RTE_ASSERT(real_##func); \
176e18a033bSKonstantin Ananyev} while (0)
177e18a033bSKonstantin Ananyev
178e18a033bSKonstantin Ananyevstatic void __attribute__((constructor))
179e18a033bSKonstantin Ananyevstub_init(void)
180e18a033bSKonstantin Ananyev{
181e18a033bSKonstantin Ananyev	INIT_FUNC(accept4);
182e18a033bSKonstantin Ananyev	INIT_FUNC(close);
183e18a033bSKonstantin Ananyev	INIT_FUNC(readv);
184e18a033bSKonstantin Ananyev	INIT_FUNC(recv);
185e18a033bSKonstantin Ananyev	INIT_FUNC(setsockopt);
186e18a033bSKonstantin Ananyev	INIT_FUNC(shutdown);
187e18a033bSKonstantin Ananyev	INIT_FUNC(writev);
188e18a033bSKonstantin Ananyev}
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev#undef INIT_FUNC
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyevint
193e18a033bSKonstantin Ananyevtldk_stbl_init(const ngx_cycle_t *cycle, const struct tldk_ctx *tc)
194e18a033bSKonstantin Ananyev{
195e18a033bSKonstantin Ananyev	uint32_t i, lc, sid, sn;
196e18a033bSKonstantin Ananyev	size_t sz;
197e18a033bSKonstantin Ananyev	struct tle_evq_param eprm;
198e18a033bSKonstantin Ananyev	struct rlimit rlim;
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev	lc = tc->cf->lcore;
201e18a033bSKonstantin Ananyev	sn = tc->cf->nb_stream;
202e18a033bSKonstantin Ananyev	sid = rte_lcore_to_socket_id(lc);
203e18a033bSKonstantin Ananyev
204e18a033bSKonstantin Ananyev	if (sn < cycle->listening.nelts + cycle->connection_n)
205e18a033bSKonstantin Ananyev		return -EINVAL;
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyev	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
208e18a033bSKonstantin Ananyev		return -errno;
209e18a033bSKonstantin Ananyev
210e18a033bSKonstantin Ananyev	stbl.nosd = rlim.rlim_max;
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyev	/* allocate event queues */
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev	memset(&eprm, 0, sizeof(eprm));
215e18a033bSKonstantin Ananyev	eprm.socket_id = sid;
216e18a033bSKonstantin Ananyev	eprm.max_events = sn;
217e18a033bSKonstantin Ananyev
218e18a033bSKonstantin Ananyev	stbl.syneq = tle_evq_create(&eprm);
219e18a033bSKonstantin Ananyev	stbl.ereq = tle_evq_create(&eprm);
220e18a033bSKonstantin Ananyev	stbl.rxeq = tle_evq_create(&eprm);
221e18a033bSKonstantin Ananyev	stbl.txeq = tle_evq_create(&eprm);
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev	RTE_LOG(NOTICE, USER1, "%s(lcore=%u, worker=%lu): "
224e18a033bSKonstantin Ananyev		"synevq=%p, erevq=%p, rxevq=%p, txevq=%p\n",
225e18a033bSKonstantin Ananyev		__func__, lc, ngx_worker,
226e18a033bSKonstantin Ananyev		stbl.syneq, stbl.ereq, stbl.rxeq, stbl.txeq);
227e18a033bSKonstantin Ananyev	if (stbl.syneq == NULL || stbl.ereq == NULL || stbl.rxeq == NULL ||
228e18a033bSKonstantin Ananyev			stbl.txeq == NULL)
229e18a033bSKonstantin Ananyev		return -ENOMEM;
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev	LIST_INIT(&stbl.lstn.head);
232e18a033bSKonstantin Ananyev	LIST_INIT(&stbl.free.head);
233e18a033bSKonstantin Ananyev	LIST_INIT(&stbl.use.head);
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev	sz = sn * sizeof(*stbl.sd);
236e18a033bSKonstantin Ananyev	stbl.sd = rte_zmalloc_socket(NULL, sz, RTE_CACHE_LINE_SIZE,
237e18a033bSKonstantin Ananyev		rte_lcore_to_socket_id(lc));
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev	if (stbl.sd == NULL) {
240e18a033bSKonstantin Ananyev		RTE_LOG(ERR, USER1, "%s(lcore=%u, worker=%lu): "
241e18a033bSKonstantin Ananyev			"failed to allocate %zu bytes\n",
242e18a033bSKonstantin Ananyev			__func__, lc, ngx_worker, sz);
243e18a033bSKonstantin Ananyev		return -ENOMEM;
244e18a033bSKonstantin Ananyev	}
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev	stbl.snum = sn;
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev	/* init listen socks */
249e18a033bSKonstantin Ananyev	for (i = 0; i != cycle->listening.nelts; i++) {
250e18a033bSKonstantin Ananyev		stbl.sd[i].rxev = tle_event_alloc(stbl.syneq, stbl.sd + i);
251e18a033bSKonstantin Ananyev		stbl.sd[i].txev = tle_event_alloc(stbl.txeq, stbl.sd + i);
252e18a033bSKonstantin Ananyev		stbl.sd[i].erev = tle_event_alloc(stbl.ereq, stbl.sd + i);
253e18a033bSKonstantin Ananyev		put_sock(&stbl.lstn, stbl.sd + i);
254e18a033bSKonstantin Ananyev	}
255e18a033bSKonstantin Ananyev
256e18a033bSKonstantin Ananyev	/* init worker connection socks */
257e18a033bSKonstantin Ananyev	for (; i != sn; i++) {
258e18a033bSKonstantin Ananyev		stbl.sd[i].rxev = tle_event_alloc(stbl.rxeq, stbl.sd + i);
259e18a033bSKonstantin Ananyev		stbl.sd[i].txev = tle_event_alloc(stbl.txeq, stbl.sd + i);
260e18a033bSKonstantin Ananyev		stbl.sd[i].erev = tle_event_alloc(stbl.ereq, stbl.sd + i);
261e18a033bSKonstantin Ananyev		put_sock(&stbl.free, stbl.sd + i);
262e18a033bSKonstantin Ananyev	}
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyev	return 0;
265e18a033bSKonstantin Ananyev}
266e18a033bSKonstantin Ananyev
267e18a033bSKonstantin Ananyevint
268e18a033bSKonstantin Ananyevtldk_open_bind_listen(struct tldk_ctx *tcx, int domain, int type,
269e18a033bSKonstantin Ananyev	const struct sockaddr *addr, socklen_t addrlen, int backlog)
270e18a033bSKonstantin Ananyev{
271e18a033bSKonstantin Ananyev	int32_t rc;
272e18a033bSKonstantin Ananyev	struct tldk_sock *ts;
273e18a033bSKonstantin Ananyev	struct tle_tcp_stream_param sprm;
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev	ts = get_sock(&stbl.lstn);
276e18a033bSKonstantin Ananyev	if (ts == NULL) {
277e18a033bSKonstantin Ananyev		errno = ENOBUFS;
278e18a033bSKonstantin Ananyev		return -1;
279e18a033bSKonstantin Ananyev	}
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev	tle_event_active(ts->erev, TLE_SEV_DOWN);
282e18a033bSKonstantin Ananyev	tle_event_active(ts->rxev, TLE_SEV_DOWN);
283e18a033bSKonstantin Ananyev	tle_event_active(ts->txev, TLE_SEV_DOWN);
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev	/* setup stream parameters */
286e18a033bSKonstantin Ananyev
287e18a033bSKonstantin Ananyev	memset(&sprm, 0, sizeof(sprm));
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev	sprm.cfg.err_ev = ts->erev;
290e18a033bSKonstantin Ananyev	sprm.cfg.recv_ev = ts->rxev;
291e18a033bSKonstantin Ananyev	sprm.cfg.send_ev = ts->txev;
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyev	memcpy(&sprm.addr.local, addr, addrlen);
294e18a033bSKonstantin Ananyev	sprm.addr.remote.ss_family = sprm.addr.local.ss_family;
295e18a033bSKonstantin Ananyev
296e18a033bSKonstantin Ananyev	ts->s = tle_tcp_stream_open(tcx->ctx, &sprm);
297e18a033bSKonstantin Ananyev	if (ts->s != NULL)
298e18a033bSKonstantin Ananyev		rc = tle_tcp_stream_listen(ts->s);
299e18a033bSKonstantin Ananyev	else
300e18a033bSKonstantin Ananyev		rc = -rte_errno;
301e18a033bSKonstantin Ananyev
302e18a033bSKonstantin Ananyev	if (rc != 0) {
303e18a033bSKonstantin Ananyev		term_sock(ts);
304e18a033bSKonstantin Ananyev		put_sock(&stbl.lstn, ts);
305e18a033bSKonstantin Ananyev		errno = -rc;
306e18a033bSKonstantin Ananyev		return -1;
307e18a033bSKonstantin Ananyev	}
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev	return SOCK_TO_SD(ts);
310e18a033bSKonstantin Ananyev}
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev/*
313e18a033bSKonstantin Ananyev * socket API
314e18a033bSKonstantin Ananyev */
315e18a033bSKonstantin Ananyev
316e18a033bSKonstantin Ananyevint
317e18a033bSKonstantin Ananyevclose(int sd)
318e18a033bSKonstantin Ananyev{
319e18a033bSKonstantin Ananyev	int32_t rc;
320e18a033bSKonstantin Ananyev	struct tldk_sock *ts;
321e18a033bSKonstantin Ananyev
322e18a033bSKonstantin Ananyev	FE_TRACE("worker#%lu: %s(%d);\n",
323e18a033bSKonstantin Ananyev		ngx_worker, __func__, sd);
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev	ts = sd_to_sock(sd);
326e18a033bSKonstantin Ananyev	if (ts == NULL)
327e18a033bSKonstantin Ananyev		return real_close(sd);
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev	sock_stat.nb_close++;
330e18a033bSKonstantin Ananyev
331e18a033bSKonstantin Ananyev	rc = close_sock(ts);
332e18a033bSKonstantin Ananyev	if (rc != 0) {
333e18a033bSKonstantin Ananyev		errno =-rc;
334e18a033bSKonstantin Ananyev		return -1;
335e18a033bSKonstantin Ananyev	}
336e18a033bSKonstantin Ananyev	return 0;
337e18a033bSKonstantin Ananyev}
338e18a033bSKonstantin Ananyev
339e18a033bSKonstantin Ananyevint
340e18a033bSKonstantin Ananyevshutdown(int sd, int how)
341e18a033bSKonstantin Ananyev{
342e18a033bSKonstantin Ananyev	struct tldk_sock *ts;
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyev	FE_TRACE("worker#%lu: %s(%d, %#x);\n",
345e18a033bSKonstantin Ananyev		ngx_worker, __func__, sd, how);
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev	ts = sd_to_sock(sd);
348e18a033bSKonstantin Ananyev	if (ts == NULL)
349e18a033bSKonstantin Ananyev		return real_shutdown(sd, how);
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev	sock_stat.nb_shutdown++;
352e18a033bSKonstantin Ananyev
353e18a033bSKonstantin Ananyev	errno = ENOTSUP;
354e18a033bSKonstantin Ananyev	return -1;
355e18a033bSKonstantin Ananyev}
356e18a033bSKonstantin Ananyev
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyevint
359e18a033bSKonstantin Ananyevaccept4(int sd, struct sockaddr *addr, socklen_t *addrlen, int flags)
360e18a033bSKonstantin Ananyev{
361e18a033bSKonstantin Ananyev	uint32_t n, slen;
362e18a033bSKonstantin Ananyev	struct tle_stream *s;
363e18a033bSKonstantin Ananyev	struct tldk_sock *cs, *ts;
364e18a033bSKonstantin Ananyev	struct tle_tcp_stream_cfg prm;
365e18a033bSKonstantin Ananyev	struct tle_tcp_stream_addr sa;
366e18a033bSKonstantin Ananyev
367e18a033bSKonstantin Ananyev	FE_TRACE("worker#%lu: %s(%d, %p, %p, %#x);\n",
368e18a033bSKonstantin Ananyev		ngx_worker, __func__, sd, addr, addrlen, flags);
369e18a033bSKonstantin Ananyev
370e18a033bSKonstantin Ananyev	ts = sd_to_sock(sd);
371e18a033bSKonstantin Ananyev	if (ts == NULL)
372e18a033bSKonstantin Ananyev		return real_accept4(sd, addr, addrlen, flags);
373e18a033bSKonstantin Ananyev	else if (ts->s == NULL) {
374e18a033bSKonstantin Ananyev		errno = EBADF;
375e18a033bSKonstantin Ananyev		return -1;
376e18a033bSKonstantin Ananyev	}
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev	sock_stat.nb_accept++;
379e18a033bSKonstantin Ananyev
380e18a033bSKonstantin Ananyev	n = ts->acpt.num;
381e18a033bSKonstantin Ananyev	if (n == 0) {
382e18a033bSKonstantin Ananyev		n = tle_tcp_stream_accept(ts->s, ts->acpt.buf,
383e18a033bSKonstantin Ananyev			RTE_DIM(ts->acpt.buf));
384e18a033bSKonstantin Ananyev		if (n == 0) {
385e18a033bSKonstantin Ananyev			errno = EAGAIN;
386e18a033bSKonstantin Ananyev			return -1;
387e18a033bSKonstantin Ananyev		}
388e18a033bSKonstantin Ananyev	}
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev	s = ts->acpt.buf[n - 1];
391e18a033bSKonstantin Ananyev	ts->acpt.num = n - 1;
392e18a033bSKonstantin Ananyev
393e18a033bSKonstantin Ananyev	tle_event_raise(ts->rxev);
394e18a033bSKonstantin Ananyev
395e18a033bSKonstantin Ananyev	cs = get_sock(&stbl.free);
396e18a033bSKonstantin Ananyev	if (cs == NULL) {
397e18a033bSKonstantin Ananyev		tle_tcp_stream_close(s);
398e18a033bSKonstantin Ananyev		errno = ENOBUFS;
399e18a033bSKonstantin Ananyev		return -1;
400e18a033bSKonstantin Ananyev	}
401e18a033bSKonstantin Ananyev
402e18a033bSKonstantin Ananyev	cs->s = s;
403e18a033bSKonstantin Ananyev	put_sock(&stbl.use, cs);
404e18a033bSKonstantin Ananyev
405e18a033bSKonstantin Ananyev	tle_event_active(cs->erev, TLE_SEV_DOWN);
406e18a033bSKonstantin Ananyev	tle_event_active(cs->rxev, TLE_SEV_DOWN);
407e18a033bSKonstantin Ananyev	tle_event_active(cs->txev, TLE_SEV_DOWN);
408e18a033bSKonstantin Ananyev
409e18a033bSKonstantin Ananyev	memset(&prm, 0, sizeof(prm));
410e18a033bSKonstantin Ananyev	prm.recv_ev = cs->rxev;
411e18a033bSKonstantin Ananyev	prm.send_ev = cs->txev;
412e18a033bSKonstantin Ananyev	prm.err_ev = cs->erev;
413e18a033bSKonstantin Ananyev	tle_tcp_stream_update_cfg(&s, &prm, 1);
414e18a033bSKonstantin Ananyev
415e18a033bSKonstantin Ananyev	if (tle_tcp_stream_get_addr(s, &sa) == 0) {
416e18a033bSKonstantin Ananyev
417e18a033bSKonstantin Ananyev		if (sa.remote.ss_family == AF_INET)
418e18a033bSKonstantin Ananyev			slen = sizeof(struct sockaddr_in);
419