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