1 /* distcache, Distributed Session Caching technology
2  * Copyright (C) 2000-2003  Geoff Thorpe, and Cryptographic Appliances, Inc.
3  * Copyright (C) 2004       The Distcache.org project
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; using version 2.1 of the License. The copyright holders
8  * may elect to allow the application of later versions of the License to this
9  * software, please contact the author (geoff@distcache.org) if you wish us to
10  * review any later version released by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #define SYS_GENERATING_LIB
23 
24 #include <libsys/pre.h>
25 #include <libnal/nal.h>
26 #include "nal_internal.h"
27 #include "ctrl_fd.h"
28 #include <libsys/post.h>
29 
30 /**************************/
31 /* predeclare our vtables */
32 /**************************/
33 
34 /* Predeclare the address functions */
35 static int addr_on_create(NAL_ADDRESS *addr);
36 static void addr_on_destroy(NAL_ADDRESS *addr);
37 static int addr_parse(NAL_ADDRESS *addr, const char *addr_string);
38 static int addr_can_connect(const NAL_ADDRESS *addr);
39 static int addr_can_listen(const NAL_ADDRESS *addr);
40 static const NAL_LISTENER_vtable *addr_create_listener(const NAL_ADDRESS *addr);
41 static const NAL_CONNECTION_vtable *addr_create_connection(const NAL_ADDRESS *addr);
42 static const char *addr_prefixes[] = {"IP:", "IPv4:", "UNIX:", NULL};
43 extern NAL_ADDRESS_vtable builtin_sock_addr_vtable;
44 extern NAL_ADDRESS_vtable builtin_fd_addr_vtable;
45 NAL_ADDRESS_vtable builtin_sock_addr_vtable = {
46 	"proto_std",
47 	sizeof(nal_sockaddr),
48 	addr_prefixes,
49 	addr_on_create,
50 	addr_on_destroy,
51 	addr_on_destroy, /* destroy==reset */
52 	NULL, /* pre_close */
53 	addr_parse,
54 	addr_can_connect,
55 	addr_can_listen,
56 	addr_create_listener,
57 	addr_create_connection,
58 	&builtin_fd_addr_vtable
59 };
60 
61 /* Predeclare the listener functions */
62 static int list_on_create(NAL_LISTENER *);
63 static void list_on_destroy(NAL_LISTENER *);
64 static int list_listen(NAL_LISTENER *, const NAL_ADDRESS *);
65 static const NAL_CONNECTION_vtable *list_pre_accept(NAL_LISTENER *);
66 static int list_finished(const NAL_LISTENER *);
67 static int list_pre_selector_add(NAL_LISTENER *, NAL_SELECTOR *);
68 static void list_post_selector_del(NAL_LISTENER *, NAL_SELECTOR *);
69 static void list_pre_select(NAL_LISTENER *, NAL_SELECTOR *, NAL_SELECTOR_TOKEN);
70 static void list_post_select(NAL_LISTENER *, NAL_SELECTOR *, NAL_SELECTOR_TOKEN);
71 static int list_set_fs_owner(NAL_LISTENER *l, const char *ownername,
72 				const char *groupname);
73 static int list_set_fs_perms(NAL_LISTENER *l, const char *octal_string);
74 /* This is the type we attach to our listeners */
75 typedef struct st_list_ctx {
76 	int fd, caught;
77 	nal_sockaddr_type type;
78 } list_ctx;
79 static const NAL_LISTENER_vtable list_vtable = {
80 	sizeof(list_ctx),
81 	list_on_create,
82 	list_on_destroy,
83 	list_on_destroy, /* destroy==reset */
84 	NULL, /* pre_close */
85 	list_listen,
86 	list_pre_accept,
87 	list_finished,
88 	list_pre_selector_add,
89 	NULL, /* post_selector_add */
90 	NULL, /* pre_selector_del */
91 	list_post_selector_del,
92 	list_pre_select,
93 	list_post_select,
94 	list_set_fs_owner,
95 	list_set_fs_perms
96 };
97 
98 /* Predeclare the connection functions */
99 static int conn_on_create(NAL_CONNECTION *);
100 static void conn_on_destroy(NAL_CONNECTION *);
101 static void conn_on_reset(NAL_CONNECTION *);
102 static int conn_connect(NAL_CONNECTION *, const NAL_ADDRESS *);
103 static int conn_accept(NAL_CONNECTION *, const NAL_LISTENER *);
104 static int conn_set_size(NAL_CONNECTION *, unsigned int);
105 static NAL_BUFFER *conn_get_read(const NAL_CONNECTION *);
106 static NAL_BUFFER *conn_get_send(const NAL_CONNECTION *);
107 static int conn_is_established(const NAL_CONNECTION *);
108 static int conn_pre_selector_add(NAL_CONNECTION *, NAL_SELECTOR *);
109 static void conn_post_selector_del(NAL_CONNECTION *, NAL_SELECTOR *);
110 static void conn_pre_select(NAL_CONNECTION *, NAL_SELECTOR *, NAL_SELECTOR_TOKEN);
111 static void conn_post_select(NAL_CONNECTION *, NAL_SELECTOR *, NAL_SELECTOR_TOKEN);
112 static int conn_do_io(NAL_CONNECTION *);
113 /* This is the type we attach to our connections */
114 typedef struct st_conn_ctx {
115 	int fd, established;
116 	unsigned char flags;
117 	NAL_BUFFER *b_read;
118 	NAL_BUFFER *b_send;
119 } conn_ctx;
120 static const NAL_CONNECTION_vtable conn_vtable = {
121 	sizeof(conn_ctx),
122 	conn_on_create,
123 	conn_on_destroy,
124 	conn_on_reset,
125 	NULL, /* pre_close */
126 	conn_connect,
127 	conn_accept,
128 	conn_set_size,
129 	conn_get_read,
130 	conn_get_send,
131 	conn_is_established,
132 	conn_pre_selector_add,
133 	NULL, /* post_selector_add */
134 	NULL, /* pre_selector_del */
135 	conn_post_selector_del,
136 	conn_pre_select,
137 	conn_post_select,
138 	conn_do_io
139 };
140 
141 /***********/
142 /* globals */
143 /***********/
144 
145 /* This flag, if set to zero, will cause new ipv4 connections to have the Nagle
146  * algorithm turned off (by setting TCP_NODELAY). */
147 static int gb_use_nagle = 0;
148 
149 /*****************/
150 /* API functions */
151 /*****************/
152 
NAL_config_set_nagle(int enabled)153 void NAL_config_set_nagle(int enabled)
154 {
155 	gb_use_nagle = enabled;
156 }
157 
NAL_CONNECTION_create_pair(NAL_CONNECTION * conn1,NAL_CONNECTION * conn2,unsigned int def_buffer_size)158 int NAL_CONNECTION_create_pair(NAL_CONNECTION *conn1,
159 				NAL_CONNECTION *conn2,
160 				unsigned int def_buffer_size)
161 {
162 	int fds[2];
163 	conn_ctx *ctx1, *ctx2;
164 	if(nal_connection_get_vtable(conn1) || nal_connection_get_vtable(conn2))
165 		return 0;
166 	if(!nal_connection_set_vtable(conn1, &conn_vtable) ||
167 			!nal_connection_set_vtable(conn2, &conn_vtable))
168 		return 0;
169 	if(!NAL_CONNECTION_set_size(conn1, def_buffer_size) ||
170 			!NAL_CONNECTION_set_size(conn2, def_buffer_size))
171 		return 0;
172 	if(!nal_sock_create_unix_pair(fds))
173 		return 0;
174 	if(!nal_fd_make_non_blocking(fds[0], 1) ||
175 			!nal_fd_make_non_blocking(fds[1], 1) ||
176 			!nal_sock_set_nagle(fds[0], gb_use_nagle, nal_sockaddr_type_unix) ||
177 			!nal_sock_set_nagle(fds[1], gb_use_nagle, nal_sockaddr_type_unix)) {
178 		nal_fd_close(fds);
179 		nal_fd_close(fds + 1);
180 		return 0;
181 	}
182 	ctx1 = nal_connection_get_vtdata(conn1);
183 	ctx2 = nal_connection_get_vtdata(conn2);
184 	ctx1->fd = fds[0];
185 	ctx2->fd = fds[1];
186 	ctx1->established = 1;
187 	ctx2->established = 1;
188 	ctx1->flags = ctx2->flags = 0;
189 	return 1;
190 }
191 
192 /**************************************/
193 /* Implementation of address handlers */
194 /**************************************/
195 
addr_on_create(NAL_ADDRESS * addr)196 static int addr_on_create(NAL_ADDRESS *addr)
197 {
198 	return 1;
199 }
200 
addr_on_destroy(NAL_ADDRESS * addr)201 static void addr_on_destroy(NAL_ADDRESS *addr)
202 {
203 }
204 
addr_parse(NAL_ADDRESS * addr,const char * addr_string)205 static int addr_parse(NAL_ADDRESS *addr, const char *addr_string)
206 {
207 	char *tmp_ptr;
208 	nal_sockaddr *ctx;
209 	int len;
210 
211 	/* The addresses we support all start with a protocol followed by a
212 	 * colon. */
213 	tmp_ptr = strchr(addr_string, ':');
214 	if(!tmp_ptr) return 0;
215 	/* How long is the prefix to the ':'? */
216 	len = (tmp_ptr - addr_string);
217 	if(len < 1) return 0;
218 	/* Make 'tmp_ptr' point to what remains after the ':' */
219 	tmp_ptr++;
220 	/* Retrieve the context we keep attached to NAL_ADDRESS */
221 	ctx = nal_address_get_vtdata(addr);
222 	/* Parse the string */
223 	if(((len == 4) && (strncmp(addr_string, "IPv4", 4) == 0)) ||
224 			((len == 2) && (strncmp(addr_string, "IP", 2) == 0))) {
225 		if(!nal_sock_sockaddr_from_ipv4(ctx, tmp_ptr))
226 			return 0;
227 	} else if((len == 4) && (strncmp(addr_string, "UNIX", 4) == 0)) {
228 		if(!nal_sock_sockaddr_from_unix(ctx, tmp_ptr))
229 			return 0;
230 	} else
231 		/* Unknown prefix */
232 		return 0;
233 	/* Success */
234 	return 1;
235 }
236 
addr_can_connect(const NAL_ADDRESS * addr)237 static int addr_can_connect(const NAL_ADDRESS *addr)
238 {
239 	nal_sockaddr *ctx = nal_address_get_vtdata(addr);
240 	return ((ctx->caps & NAL_ADDRESS_CAN_CONNECT) ? 1 : 0);
241 }
242 
addr_can_listen(const NAL_ADDRESS * addr)243 static int addr_can_listen(const NAL_ADDRESS *addr)
244 {
245 	nal_sockaddr *ctx = nal_address_get_vtdata(addr);
246 	return ((ctx->caps & NAL_ADDRESS_CAN_LISTEN) ? 1 : 0);
247 }
248 
addr_create_listener(const NAL_ADDRESS * addr)249 static const NAL_LISTENER_vtable *addr_create_listener(const NAL_ADDRESS *addr)
250 {
251 	return &list_vtable;
252 }
253 
addr_create_connection(const NAL_ADDRESS * addr)254 static const NAL_CONNECTION_vtable *addr_create_connection(const NAL_ADDRESS *addr)
255 {
256 	return &conn_vtable;
257 }
258 
259 /******************************************/
260 /* Implementation of list_vtable handlers */
261 /******************************************/
262 
list_on_create(NAL_LISTENER * l)263 static int list_on_create(NAL_LISTENER *l)
264 {
265 	return 1;
266 }
267 
list_on_destroy(NAL_LISTENER * l)268 static void list_on_destroy(NAL_LISTENER *l)
269 {
270 	list_ctx *ctx = nal_listener_get_vtdata(l);
271 	nal_fd_close(&ctx->fd);
272 	ctx->caught = 0;
273 }
274 
list_listen(NAL_LISTENER * l,const NAL_ADDRESS * addr)275 static int list_listen(NAL_LISTENER *l, const NAL_ADDRESS *addr)
276 {
277 	nal_sockaddr *ctx_addr = nal_address_get_vtdata(addr);
278 	list_ctx *ctx_listener = nal_listener_get_vtdata(l);
279 	ctx_listener->fd = -1;
280 	if(!nal_sock_create_socket(&ctx_listener->fd, ctx_addr) ||
281 			!nal_fd_make_non_blocking(ctx_listener->fd, 1) ||
282 			!nal_sock_listen(ctx_listener->fd, ctx_addr)) {
283 		nal_fd_close(&ctx_listener->fd);
284 		return 0;
285 	}
286 	ctx_listener->type = ctx_addr->type;
287 	return 1;
288 }
289 
list_pre_accept(NAL_LISTENER * l)290 static const NAL_CONNECTION_vtable *list_pre_accept(NAL_LISTENER *l)
291 {
292 	list_ctx *ctx = nal_listener_get_vtdata(l);
293 	if(ctx->caught) {
294 		/* ctx->caught = 0; */ /* this is unset in conn::accept */
295 		return &conn_vtable;
296 	}
297 	return NULL;
298 }
299 
list_finished(const NAL_LISTENER * l)300 static int list_finished(const NAL_LISTENER *l)
301 {
302 	return 0;
303 }
304 
list_pre_selector_add(NAL_LISTENER * l,NAL_SELECTOR * sel)305 static int list_pre_selector_add(NAL_LISTENER *l, NAL_SELECTOR *sel)
306 {
307 	switch(nal_selector_get_type(sel)) {
308 	case NAL_SELECTOR_TYPE_FDSELECT:
309 	case NAL_SELECTOR_TYPE_FDPOLL:
310 		return 1;
311 	case NAL_SELECTOR_TYPE_DYNAMIC:
312 		return nal_selector_dynamic_set(sel, NAL_SELECTOR_VT_DEFAULT());
313 	default:
314 		break;
315 	}
316 	return 0;
317 }
318 
list_post_selector_del(NAL_LISTENER * l,NAL_SELECTOR * sel)319 static void list_post_selector_del(NAL_LISTENER *l, NAL_SELECTOR *sel)
320 {
321 	list_ctx *ctx = nal_listener_get_vtdata(l);
322 	ctx->caught = 0;
323 }
324 
list_pre_select(NAL_LISTENER * l,NAL_SELECTOR * sel,NAL_SELECTOR_TOKEN tok)325 static void list_pre_select(NAL_LISTENER *l, NAL_SELECTOR *sel,
326 			NAL_SELECTOR_TOKEN tok)
327 {
328 	list_ctx *ctx = nal_listener_get_vtdata(l);
329 	if(!ctx->caught)
330 		nal_selector_fd_set(sel, tok, ctx->fd, SELECTOR_FLAG_READ);
331 }
332 
list_post_select(NAL_LISTENER * l,NAL_SELECTOR * sel,NAL_SELECTOR_TOKEN tok)333 static void list_post_select(NAL_LISTENER *l, NAL_SELECTOR *sel,
334 			NAL_SELECTOR_TOKEN tok)
335 {
336 	unsigned char flags;
337 	list_ctx *ctx = nal_listener_get_vtdata(l);
338 	/* We detect readability on the listener socket and set "caught". */
339 	nal_selector_fd_test(&flags, sel, tok, ctx->fd);
340 	if(flags & SELECTOR_FLAG_READ) {
341 		/* We shouldn't have been selectable if this was already set */
342 		assert(!ctx->caught);
343 		ctx->caught = 1;
344 	}
345 }
346 
list_set_fs_owner(NAL_LISTENER * l,const char * ownername,const char * groupname)347 static int list_set_fs_owner(NAL_LISTENER *l, const char *ownername,
348 				const char *groupname)
349 {
350 	nal_sockaddr sa;
351 	list_ctx *ctx = nal_listener_get_vtdata(l);
352 	if(ctx->type != nal_sockaddr_type_unix) return 0;
353 	if(!nal_sockaddr_get(&sa, ctx->fd)) return 0;
354 	return nal_sockaddr_chown(&sa, ownername, groupname);
355 }
356 
list_set_fs_perms(NAL_LISTENER * l,const char * octal_string)357 static int list_set_fs_perms(NAL_LISTENER *l, const char *octal_string)
358 {
359 	nal_sockaddr sa;
360 	list_ctx *ctx = nal_listener_get_vtdata(l);
361 	if(ctx->type != nal_sockaddr_type_unix) return 0;
362 	if(!nal_sockaddr_get(&sa, ctx->fd)) return 0;
363 	return nal_sockaddr_chmod(&sa, octal_string);
364 }
365 
366 /******************************************/
367 /* Implementation of conn_vtable handlers */
368 /******************************************/
369 
370 /* internal function shared by conn_connect and conn_accept */
conn_ctx_setup(conn_ctx * ctx_conn,int fd,int established,unsigned int buf_size)371 static int conn_ctx_setup(conn_ctx *ctx_conn, int fd, int established,
372 				unsigned int buf_size)
373 {
374 	if(!NAL_BUFFER_set_size(ctx_conn->b_read, buf_size) ||
375 			!NAL_BUFFER_set_size(ctx_conn->b_send, buf_size))
376 		return 0;
377 	ctx_conn->fd = fd;
378 	ctx_conn->established = established;
379 	return 1;
380 }
381 
conn_on_create(NAL_CONNECTION * conn)382 static int conn_on_create(NAL_CONNECTION *conn)
383 {
384 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
385 	if(!ctx->b_read) ctx->b_read = NAL_BUFFER_new();
386 	if(!ctx->b_send) ctx->b_send = NAL_BUFFER_new();
387 	if(!ctx->b_read || !ctx->b_send) return 0;
388 	ctx->fd = -1;
389 	return 1;
390 }
391 
conn_on_destroy(NAL_CONNECTION * conn)392 static void conn_on_destroy(NAL_CONNECTION *conn)
393 {
394 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
395 	nal_fd_close(&ctx->fd);
396 	NAL_BUFFER_free(ctx->b_read);
397 	NAL_BUFFER_free(ctx->b_send);
398 }
399 
conn_on_reset(NAL_CONNECTION * conn)400 static void conn_on_reset(NAL_CONNECTION *conn)
401 {
402 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
403 	nal_fd_close(&ctx->fd);
404 	NAL_BUFFER_reset(ctx->b_read);
405 	NAL_BUFFER_reset(ctx->b_send);
406 	ctx->flags = 0;
407 	ctx->established = 0;
408 }
409 
conn_connect(NAL_CONNECTION * conn,const NAL_ADDRESS * addr)410 static int conn_connect(NAL_CONNECTION *conn, const NAL_ADDRESS *addr)
411 {
412 	int fd = -1, established;
413 	const nal_sockaddr *ctx_addr = nal_address_get_vtdata(addr);
414 	conn_ctx *ctx_conn = nal_connection_get_vtdata(conn);
415 	if(!nal_sock_create_socket(&fd, ctx_addr) ||
416 			!nal_fd_make_non_blocking(fd, 1) ||
417 			!nal_sock_connect(fd, ctx_addr, &established) ||
418 			!nal_sock_set_nagle(fd, gb_use_nagle, ctx_addr->type) ||
419 			!conn_ctx_setup(ctx_conn, fd, established,
420 				NAL_ADDRESS_get_def_buffer_size(addr)))
421 		goto err;
422 	return 1;
423 err:
424 	nal_fd_close(&fd);
425 	return 0;
426 }
427 
conn_accept(NAL_CONNECTION * conn,const NAL_LISTENER * l)428 static int conn_accept(NAL_CONNECTION *conn, const NAL_LISTENER *l)
429 {
430 	int fd = -1;
431 	list_ctx *ctx_list = nal_listener_get_vtdata(l);
432 	conn_ctx *ctx_conn = nal_connection_get_vtdata(conn);
433 	assert(ctx_list->caught);
434 	if(!nal_sock_accept(ctx_list->fd, &fd)) {
435 #if 0 /* We only support one accept per readability so this stuff simply shouldn't occur */
436 		switch(errno) {
437 		case EAGAIN:
438 #if EAGAIN != EWOULDBLOCK
439 		case EWOULDBLOCK:
440 #endif
441 			/* We've exhausted the listen queue for now */
442 			ctx_list->caught = 0;
443 			break;
444 		default:
445 			break;
446 		}
447 #endif
448 		goto err;
449 	}
450 	ctx_list->caught = 0;
451 	if(!nal_fd_make_non_blocking(fd, 1) ||
452 			!nal_sock_set_nagle(fd, gb_use_nagle, ctx_list->type) ||
453 			!conn_ctx_setup(ctx_conn, fd, 1,
454 				nal_listener_get_def_buffer_size(l)))
455 		goto err;
456 	return 1;
457 err:
458 	nal_fd_close(&fd);
459 	return 0;
460 }
461 
conn_set_size(NAL_CONNECTION * conn,unsigned int size)462 static int conn_set_size(NAL_CONNECTION *conn, unsigned int size)
463 {
464 	conn_ctx *ctx_conn = nal_connection_get_vtdata(conn);
465 	if(!NAL_BUFFER_set_size(ctx_conn->b_read, size) ||
466 			!NAL_BUFFER_set_size(ctx_conn->b_send, size))
467 		return 0;
468 	return 1;
469 }
470 
conn_get_read(const NAL_CONNECTION * conn)471 static NAL_BUFFER *conn_get_read(const NAL_CONNECTION *conn)
472 {
473 	conn_ctx *ctx_conn = nal_connection_get_vtdata(conn);
474 	return ctx_conn->b_read;
475 }
476 
conn_get_send(const NAL_CONNECTION * conn)477 static NAL_BUFFER *conn_get_send(const NAL_CONNECTION *conn)
478 {
479 	conn_ctx *ctx_conn = nal_connection_get_vtdata(conn);
480 	return ctx_conn->b_send;
481 }
482 
conn_is_established(const NAL_CONNECTION * conn)483 static int conn_is_established(const NAL_CONNECTION *conn)
484 {
485 	conn_ctx *ctx_conn = nal_connection_get_vtdata(conn);
486 	return ctx_conn->established;
487 }
488 
conn_pre_selector_add(NAL_CONNECTION * conn,NAL_SELECTOR * sel)489 static int conn_pre_selector_add(NAL_CONNECTION *conn, NAL_SELECTOR *sel)
490 {
491 	switch(nal_selector_get_type(sel)) {
492 	case NAL_SELECTOR_TYPE_FDSELECT:
493 	case NAL_SELECTOR_TYPE_FDPOLL:
494 		return 1;
495 	case NAL_SELECTOR_TYPE_DYNAMIC:
496 		return nal_selector_dynamic_set(sel, NAL_SELECTOR_VT_DEFAULT());
497 	default:
498 		break;
499 	}
500 	return 0;
501 }
502 
conn_post_selector_del(NAL_CONNECTION * conn,NAL_SELECTOR * sel)503 static void conn_post_selector_del(NAL_CONNECTION *conn, NAL_SELECTOR *sel)
504 {
505 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
506 	ctx->flags = 0;
507 }
508 
conn_pre_select(NAL_CONNECTION * conn,NAL_SELECTOR * sel,NAL_SELECTOR_TOKEN token)509 static void conn_pre_select(NAL_CONNECTION *conn, NAL_SELECTOR *sel,
510 			NAL_SELECTOR_TOKEN token)
511 {
512 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
513 	nal_selector_fd_set(sel, token, ctx->fd,
514 		/* Do we select for readability? Only if connection is complete
515 		 * and there is space in the buffer. */
516 		(ctx->established && NAL_BUFFER_notfull(ctx->b_read) ?
517 			SELECTOR_FLAG_READ : 0) |
518 		/* Do we select for writability? We do if the connection isn't
519 		 * complete or there is data in the buffer to be sent. */
520 		(!ctx->established || NAL_BUFFER_notempty(ctx->b_send) ?
521 			SELECTOR_FLAG_SEND : 0) |
522 		SELECTOR_FLAG_EXCEPT);
523 }
524 
conn_post_select(NAL_CONNECTION * conn,NAL_SELECTOR * sel,NAL_SELECTOR_TOKEN token)525 static void conn_post_select(NAL_CONNECTION *conn, NAL_SELECTOR *sel,
526 			NAL_SELECTOR_TOKEN token)
527 {
528 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
529 	nal_selector_fd_test(&ctx->flags, sel, token, ctx->fd);
530 }
531 
conn_do_io(NAL_CONNECTION * conn)532 static int conn_do_io(NAL_CONNECTION *conn)
533 {
534 	int nb = 0;
535 	conn_ctx *ctx = nal_connection_get_vtdata(conn);
536 	if(ctx->flags & SELECTOR_FLAG_EXCEPT) return 0;
537 	/* If we're waiting on a non-blocking connect, hook the test here */
538 	if(!ctx->established) {
539 		/* We need to be sendable after a non-blocking connect */
540 		if(!(ctx->flags & SELECTOR_FLAG_SEND))
541 			return 1;
542 		/* Connect or error? */
543 		if(!nal_sock_is_connected(ctx->fd))
544 			return 0;
545 		ctx->established = 1;
546 		/* this is the case where sendability is OK when there's
547 		 * nothing to send */
548 		nb = 1;
549 	}
550 	if(ctx->flags & SELECTOR_FLAG_READ) {
551 		int io_ret = nal_fd_buffer_from_fd(ctx->b_read, ctx->fd, 0);
552 		/* zero shouldn't happen if we're readable, and negative is err */
553 		if(io_ret <= 0)
554 			return 0;
555 	}
556 	if(ctx->flags & SELECTOR_FLAG_SEND) {
557 		int io_ret = nal_fd_buffer_to_fd(ctx->b_send, ctx->fd, 0);
558 		if((io_ret < 0) || (!io_ret && !nb))
559 			return 0;
560 	}
561 	ctx->flags = 0;
562 	return 1;
563 }
564 
565