1 /* url-socket.c - File namespace extensions.
2 *
3 ****************************************************************
4 * Copyright (C) 1999, 2000 Thomas Lord
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11
12 #include "hackerlab/os/alloca.h"
13 #include "hackerlab/os/errno.h"
14 #include "hackerlab/os/sys/param.h"
15 #include "hackerlab/os/sys/socket.h"
16 #include "hackerlab/bugs/panic.h"
17 #include "hackerlab/char/char-class.h"
18 #include "hackerlab/char/str.h"
19 #include "hackerlab/mem/mem.h"
20 #include "hackerlab/mem/must-malloc.h"
21 #include "hackerlab/arrays/ar.h"
22 #include "hackerlab/fmt/cvt.h"
23 #include "hackerlab/fs/file-names.h"
24 #include "hackerlab/vu/vu-sys.h"
25 #include "hackerlab/vu/vu-bad-arg.h"
26 #include "hackerlab/vu-network/url-socket.h"
27
28
29 /************************************************************************
30 *(h0 "A VU Handler for the URL Socket Scheme")
31 *
32 * These functions provide VU namespace handlers for file-names
33 * that designate various kinds of sockets. By using these handlers,
34 * your programs can (almost) transparently handle filenames
35 * like:
36 *
37 * inet://myserver.host.com:10000
38 *
39 * or
40 *
41 * unix:/tmp/.X11-unix/X0
42 *
43 * Two kinds of sockets are available: *server* sockets and *client*
44 * sockets.
45 *
46 * "server sockets" are created with `socket(2)', `bind(2)', and
47 * `listen(2)'. When `vu_open' is called, a call to `listen(2)' is
48 * made and the client connection (if any) is returned.
49 *
50 * "client sockets" are created with `socket(2)', `bind(2)', and
51 * `connect(2)'.
52 *
53 * Sockets may be named in either the `unix' or `inet' domains.
54 *
55 * The syntax of these URLs is described in the documentation for
56 * `url_socket_push_client_handler' and
57 * `url_socket_push_socket_handler'.
58 */
59
60
61 /* struct url_socket_params
62 *
63 * The closure type for every file name pattern than can open a socket
64 * URL. A pointer to one of these structures is used as the closure
65 * when calling `vu_push_name_handler'.
66 *
67 * These closures are copied by must_malloc/mem_move.
68 */
69 struct url_socket_params
70 {
71 enum url_socket_type type; /* What type of socket (server, client, both) is opened by this file name pattern? */
72 enum url_socket_domains domains; /* What domain (unix, inet, both) is opened by this file name pattern? */
73 int server_flags; /* How was the server opened? (O_NONBLOCK, etc.) */
74 int default_port; /* If the port isn't specified in the file name, this is the default. */
75 int backlog; /* For listen(2). */
76 url_socket_server_callback server_callback; /* Called back when a new server socket is created and bound. */
77 url_socket_connect_callback connection_callback; /* Called when a server socket receives a new connection. */
78 url_socket_server_close_callback server_close_callback; /* Called when a server socket is closed. */
79 void * closure; /* A closure for the two callbacks. */
80 };
81
82
83
84 /* url_socket_vtable
85 *
86 * System calls for functions that operate on descriptors, URL
87 * handling for functions that operate on file names.
88 */
89 static struct vu_fs_discipline url_socket_vtable;
90
91
92 /* url_server_socket_vtable
93 *
94 * Errors for most functions. Server shut-down for `vu_close'.
95 */
96 static struct vu_fs_discipline url_server_socket_vtable;
97
98
99 /* __STDC__ prototypes for static functions */
100 static regex_t * url_socket_client_regex (const t_uchar ** name,
101 const t_uchar *** doc,
102 enum url_socket_domains domains,
103 int default_port);
104 static regex_t * url_socket_server_regex (const t_uchar ** name,
105 const t_uchar *** doc,
106 enum url_socket_domains domains,
107 int may_be_client,
108 int default_port);
109 static regex_t * url_socket_only_server_regex (const t_uchar ** name,
110 const t_uchar *** doc,
111 enum url_socket_domains domains,
112 int default_port);
113 static int server_fd_for_addr (int * errn,
114 struct sockaddr * addr,
115 int addr_len,
116 const char * path,
117 int flags,
118 int mode,
119 struct url_socket_params * params);
120 static struct server_memo * find_memo_for_server_fd (int fd);
121 static void remove_memo_for_server_fd (int fd);
122 static int decode_socket_url (int * errn,
123 struct sockaddr * addr,
124 int * addr_len,
125 struct url_socket_params * params,
126 int * be_a_server,
127 const char * path,
128 int be_a_server_hint);
129 static void * url_socket_make_closure (void * closure);
130 static void url_socket_free_closure (void * closure);
131 static int url_socket_open (int * errn, const char * path, int flags, int mode, void * closure);
132 static int url_socket_close (int * errn, int fd, void * closure);
133 static int url_socket_access (int * errn, const char * path, int mode, void * closure);
134 static int url_socket_chdir (int * errn, const char * path, void * closure);
135 static int url_socket_chmod (int * errn, const char * path, int mode, void * closure);
136 static int url_socket_chown (int * errn, const char * path, int owner, int group, void * closure);
137 static int url_socket_chroot (int * errn, const char * path, void * closure);
138 static int url_socket_closedir (int * errn, DIR * dir, void * closure);
139 static int url_socket_fchdir (int * errn, int fd, void * closure);
140 static int url_socket_fchmod (int * errn, int fd, int mode, void * closure);
141 static int url_socket_fchown (int * errn, int fd, int owner, int group, void * closure);
142 static int url_socket_fstat (int * errn, int fd, struct stat * buf, void * closure);
143 static int url_socket_fsync (int * errn, int fd, void * closure);
144 static int url_socket_ftruncate (int * errn, int fd, off_t where, void * closure);
145 static int url_socket_link (int * errn, const char * from, const char * to, void * closure);
146 static off_t url_socket_lseek (int * errn, int fd, off_t offset, int whence, void * closure);
147 static int url_socket_lstat (int * errn, const char * path, struct stat * buf, void * closure);
148 static int url_socket_mkdir (int * errn, const char * path, int mode, void * closure);
149 static int url_socket_opendir (int * errn, DIR ** retv, const char * path, void * closure);
150 static ssize_t url_socket_read (int * errn, int fd, char * buf, size_t count, void * closure);
151 static int url_socket_readdir (int * errn, struct alloc_limits * limits, char ** file_ret, DIR * dir, void * closure);
152 static int url_socket_readlink (int * errn, const char * path, char * buf, int bufsize, void * closure);
153 static int url_socket_rename (int * errn, const char * from, const char * to, void * closure);
154 static int url_socket_rmdir (int * errn, const char * path, void * closure);
155 static int url_socket_stat (int * errn, const char * path, struct stat * buf, void * closure);
156 static int url_socket_symlink (int * errn, const char * from, const char * to, void * closure);
157 static int url_socket_truncate (int * errn, const char * path, off_t where, void * closure);
158 static int url_socket_unlink (int * errn, const char * path, void * closure);
159 static int url_socket_utime (int * errn, const char * path, struct utimbuf * times, void * closure);
160 static ssize_t url_socket_write (int * errn, int fd, const char * buf, size_t count, void * closure);
161 static int url_socket_fcntl (int * errn, int fd, int cmd, long arg, void * closure);
162 static int url_socket_dup (int * errn, int fd, void * closure);
163 static int url_socket_dup2 (int * errn, int fd, int newfd, void * closure);
164 static int url_socket_move_state (int * errn, int fd, int newfd, void * closure);
165 static int url_server_socket_close (int * errn, int fd, void * closure);
166
167
168
169
170
171 /* static regex_t * url_socket_client_regex (const t_uchar * name,
172 * const t_uchar *** doc,
173 * enum url_socket_domains domains,
174 * int default_port);
175 *
176 * Return a file name regexp and namespace option name for client
177 * sockets in the indicated domains.
178 *
179 * Domains: Regexp: Name:
180 * -----------------------------------------------------------
181 * unix unix: client/unix
182 * inet inet:// client/inet
183 * both unix:\|inet:// client/any
184 */
185 static regex_t *
url_socket_client_regex(const t_uchar ** name,const t_uchar *** doc,enum url_socket_domains domains,int default_port)186 url_socket_client_regex (const t_uchar ** name,
187 const t_uchar *** doc,
188 enum url_socket_domains domains,
189 int default_port)
190 {
191 switch (domains)
192 {
193 default:
194 panic ("illegal domains specification to url_socket_push_client_handler");
195 case url_socket_unix:
196 {
197 static int initialized = 0;
198 static regex_t regex;
199 static const t_uchar * docstr[] =
200 {
201 "unix:$PATH",
202 "Client connection to a unix-domain socket.",
203 "$PATH is ~-expanded.",
204 0
205 };
206
207
208 if (!initialized)
209 {
210 if (0 > regcomp (®ex, "^unix:", 0))
211 panic ("unable to compile socket url regexp");
212 initialized = 1;
213 }
214 *name = "client/unix";
215 *doc = docstr;
216 return ®ex;
217 }
218 case url_socket_inet:
219 {
220 static int initialized = 0;
221 static regex_t regex;
222 static const t_uchar * docstr[] =
223 {
224 "inet:$HOST:$PORT",
225 "Client connection to an internet-domain",
226 "socket.",
227 0
228 };
229 static const t_uchar * docstr_opt_port[] =
230 {
231 "inet:$HOST[:$PORT]",
232 "Client connection to an internet-domain",
233 "socket.",
234 0
235 };
236
237 if (!initialized)
238 {
239 if (0 > regcomp (®ex, "^inet://", 0))
240 panic ("unable to compile socket url regexp");
241 initialized = 1;
242 }
243 *name = "client/inet";
244 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
245 return ®ex;
246 }
247 case url_socket_inet_or_unix:
248 {
249 static int initialized = 0;
250 static regex_t regex;
251 static const t_uchar * docstr[] =
252 {
253 "unix:$PATH or inet:$HOST:$PORT",
254 "Client connection to a unix or",
255 "internet domain socket. $PATH",
256 "is ~-expanded.",
257 0
258 };
259 static const t_uchar * docstr_opt_port[] =
260 {
261 "unix:$PATH or inet:$HOST[:$PORT]",
262 "Client connection to a unix or",
263 "internet domain socket. $PATH",
264 "is ~-expanded.",
265 0
266 };
267
268 if (!initialized)
269 {
270 if (0 > regcomp (®ex, "^[[:(unix:\\|inet://):]]", 0))
271 panic ("unable to compile socket url regexp");
272 initialized = 1;
273 }
274 *name = "client/any";
275 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
276 return ®ex;
277 }
278 }
279 }
280
281
282 /* static regex_t * url_socket_server_regex (const t_uchar ** name,
283 * const t_uchar *** doc,
284 * enum url_socket_domains domains,
285 * int may_be_client,
286 * int default_port);
287 *
288 * Return a file name regexp and option argument name for server
289 * sockets in the indicated domains. Regexps that can also be used
290 * for client sockets are included.
291 *
292 * Domains: Regexp:
293 * --------------------------------------
294 * unix unix:\|unix-server:
295 * inet inet://\|inet-server://
296 * both unix:\|unix-server:\|inet://\|inet-server://
297 *
298 * See the comment for `url_socket_push_socket_handler' for the names
299 * associated with each combination of `domains' and `may_be_client'.
300 */
301 static regex_t *
url_socket_server_regex(const t_uchar ** name,const t_uchar *** doc,enum url_socket_domains domains,int may_be_client,int default_port)302 url_socket_server_regex (const t_uchar ** name,
303 const t_uchar *** doc,
304 enum url_socket_domains domains,
305 int may_be_client,
306 int default_port)
307 {
308 switch (domains)
309 {
310 default:
311 panic ("illegal domains specification to url_socket_push_client_handler");
312 case url_socket_unix:
313 {
314 static int initialized = 0;
315 static regex_t regex;
316
317 if (!initialized)
318 {
319 if (0 > regcomp (®ex, "^[[:(unix:\\|unix-server:):]]", 0))
320 panic ("unable to compile socket url regexp");
321 initialized = 1;
322 }
323 if (may_be_client)
324 {
325 static const t_uchar * docstr[] =
326 {
327 "unix:$PATH or unix-server:$PATH",
328 "Be a server or client for a unix-domain",
329 "socket. $PATH is ~-expanded.",
330 0
331 };
332 *name = "socket/unix";
333 *doc = docstr;
334 }
335 else
336 {
337 static const t_uchar * docstr[] =
338 {
339 "unix:$PATH or unix-server:$PATH",
340 "Be a server for a unix-domain socket.",
341 "$PATH is ~-expanded.",
342 0
343 };
344 *name = "server/unix";
345 *doc = docstr;
346 }
347 return ®ex;
348 }
349 case url_socket_inet:
350 {
351 static int initialized = 0;
352 static regex_t regex;
353
354 if (!initialized)
355 {
356 if (0 > regcomp (®ex, "^[[:(inet://\\|inet-server://):]]", 0))
357 panic ("unable to compile socket url regexp");
358 initialized = 1;
359 }
360 if (may_be_client)
361 {
362 static const t_uchar * docstr[] =
363 {
364 "inet:$HOST:$PORT",
365 " or inet-server:$PATH:$PORT",
366 "Be a server or client for an",
367 "internet-domain socket.",
368 0
369 };
370 static const t_uchar * docstr_opt_port[] =
371 {
372 "inet:$HOST[:$PORT]",
373 " or inet-server:$PATH[:$PORT]",
374 "Be a server or client for an",
375 "internet-domain socket.",
376 0
377 };
378 *name = "socket/inet";
379 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
380 }
381 else
382 {
383 static const t_uchar * docstr[] =
384 {
385 "inet:$HOST:$PORT",
386 " or inet-server:$PATH:$PORT",
387 "Be a server for an internet-domain",
388 "socket.",
389 0
390 };
391 static const t_uchar * docstr_opt_port[] =
392 {
393 "inet:$HOST[:$PORT]",
394 " or inet-server:$PATH[:$PORT]",
395 "Be a server for an internet-domain",
396 "socket.",
397 0
398 };
399 *name = "server/inet";
400 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
401 }
402 return ®ex;
403 }
404 case url_socket_inet_or_unix:
405 {
406 static int initialized = 0;
407 static regex_t regex;
408 if (!initialized)
409 {
410 if (0 > regcomp (®ex, "^[[:(unix:\\|unix-server:\\|inet://\\|inet-server://):]]", 0))
411 panic ("unable to compile socket url regexp");
412 initialized = 1;
413 }
414 if (may_be_client)
415 {
416 static const t_uchar * docstr[] =
417 {
418 "unix:$PATH, unix-server:$PATH",
419 "inet:$HOST:$PORT",
420 "or inet-server:$HOST:$PORT",
421 "Be a client or server for a unix or",
422 "internet domain socket. $PATH is",
423 "~-expanded.",
424 0
425 };
426 static const t_uchar * docstr_opt_port[] =
427 {
428 "unix:$PATH, unix-server:$PATH",
429 "inet:$HOST:[$PORT]",
430 "or inet-server:$HOST:[$PORT]",
431 "Be client or a server for a unix or internet",
432 "domain socket. $PATH is ~-expanded.",
433 0
434 };
435 *name = "socket/any";
436 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
437 }
438 else
439 {
440 static const t_uchar * docstr[] =
441 {
442 "unix:$PATH, unix-server:$PATH",
443 "inet:$HOST:$PORT",
444 "or inet-server:$HOST:$PORT",
445 "Be a server for a unix or internet",
446 "internet domain socket. $PATH is",
447 "~-expanded.",
448 0
449 };
450 static const t_uchar * docstr_opt_port[] =
451 {
452 "unix:$PATH, unix-server:$PATH",
453 "inet:$HOST:[$PORT]",
454 "or inet-server:$HOST:[$PORT]",
455 "Be server for a unix or internet domain",
456 "socket. $PATH is ~-expanded.",
457 0
458 };
459 *name = "server/any";
460 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
461 }
462 return ®ex;
463 }
464 }
465 }
466
467
468 /* static regex_t * url_socket_only_server_regex (const t_uchar ** name,
469 * const t_uchar *** doc,
470 * enum url_socket_domains domains,
471 * int default_port);
472 *
473 * Return a file name regexp and option argument name for server
474 * sockets in the indicated domains. Regexps that can also be used
475 * for client sockets are excluded.
476 *
477 * Domains: Regexp:
478 * --------------------------------------
479 * unix unix-server:
480 * inet inet-server://
481 * both unix-server:\|inet-server://
482 *
483 * See the comment for `url_socket_push_socket_handler' for the names
484 * associated with each domain.
485 */
486 static regex_t *
url_socket_only_server_regex(const t_uchar ** name,const t_uchar *** doc,enum url_socket_domains domains,int default_port)487 url_socket_only_server_regex (const t_uchar ** name,
488 const t_uchar *** doc,
489 enum url_socket_domains domains,
490 int default_port)
491 {
492 switch (domains)
493 {
494 default:
495 panic ("illegal domains specification to url_socket_push_client_handler");
496 case url_socket_unix:
497 {
498 static int initialized = 0;
499 static regex_t regex;
500 static const t_uchar * docstr[] =
501 {
502 "unix-server:$PATH",
503 "Be a server for a unix-domain socket.",
504 "$PATH is ~-expanded.",
505 0
506 };
507
508 if (!initialized)
509 {
510 if (0 > regcomp (®ex, "^unix-server:", 0))
511 panic ("unable to compile socket url regexp");
512 initialized = 1;
513 }
514 *name = "socket/unix-server";
515 *doc = docstr;
516 return ®ex;
517 }
518 case url_socket_inet:
519 {
520 static int initialized = 0;
521 static regex_t regex;
522 static const t_uchar * docstr[] =
523 {
524 "inet-server:$PATH:$PORT",
525 "Be a server for an internet-domain",
526 "socket.",
527 0
528 };
529 static const t_uchar * docstr_opt_port[] =
530 {
531 "inet-server:$PATH[:$PORT]",
532 "Be a server for an internet-domain",
533 "socket.",
534 0
535 };
536
537 if (!initialized)
538 {
539 if (0 > regcomp (®ex, "^inet-server://", 0))
540 panic ("unable to compile socket url regexp");
541 initialized = 1;
542 }
543 *name = "socket/inet-server";
544 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
545 return ®ex;
546 }
547 case url_socket_inet_or_unix:
548 {
549 static int initialized = 0;
550 static regex_t regex;
551 static const t_uchar * docstr[] =
552 {
553 "unix-server:$PATH",
554 "or inet-server:$HOST:$PORT",
555 "Be a server for a unix or internet",
556 "internet domain socket. $PATH is",
557 "~-expanded.",
558 0
559 };
560 static const t_uchar * docstr_opt_port[] =
561 {
562 "unix-server:$PATH",
563 "or inet-server:$HOST:[$PORT]",
564 "Be server for a unix or internet domain",
565 "socket. $PATH is ~-expanded.",
566 0
567 };
568
569 if (!initialized)
570 {
571 if (0 > regcomp (®ex, "^[[:(unix-server:\\|inet-server://):]]", 0))
572 panic ("unable to compile socket url regexp");
573 initialized = 1;
574 }
575 *name = "socket/any-server";
576 *doc = ((default_port < 0) ? docstr : docstr_opt_port);
577 return ®ex;
578 }
579 }
580 }
581
582
583
584 /*(c url_socket_push_client_handler)
585 * void url_socket_push_client_handler (enum url_socket_domains domains,
586 * int default_port,
587 * int is_optional);
588 *
589 * Push a VU namespace handler for client sockets.
590 *
591 * Domains: File Name:
592 * ------------------------------------------------------------------
593 * url_socket_unix unix:$PATH
594 * url_socket_inet inet://$HOST[:$PORT]
595 * url_socket_inet_or_unix unix:$PATH or inet://$HOST[:$PORT]
596 *
597 * Note that the `$PATH' of a unix domain socket is subject to "~" expansion
598 * using `file_name_tilde_expand'.
599 *
600 * (See xref:"file_name_tilde_expand".)
601 *
602 * `default_port' is used for internet-domain sockets.
603 *
604 * If `is_optional' is 0, the handler is immediately added to the VU namespace.
605 * If `is_optional' is not 0, the handler is added to the list of optional
606 * handlers and may be enabled by `vu_enable_optional_name_handler'.
607 *
608 * (See xref:"vu_enable_optional_name_handler".)
609 *
610 *
611 * Domains: Optional Handler Name:
612 * ------------------------------------------------------------------
613 * url_socket_unix client/unix
614 * url_socket_inet client/inet
615 * url_socket_inet_or_unix client/any
616 *
617 */
618 void
url_socket_push_client_handler(enum url_socket_domains domains,int default_port,int is_optional)619 url_socket_push_client_handler (enum url_socket_domains domains,
620 int default_port,
621 int is_optional)
622 {
623 regex_t * regex;
624 struct url_socket_params params;
625 const t_uchar * name;
626 const t_uchar ** doc;
627
628 regex = url_socket_client_regex (&name, &doc, domains, default_port);
629 params.type = url_socket_client;
630 params.domains = domains;
631 params.default_port = default_port;
632 params.backlog = 0;
633 params.server_callback = 0;
634 params.connection_callback = 0;
635 params.server_close_callback = 0;
636 vu_push_name_handler (name, doc, regex, 0, &url_socket_vtable, (void *)¶ms, is_optional);
637 }
638
639
640 /*(c url_socket_push_socket_handler)
641 * void url_socket_push_socket_handler
642 * (enum url_socket_domains domains,
643 * int server_flags,
644 * int may_be_client,
645 * int only_server_url,
646 * int default_port,
647 * int backlog,
648 * url_socket_server_callback server_callback,
649 * url_socket_connect_callback connection_callback,
650 * url_socket_server_close_callback server_close_callback,
651 * void * closure,
652 * is_optional);
653 *
654 * Push a VU namespace handler for server sockets. After this call, a
655 * call to `vu_open' with a suitable file name will work by creating a
656 * socket.
657 *
658 * `server_flags' may be any bitwise combination of:
659 *
660 * O_NONBLOCK # Don't block waiting for connections.
661 *
662 * There are two kinds of file name patterns: those that can be used
663 * to name both clients and servers, and those that can only be used
664 * to name servers:
665 *
666 * server only: client or server:
667 * -------------------------------------------------
668 * unix-server:$PATH unix:$PATH
669 * inet-server://$HOST[:$PORT] inet://$HOST[:$PORT]
670 *
671 * By default, both kinds of URL are accepted and interpreted as names
672 * of server sockets. Note that:
673 *
674 * `$PATH' of a unix domain socket is subject to "~" expansion using
675 * `file_name_tilde_expand'.
676 *
677 * `$HOST' of an internet-domain socket may be `INADDR_LOOPBACK'.
678 * If the URL is the name of a server, `$HOST' may also be
679 * `INADDR_ANY'. (See `inet(4)'.)
680 *
681 * `$PORT' of an internet-domain server may be 0, meaning that the
682 * system should assign a port number which will be reported in
683 * the server callback in the `server_addr' parameter (see below).
684 *
685 * If `may_be_client' is not 0, then accept both kinds of URLs, but
686 * interpret "client or server" URLs as naming client sockets (your
687 * process will open a connection to some other server).
688 *
689 * If `only_server_url' is not 0, then accept "server only" URLs, but
690 * not "client or server" URLs. In this case, `may_be_client' is
691 * ignored. This is especially useful in combination with
692 * `url_socket_push_client_handler' and other calls to
693 * `vu_push_name_handler'.
694 *
695 * `default_port' is used when creating an internet-domain socket for
696 * which the port number was not specified in the file-name.
697 *
698 * `backlog' is used for the call to `listen(2)'.
699 *
700 * `server_callback' is called when a new server socket has been
701 * created successfully. It's arguments are explained below.
702 *
703 * `connect_callback' is called when a new connection has been
704 * received. It's arguments are explained below.
705 *
706 * `server_close_callback' is called when the server descriptor
707 * is closed. It's arguments are explained below.
708 *
709 * `closure' is an opaque value passed to the callback functions.
710 *
711 * If `is_optional' is 0, the handler is immediately added to the VU namespace.
712 * If `is_optional' is non-0, the handler is added to the list of optional
713 * handlers and may be enabled by `vu_enable_optional_name_handler'.
714 *
715 * domain(s) only_server_url may_be_client Optional Handler Name
716 * --------------------------------------------------------------------
717 * unix 0 0 server/unix
718 * inet 0 0 server/inet
719 * inet_or_unix 0 0 server/any
720 * unix 0 1 socket/unix
721 * inet 0 1 socket/inet
722 * inet_or_unix 0 1 socket/any
723 * unix 1 * socket/unix-server
724 * inet 1 * socket/inet-server
725 * inet_or_unix 1 * socket/any-server
726 *
727 *
728 * \Calling Conventions for Callbacks/
729 *
730 * typedef void (*url_socket_server_callback) (char * path,
731 * int server_flags,
732 * int flags,
733 * int mode,
734 * int server_fd,
735 * struct sockaddr * server_addr,
736 * int server_addr_len,
737 * void * closure);
738 *
739 * `path' is the file name that caused the server socket to
740 * be created.
741 *
742 * `server_flags' is 0 or a bit-wise combination of `O_NONBLOCK'.
743 *
744 * `flags' is the `flags' parameter passed to `vu_open', if this
745 * server socket was created by a call to `vu_open', 0 otherwise.
746 *
747 * `mode' is the `mode' parameter passed to `vu_open', if this
748 * server socket was created by a call to `vu_open', 0 otherwise.
749 *
750 * `server_fd' is the descriptor number of the server socket.
751 *
752 * `server_addr' and `server_addr_len' is the address passed to
753 * `bind'.
754 *
755 * `closure' is the `closure' argument passed to
756 * `url_socket_push_socket_handler'.
757 *
758 * typedef void (*url_socket_connect_callback)
759 * (char * path,
760 * int flags,
761 * int mode,
762 * int server_fd,
763 * int connection_fd,
764 * struct sockaddr * client_addr,
765 * int client_addr_len,
766 * void * closure);
767 *
768 * `path' is the file name that caused the client connection to this
769 * server to be created.
770 *
771 * `flags' is the `flags' parameter passed to `vu_open'.
772 *
773 * `mode' is the `mode' parameter passed to `vu_open'.
774 *
775 * `server_fd' is the descriptor number of the server socket.
776 *
777 * `connection_fd' is the descriptor number of the client connection.
778 *
779 * `client_addr' and `client_addr_len' is the address from `accept'.
780 *
781 * `closure' is the `closure' argument passed to
782 * `url_socket_push_socket_handler'.
783 *
784 * typedef void (*url_socket_server_close_callback)
785 * (int server_fd,
786 * struct sockaddr * server_addr,
787 * int server_addr_len,
788 * void * closure);
789 *
790 * `server_fd' is the descriptor number of the server socket.
791 *
792 * `server_addr' and `server_addr_len' is the address passed to
793 * `bind'.
794 *
795 * `closure' is the `closure' argument passed to
796 * `url_socket_push_socket_handler'.
797 *
798 */
799 void
url_socket_push_server_handler(enum url_socket_domains domains,int server_flags,int may_be_client,int only_server_url,int default_port,int backlog,url_socket_server_callback server_callback,url_socket_connect_callback connection_callback,url_socket_server_close_callback server_close_callback,void * closure,int is_optional)800 url_socket_push_server_handler (enum url_socket_domains domains,
801 int server_flags,
802 int may_be_client,
803 int only_server_url,
804 int default_port,
805 int backlog,
806 url_socket_server_callback server_callback,
807 url_socket_connect_callback connection_callback,
808 url_socket_server_close_callback server_close_callback,
809 void * closure,
810 int is_optional)
811 {
812 regex_t * regex;
813 struct url_socket_params params;
814 const t_uchar * name;
815 const t_uchar ** doc;
816
817 if (only_server_url)
818 regex = url_socket_only_server_regex (&name, &doc, domains, default_port);
819 else
820 regex = url_socket_server_regex (&name, &doc, domains, may_be_client, default_port);
821
822 if (may_be_client)
823 params.type = url_socket_server_or_client;
824 else
825 params.type = url_socket_server;
826
827 params.domains = domains;
828 params.server_flags = server_flags;
829 params.default_port = default_port;
830 params.backlog = backlog;
831 params.server_callback = server_callback;
832 params.connection_callback = connection_callback;
833 params.server_close_callback = server_close_callback;
834 params.closure = closure;
835 vu_push_name_handler (name, doc, regex, 0, &url_socket_vtable, (void *)¶ms, is_optional);
836 }
837
838
839
840 /****************************************************************
841 * Caching Server Sockets
842 *
843 * The system creates only one server socket per address.
844 */
845
846 #ifndef SOCK_MAXADDRLEN
847 #undef MAX
848 #define MAX(A,B) (((A)>=(B))?(A):(B))
849 #define SOCK_MAXADDRLEN MAX(sizeof(struct sockaddr_un), sizeof (struct sockaddr_in))
850 #endif
851
852
853 struct server_memo
854 {
855 char addr_data[SOCK_MAXADDRLEN]; /* The address of the server */
856 int fd; /* The descriptor of the server */
857 int flags; /* O_NONBLOCK */
858 char * path; /* If this is a unix domain socket, the file name to unlink */
859 };
860
861 static union
862 {
863 struct server_memo * smp;
864 void * void_ptr;
865 } addr_memo = {0};
866
867 #define IN_ADDR(A) ((struct sockaddr_in *)A)
868 #define IN_ADDR(A) ((struct sockaddr_in *)A)
869 #define UN_ADDR(A) ((struct sockaddr_un *)A)
870 #define SOCKADDR(A) ((struct sockaddr *)(A))
871 #define ADDR_MEMO(N) SOCKADDR(addr_memo.smp[(N)].addr_data)
872 #define IN_ADDR_MEMO(N) IN_ADDR(addr_memo.smp[(N)].addr_data)
873 #define UN_ADDR_MEMO(N) UN_ADDR(addr_memo.smp[(N)].addr_data)
874
875 /* static int server_fd_for_addr (int * errn,
876 * struct sockaddr * addr,
877 * int addr_len,
878 * const char * path,
879 * int flags,
880 * int mode,
881 * struct url_socket_params * params);
882 *
883 * Return a server socket for a given address or -1.
884 *
885 * `errn' returns an errno code.
886 *
887 * `addr' and `addr_len' is the address of the server (for `bind(2)').
888 *
889 * `path' is the `path' parameter for the server callback in `params'.
890 *
891 * `flags' is the `flags' parameter for the server callback in `params'.
892 *
893 * `mode' is the `mode' parameter for the server callback in `params'.
894 *
895 * `params' is the VU closure containing the server callback and other
896 * parameters.
897 */
898 static int
server_fd_for_addr(int * errn,struct sockaddr * addr,int addr_len,const char * path,int flags,int mode,struct url_socket_params * params)899 server_fd_for_addr (int * errn,
900 struct sockaddr * addr,
901 int addr_len,
902 const char * path,
903 int flags,
904 int mode,
905 struct url_socket_params * params)
906 {
907 int fd;
908 int size;
909 int x;
910 int desired_flags;
911 struct server_memo * memo;
912
913 size = ar_size (addr_memo.void_ptr, lim_use_must_malloc, sizeof (*addr_memo.smp));
914 for (x = 0; x < size; ++x)
915 {
916 if (addr->sa_family == ADDR_MEMO(x)->sa_family)
917 {
918 switch (addr->sa_family)
919 {
920 default:
921 panic ("corrupt address memo in url-socket.c");
922 case AF_INET:
923 if ( (IN_ADDR (addr)->sin_port == IN_ADDR_MEMO (x)->sin_port)
924 && !mem_cmp ((t_uchar *)&IN_ADDR (addr)->sin_addr, (t_uchar *)&IN_ADDR_MEMO (x)->sin_addr, sizeof (struct in_addr)))
925 {
926 memo = &addr_memo.smp [x];
927 fd = addr_memo.smp[x].fd;
928 goto got_fd;
929 }
930 break;
931 case AF_UNIX:
932 if (!str_cmp (UN_ADDR (addr)->sun_path, UN_ADDR_MEMO (x)->sun_path))
933 {
934 memo = &addr_memo.smp [x];
935 fd = addr_memo.smp[x].fd;
936 goto got_fd;
937 }
938 break;
939 }
940 }
941 }
942
943 fd = socket (addr->sa_family, SOCK_STREAM, 0);
944 if (fd < 0)
945 {
946 *errn = errno;
947 return -1;
948 }
949
950
951 {
952 int ign;
953
954 if (0 > setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *)&ign, sizeof (ign)))
955 {
956 *errn = errno;
957 close (fd);
958 return -1;
959 }
960 }
961
962 if (0 > bind (fd, addr, addr_len))
963 {
964 *errn = errno;
965 close (fd);
966 return -1;
967 }
968
969 if (0 > listen (fd, params->backlog))
970 {
971 *errn = errno;
972 close (fd);
973 return -1;
974 }
975
976 {
977 int orig_flags;
978 orig_flags = fcntl (fd, F_GETFL, 0);
979 if (orig_flags < 0)
980 {
981 *errn = errno;
982 close (fd);
983 return -1;
984 }
985 memo = (struct server_memo *)ar_push (&addr_memo.void_ptr, lim_use_must_malloc, sizeof (struct server_memo));
986 mem_move (memo->addr_data, (t_uchar *)addr, addr_len);
987 memo->fd = fd;
988 memo->flags = orig_flags & O_NONBLOCK;
989 if (addr->sa_family == AF_INET)
990 memo->path = 0;
991 else
992 memo->path = str_save (lim_use_must_malloc, UN_ADDR (addr)->sun_path);
993 }
994
995 vu_set_fd_handler (fd, &url_server_socket_vtable, (void *)params);
996
997 if (params->server_callback)
998 params->server_callback (path, params->server_flags, flags, mode, fd, addr, addr_len, params->closure);
999
1000 got_fd:
1001 desired_flags = (params->server_flags & O_NONBLOCK);
1002 if (desired_flags != memo->flags)
1003 {
1004 if (-1 == fcntl (fd, F_SETFL, desired_flags))
1005 {
1006 *errn = errno;
1007 return -1;
1008 }
1009 memo->flags = desired_flags;
1010 }
1011 return fd;
1012 }
1013
1014
1015 /* static void remove_memo_for_server_fd (int fd);
1016 *
1017 * Remove the cache of data about server socket `fd'.
1018 */
1019 static struct server_memo *
find_memo_for_server_fd(int fd)1020 find_memo_for_server_fd (int fd)
1021 {
1022 int size;
1023 int x;
1024
1025 size = ar_size (addr_memo.void_ptr, lim_use_must_malloc, sizeof (*addr_memo.smp));
1026 for (x = 0; x < size; ++x)
1027 {
1028 if (addr_memo.smp[x].fd == fd)
1029 return &addr_memo.smp[x];
1030 }
1031 while (1)
1032 panic ("url-socket.c: trying to find a server fd memo for unknown server");
1033 }
1034
1035
1036 /* static void remove_memo_for_server_fd (int fd);
1037 *
1038 * Remove the cache of data about server socket `fd'.
1039 */
1040 static void
remove_memo_for_server_fd(int fd)1041 remove_memo_for_server_fd (int fd)
1042 {
1043 int size;
1044 int x;
1045
1046 size = ar_size (addr_memo.void_ptr, lim_use_must_malloc, sizeof (*addr_memo.smp));
1047 for (x = 0; x < size; ++x)
1048 {
1049 if (addr_memo.smp[x].fd == fd)
1050 {
1051 addr_memo.smp[x] = addr_memo.smp[size - 1];
1052 ar_pop (&addr_memo.void_ptr, lim_use_must_malloc, sizeof (struct server_memo));
1053 return;
1054 }
1055 }
1056 panic ("url-socket.c: trying to remove server fd memo for unknown server");
1057 }
1058
1059
1060
1061
1062
1063 /* static int decode_socket_url (int * errn,
1064 * struct sockaddr * addr,
1065 * int * addr_len,
1066 * int * be_a_server,
1067 * const char * path,
1068 * struct url_socket_params * params,
1069 * int be_a_server_hint);
1070 *
1071 * Translate a URL to a socket address. Return 0 on success,
1072 * -1 in the event of an error.
1073 *
1074 * `errn' returns an errno code.
1075 *
1076 * `addr' and `addr_len' return the translated address.
1077 *
1078 * `be_a_server' returns 0 if a client socket was specified,
1079 * 1 if a server socket was specified. The `path' specifies a
1080 * server if the URL scheme is "unix-server" or "inet-server",
1081 * or if the `type' field of `params' is `url_socket_server'.
1082 * It is an error (EINVAL) if the `type' field of `params' is
1083 * `url_socket_client', but the URL scheme is "unix-server" or
1084 * "inet-server" (Other kinds of errors may also return EINVAL.)
1085 *
1086 * `path' is the URL to translate.
1087 *
1088 * `params' is the URL params associated with `path'. For example, this
1089 * is the `closure' parameter passed to `url_socket_open'.
1090 *
1091 * `be_a_server_hint' applies only if the `type' field of `params'
1092 * is `url_socket_server_or_client'.
1093 *
1094 */
1095 static int
decode_socket_url(int * errn,struct sockaddr * addr,int * addr_len,struct url_socket_params * params,int * be_a_server,const char * path,int be_a_server_hint)1096 decode_socket_url (int * errn,
1097 struct sockaddr * addr,
1098 int * addr_len,
1099 struct url_socket_params * params,
1100 int * be_a_server,
1101 const char * path,
1102 int be_a_server_hint)
1103 {
1104 int is_server_address;
1105
1106 is_server_address = 0;
1107 if (!str_cmp_prefix ("inet://", path) || (is_server_address = !str_cmp_prefix ("inet-server://", path)))
1108 {
1109 char * addr_spec;
1110 char * end_of_addr_spec;
1111 char * host;
1112
1113 /* Sanity check the requested socket type against the
1114 * parameters for this handler.
1115 *
1116 * Perhaps this should actually panic.
1117 */
1118 if ( (params->domains != url_socket_inet)
1119 && (params->domains != url_socket_inet_or_unix))
1120 {
1121 bogus_addr:
1122 *errn = EINVAL;
1123 return -1;
1124 }
1125
1126 IN_ADDR(addr)->sin_family = AF_INET;
1127
1128
1129 /* Find the extent of the host part of the path.
1130 * Find the port number, if any was specified.
1131 */
1132 addr_spec = str_chr_index (path, '/');
1133 addr_spec += 2;
1134 end_of_addr_spec = str_chr_index (addr_spec, ':');
1135
1136 if (!end_of_addr_spec)
1137 {
1138 /* No port specified in path. Use the default.
1139 */
1140 end_of_addr_spec = str_chr_index (addr_spec, 0);
1141 if (params->default_port < 0)
1142 goto bogus_addr;
1143 IN_ADDR(addr)->sin_port = htons (params->default_port);
1144 }
1145 else
1146 {
1147 char * port_name;
1148 unsigned long port;
1149 int errn;
1150
1151 /* Port number explicitly specified.
1152 */
1153 port_name = end_of_addr_spec + 1;
1154 if (0 > cvt_decimal_to_ulong (&errn, &port, port_name, str_length (port_name)))
1155 return -1;
1156
1157 IN_ADDR(addr)->sin_port = htons (port);
1158 }
1159
1160 /* Make a copy of the hostname, so we can have a 0-terminated
1161 * form.
1162 */
1163 host = alloca (1 + end_of_addr_spec - addr_spec);
1164 str_cpy_n (host, addr_spec, end_of_addr_spec - addr_spec);
1165 host[end_of_addr_spec - addr_spec] = 0;
1166
1167 /* Does it appear to be an IP address?
1168 */
1169 if (char_is_digit (*host))
1170 {
1171
1172 IN_ADDR(addr)->sin_addr.s_addr = inet_addr (host);
1173 if ((t_ulong)(long)IN_ADDR(addr)->sin_addr.s_addr == (t_ulong)-1)
1174 goto bogus_addr;
1175 }
1176 #if 0
1177 /* INADDR_LOOPBACK is not defined in some versions of BSD/OS. */
1178 else if (!str_cmp ("INADDR_LOOPBACK", host))
1179 {
1180 IN_ADDR(addr)->sin_addr.s_addr = INADDR_LOOPBACK;
1181 }
1182 #endif
1183 else if (!str_cmp ("INADDR_ANY", host))
1184 {
1185 IN_ADDR(addr)->sin_addr.s_addr = INADDR_ANY;
1186 }
1187 else
1188 {
1189 struct hostent * hostentp;
1190 hostentp = gethostbyname (host);
1191 if (!hostentp || (hostentp->h_addrtype != AF_INET))
1192 goto bogus_addr;
1193 mem_move ((t_uchar *)&IN_ADDR(addr)->sin_addr, hostentp->h_addr, hostentp->h_length);
1194 }
1195 *addr_len = sizeof (struct sockaddr_in);
1196 }
1197 else if (!str_cmp_prefix ("unix:", path) || (is_server_address = !str_cmp_prefix ("unix-server:", path)))
1198 {
1199 char * socket_path;
1200 char * expanded_socket_path;
1201 int len;
1202
1203 /* Sanity check the requested socket type against the
1204 * parameters for this handler.
1205 */
1206 if ( (params->domains != url_socket_unix)
1207 && (params->domains != url_socket_inet_or_unix))
1208 goto bogus_addr;
1209
1210 UN_ADDR(addr)->sun_family = AF_UNIX;
1211 socket_path = 1 + str_chr_index (path, ':');
1212 expanded_socket_path = file_name_tilde_expand (lim_use_must_malloc, socket_path);
1213 len = str_length (expanded_socket_path);
1214 if (len + 1 > sizeof (UN_ADDR(addr)->sun_path))
1215 {
1216 *errn = ENAMETOOLONG;
1217 return -1;
1218 }
1219 str_cpy (UN_ADDR(addr)->sun_path, expanded_socket_path);
1220 *addr_len = sizeof (struct sockaddr_un);
1221 }
1222
1223 if (is_server_address && (params->type == url_socket_client))
1224 goto bogus_addr;
1225
1226 *be_a_server = ( is_server_address
1227 || (params->type == url_socket_server)
1228 || be_a_server_hint);
1229
1230 if ( (addr->sa_family == AF_INET)
1231 && !*be_a_server
1232 && (IN_ADDR(addr)->sin_addr.s_addr == INADDR_ANY))
1233 {
1234 *errn = EINVAL;
1235 return -1;
1236 }
1237
1238 return 0;
1239 }
1240
1241
1242
1243
1244 /*c int url_socket_create_server_socket (int * errn, char * path)
1245 *
1246 * Create a server socket for `path'. Return a descriptor number
1247 * or -1.
1248 *
1249 * `errno' returns an errno code.
1250 *
1251 * `path' should be a URL matching a pattern added to the VU file
1252 * namespace.
1253 *
1254 * `vu_close' can be used to close a server fd.
1255 */
1256 int
url_socket_create_server_socket(int * errn,char * path)1257 url_socket_create_server_socket (int * errn, char * path)
1258 {
1259 struct vu_handler * handler;
1260 struct url_socket_params * params;
1261 char addr_space[SOCK_MAXADDRLEN];
1262 struct sockaddr * addr;
1263 int addr_len;
1264 int be_a_server;
1265
1266 handler = vu_path_dispatch (path);
1267 params = (struct url_socket_params *)handler->closure;
1268 addr = (struct sockaddr *)addr_space;
1269
1270 if (0 > decode_socket_url (errn, addr, &addr_len, params, &be_a_server, path, 0))
1271 return -1;
1272
1273 if (!be_a_server)
1274 {
1275 *errn = EINVAL;
1276 return -1;
1277 }
1278 else
1279 {
1280 int server_fd;
1281
1282 server_fd = server_fd_for_addr (errn, addr, addr_len, path, 0, 0, params);
1283 return server_fd;
1284 }
1285 }
1286
1287
1288
1289 int
url_inet_client(int * errn,t_uchar * host,int port)1290 url_inet_client (int * errn, t_uchar * host, int port)
1291 {
1292 t_ulong host_addr;
1293
1294 if (char_is_digit (*host))
1295 {
1296 struct in_addr a;
1297
1298 a.s_addr = inet_addr (host);
1299 if ((t_ulong)(long)a.s_addr == (t_ulong) -1)
1300 {
1301 bogus_addr:
1302 *errn = EINVAL;
1303 return -1;
1304 }
1305 host_addr = ntohl (a.s_addr);
1306 }
1307 else
1308 {
1309 struct hostent * hostentp;
1310
1311 hostentp = gethostbyname (host);
1312 if (!hostentp || (hostentp->h_addrtype != AF_INET))
1313 goto bogus_addr;
1314 mem_move ((t_uchar *)&host_addr, hostentp->h_addr, hostentp->h_length);
1315
1316 host_addr = ntohl (host_addr);
1317 }
1318
1319 return url_inet_client_addr (errn, host_addr, port);
1320 }
1321
1322
1323
1324 int
url_inet_client_addr(int * errn,t_ulong host,int port)1325 url_inet_client_addr (int * errn, t_ulong host, int port)
1326 {
1327 int fd;
1328 struct url_socket_params params;
1329 struct sockaddr_in addr;
1330
1331 addr.sin_family = AF_INET;
1332 addr.sin_port = htons (port);
1333 addr.sin_addr.s_addr = htonl (host);
1334
1335 fd = socket (AF_INET, SOCK_STREAM, 0);
1336 if (fd < 0)
1337 {
1338 *errn = errno;
1339 return -1;
1340 }
1341 if (0 > connect (fd, (struct sockaddr *)&addr, sizeof (addr)))
1342 {
1343 *errn = errno;
1344 close (fd);
1345 return -1;
1346 }
1347
1348 params.type = url_socket_client;
1349 params.domains = url_socket_inet;
1350 params.default_port = 0;
1351 params.backlog = 5;
1352 params.server_callback = 0;
1353 params.connection_callback = 0;
1354 params.server_close_callback = 0;
1355 vu_set_fd_handler (fd, &url_socket_vtable, (void *)¶ms);
1356
1357 return fd;
1358 }
1359
1360
1361
1362 int
url_inet_server_accept(int * errn,int server_fd)1363 url_inet_server_accept (int * errn, int server_fd)
1364 {
1365 struct url_socket_params params;
1366 char client_addr_space[SOCK_MAXADDRLEN];
1367 struct sockaddr * client_addr;
1368 int client_addr_len;
1369 int connection_fd;
1370
1371 client_addr = (struct sockaddr *)client_addr_space;
1372 client_addr_len = sizeof (client_addr_space);
1373
1374 connection_fd = accept (server_fd, client_addr, &client_addr_len);
1375 if (connection_fd < 0)
1376 {
1377 *errn = errno;
1378 return -1;
1379 }
1380
1381 params.type = url_socket_server;
1382 params.domains = url_socket_inet;
1383 params.default_port = 0;
1384 params.backlog = 0;
1385 params.server_callback = 0;
1386 params.connection_callback = 0;
1387 params.server_close_callback = 0;
1388 vu_set_fd_handler (connection_fd, &url_socket_vtable, (void *)¶ms);
1389
1390 return connection_fd;
1391 }
1392
1393
1394 int
url_inet_server(alloc_limits limits,t_ulong * host_addr_is,t_uchar ** host_id_is,int * port_is,int * errn,t_uchar * host,int port)1395 url_inet_server (alloc_limits limits,
1396 t_ulong * host_addr_is,
1397 t_uchar ** host_id_is,
1398 int * port_is,
1399 int * errn,
1400 t_uchar * host,
1401 int port)
1402 {
1403 int fd;
1404 struct url_socket_params params;
1405 struct sockaddr_in addr;
1406 t_uchar *myhost;
1407
1408 mem_set0 ((t_uchar *)&addr, sizeof (addr));
1409
1410 addr.sin_family = AF_INET;
1411 addr.sin_port = htons (port);
1412
1413 if (!host)
1414 {
1415 if (host_id_is)
1416 {
1417 size_t size = 64;
1418 int err;
1419 myhost = (t_uchar *) must_malloc (size + 1);
1420 while (1)
1421 {
1422 int i = size - 1;
1423 myhost[i] = '\0';
1424 err = gethostname (myhost, size);
1425 if (err >= 0 && myhost[i] == '\0')
1426 break;
1427 else if (err < 0 && errno != ENAMETOOLONG && errno != 0)
1428 must_free (myhost);
1429 size *= 2;
1430 myhost = must_realloc (myhost, size + 1);
1431 }
1432 *host_id_is = str_save (limits, myhost);
1433 }
1434 addr.sin_addr.s_addr = htonl (INADDR_ANY);
1435 }
1436 else
1437 {
1438 if (host_id_is)
1439 *host_id_is = str_save (limits, host);
1440
1441 if (char_is_digit (*host))
1442 {
1443 addr.sin_addr.s_addr = inet_addr (host);
1444 if ((t_ulong)(long)addr.sin_addr.s_addr == (t_ulong)-1)
1445 goto bogus_addr;
1446
1447 }
1448 else if (!str_cmp ("INADDR_ANY", host))
1449 {
1450 addr.sin_addr.s_addr = htonl (INADDR_ANY);
1451 }
1452 else
1453 {
1454 struct hostent * hostentp;
1455
1456 hostentp = gethostbyname (host);
1457 if (!hostentp || (hostentp->h_addrtype != AF_INET))
1458 {
1459 bogus_addr:
1460 *errn = EINVAL;
1461 return -1;
1462 }
1463 mem_move ((t_uchar *)&addr.sin_addr, hostentp->h_addr, hostentp->h_length);
1464 }
1465 }
1466
1467 mem_set0 ((t_uchar *)¶ms, sizeof (params));
1468 params.type = url_socket_server;
1469 params.domains = url_socket_inet;
1470 params.default_port = 0;
1471 params.backlog = 1;
1472 params.server_callback = 0;
1473 params.connection_callback = 0;
1474 params.server_close_callback = 0;
1475
1476 fd = server_fd_for_addr (errn, (struct sockaddr *)&addr, sizeof (addr), 0, O_RDWR, 0, ¶ms);
1477
1478 if (fd < 0)
1479 {
1480 return -1;
1481 }
1482 else
1483 {
1484 if (host_addr_is)
1485 {
1486 if (ntohl (addr.sin_addr.s_addr) != INADDR_ANY)
1487 {
1488 *host_addr_is = ntohl (addr.sin_addr.s_addr);
1489 }
1490 else
1491 {
1492 struct hostent * hostent;
1493 size_t size = 64;
1494 int err;
1495 t_uchar *my_name;
1496
1497 my_name = (t_uchar *) must_malloc (size + 1);
1498 while (1)
1499 {
1500 int i = size - 1;
1501 my_name[i] = '\0';
1502 err = gethostname (my_name, size);
1503 if (err >= 0 && my_name[i] == '\0')
1504 break;
1505 else if (err < 0 && errno != ENAMETOOLONG && errno != 0)
1506 must_free (my_name);
1507 size *= 2;
1508 my_name = must_realloc (my_name, size + 1);
1509 }
1510
1511 hostent = gethostbyname (my_name);
1512 if (!hostent)
1513 {
1514 int ign;
1515 *errn = errno;
1516 vu_close (&ign, fd);
1517 return -1;
1518 }
1519 {
1520 t_uint32 tmp;
1521
1522 mem_move ((t_uchar *)&tmp, (t_uchar *)hostent->h_addr, 4);
1523 *host_addr_is = ntohl (tmp);
1524 }
1525 }
1526 }
1527
1528 if (port_is)
1529 {
1530 char name_space[SOCK_MAXADDRLEN];
1531 int name_len;
1532 struct sockaddr * name;
1533
1534 name = (struct sockaddr *)name_space;
1535 name_len = sizeof (name_space);
1536
1537 if (0 > getsockname (fd, name, &name_len))
1538 {
1539 int e;
1540 *errn = errno;
1541 vu_close (&e, fd);
1542 return -1;
1543 }
1544 else
1545 {
1546 if (port_is)
1547 {
1548 *port_is = ntohs (IN_ADDR(name)->sin_port);
1549 }
1550 }
1551 }
1552 }
1553
1554 return fd;
1555 }
1556
1557
1558
1559
1560 /****************************************************************
1561 * VU `open' and `close' for Sockets
1562 *
1563 *
1564 */
1565
1566 /*c void * url_socket_make_closure (void * closure);
1567 *
1568 * A `make_closure' function for a VU vtable. (See `vu_push_name_handler'.)
1569 */
1570 static void *
url_socket_make_closure(void * closure)1571 url_socket_make_closure (void * closure)
1572 {
1573 struct url_socket_params * answer;
1574 answer = (struct url_socket_params *)must_malloc (sizeof (*answer));
1575 *answer = *(struct url_socket_params *)closure;
1576 return (void *)answer;
1577 }
1578
1579
1580 /*c void url_socket_free_closure (void * closure);
1581 *
1582 * A `free_closure' function for a VU vtable. (See `vu_push_name_handler'.)
1583 */
1584 static void
url_socket_free_closure(void * closure)1585 url_socket_free_closure (void * closure)
1586 {
1587 must_free (closure);
1588 }
1589
1590
1591 /*c void url_socket_open (int * errn,
1592 * const char * path,
1593 * int flags,
1594 * int mode,
1595 * void * closure);
1596 *
1597 * An `open' function for a VU vtable. (See `vu_push_name_handler'.)
1598 *
1599 * See `url_socket_push_client_handler' and `url_socket_push_server_handler'.
1600 */
1601 static int
url_socket_open(int * errn,const char * path,int flags,int mode,void * closure)1602 url_socket_open (int * errn, const char * path, int flags, int mode, void * closure)
1603 {
1604 struct url_socket_params * params;
1605 char addr_space[SOCK_MAXADDRLEN];
1606 struct sockaddr * addr;
1607 int addr_len;
1608 int be_a_server;
1609
1610 params = (struct url_socket_params *)closure;
1611 addr = (struct sockaddr *)addr_space;
1612
1613 if (0 > decode_socket_url (errn, addr, &addr_len, params, &be_a_server, path, 0))
1614 return -1;
1615
1616 if (!be_a_server)
1617 {
1618 int fd;
1619
1620 fd = socket (addr->sa_family, SOCK_STREAM, 0);
1621 if (fd < 0)
1622 {
1623 *errn = errno;
1624 return -1;
1625 }
1626 if (0 > connect (fd, addr, addr_len))
1627 {
1628 *errn = errno;
1629 close (fd);
1630 return -1;
1631 }
1632 return fd;
1633 }
1634 else
1635 {
1636 char client_addr_space[SOCK_MAXADDRLEN];
1637 struct sockaddr * client_addr;
1638 int client_addr_len;
1639 int server_fd;
1640 int connection_fd;
1641
1642 client_addr = (struct sockaddr *)client_addr_space;
1643 client_addr_len = sizeof (client_addr_space);
1644 server_fd = server_fd_for_addr (errn, addr, addr_len, path, flags, mode, params);
1645 if (server_fd < 0)
1646 return -1;
1647
1648 connection_fd = accept (server_fd, client_addr, &client_addr_len);
1649 if (connection_fd < 0)
1650 {
1651 *errn = errno;
1652 return -1;
1653 }
1654
1655 if (params->connection_callback)
1656 params->connection_callback (path, flags, mode, server_fd, connection_fd, client_addr, client_addr_len, params->closure);
1657
1658 return connection_fd;
1659 }
1660 }
1661
1662
1663
1664 /*c void url_socket_close (int * errn, int fd, void * closure);
1665 * char * path,
1666 * int flags,
1667 * int mode,
1668 * void * closure);
1669 *
1670 * A `close' function for a VU vtable. (See `vu_push_name_handler'.)
1671 *
1672 * See `url_socket_push_client_handler' and `url_socket_push_server_handler'.
1673 */
1674 static int
url_socket_close(int * errn,int fd,void * closure)1675 url_socket_close (int * errn, int fd, void * closure)
1676 {
1677 int x;
1678 int size;
1679
1680 size = ar_size (addr_memo.void_ptr, lim_use_must_malloc, sizeof (*addr_memo.smp));
1681 for (x = 0; x < size; ++x)
1682 if (fd == addr_memo.smp [x].fd)
1683 {
1684 if (0 > vu_sys_close (errn, fd, 0))
1685 return -1;
1686 addr_memo.smp[x] = addr_memo.smp[size - 1];
1687 ar_pop (&addr_memo.void_ptr, lim_use_must_malloc, sizeof (struct server_memo));
1688 return 0;
1689 }
1690 return vu_sys_close (errn, fd, 0);
1691 }
1692
1693
1694
1695 /****************************************************************
1696 * VU Vtable Functions for URL Sockets
1697 */
1698
1699 static int
url_socket_access(int * errn,const char * path,int mode,void * closure)1700 url_socket_access (int * errn, const char * path, int mode, void * closure)
1701 {
1702 *errn = EINVAL;
1703 return -1;
1704 }
1705
1706
1707 static int
url_socket_chdir(int * errn,const char * path,void * closure)1708 url_socket_chdir (int * errn, const char * path, void * closure)
1709 {
1710 *errn = EINVAL;
1711 return -1;
1712 }
1713
1714
1715 static int
url_socket_chmod(int * errn,const char * path,int mode,void * closure)1716 url_socket_chmod (int * errn, const char * path, int mode, void * closure)
1717 {
1718 *errn = EINVAL;
1719 return -1;
1720 }
1721
1722
1723 static int
url_socket_chown(int * errn,const char * path,int owner,int group,void * closure)1724 url_socket_chown (int * errn, const char * path, int owner, int group, void * closure)
1725 {
1726 *errn = EINVAL;
1727 return -1;
1728 }
1729
1730
1731 static int
url_socket_chroot(int * errn,const char * path,void * closure)1732 url_socket_chroot (int * errn, const char * path, void * closure)
1733 {
1734 *errn = EINVAL;
1735 return -1;
1736 }
1737
1738
1739 static int
url_socket_closedir(int * errn,DIR * dir,void * closure)1740 url_socket_closedir (int * errn, DIR * dir, void * closure)
1741 {
1742 *errn = EINVAL;
1743 return -1;
1744 }
1745
1746
1747 static int
url_socket_fchdir(int * errn,int fd,void * closure)1748 url_socket_fchdir (int * errn, int fd, void * closure)
1749 {
1750 *errn = EINVAL;
1751 return -1;
1752 }
1753
1754
1755 static int
url_socket_fchmod(int * errn,int fd,int mode,void * closure)1756 url_socket_fchmod (int * errn, int fd, int mode, void * closure)
1757 {
1758 *errn = EINVAL;
1759 return -1;
1760 }
1761
1762
1763 static int
url_socket_fchown(int * errn,int fd,int owner,int group,void * closure)1764 url_socket_fchown (int * errn, int fd, int owner, int group, void * closure)
1765 {
1766 *errn = EINVAL;
1767 return -1;
1768 }
1769
1770
1771 static int
url_socket_fstat(int * errn,int fd,struct stat * buf,void * closure)1772 url_socket_fstat (int * errn, int fd, struct stat * buf, void * closure)
1773 {
1774 *errn = EINVAL;
1775 return -1;
1776 }
1777
1778
1779 static int
url_socket_fsync(int * errn,int fd,void * closure)1780 url_socket_fsync (int * errn, int fd, void * closure)
1781 {
1782 *errn = EINVAL;
1783 return -1;
1784 }
1785
1786
1787 static int
url_socket_ftruncate(int * errn,int fd,off_t where,void * closure)1788 url_socket_ftruncate (int * errn, int fd, off_t where, void * closure)
1789 {
1790 *errn = EINVAL;
1791 return -1;
1792 }
1793
1794
1795 static int
url_socket_link(int * errn,const char * from,const char * to,void * closure)1796 url_socket_link (int * errn, const char * from, const char * to, void * closure)
1797 {
1798 *errn = EINVAL;
1799 return -1;
1800 }
1801
1802
1803 static off_t
url_socket_lseek(int * errn,int fd,off_t offset,int whence,void * closure)1804 url_socket_lseek (int * errn, int fd, off_t offset, int whence, void * closure)
1805 {
1806 *errn = ESPIPE;
1807 return -1;
1808 }
1809
1810
1811 static int
url_socket_lstat(int * errn,const char * path,struct stat * buf,void * closure)1812 url_socket_lstat (int * errn, const char * path, struct stat * buf, void * closure)
1813 {
1814 *errn = EINVAL;
1815 return -1;
1816 }
1817
1818
1819 static int
url_socket_mkdir(int * errn,const char * path,int mode,void * closure)1820 url_socket_mkdir (int * errn, const char * path, int mode, void * closure)
1821 {
1822 *errn = EINVAL;
1823 return -1;
1824 }
1825
1826
1827 static int
url_socket_opendir(int * errn,DIR ** retv,const char * path,void * closure)1828 url_socket_opendir (int * errn, DIR ** retv, const char * path, void * closure)
1829 {
1830 *errn = EINVAL;
1831 return -1;
1832 }
1833
1834
1835 static ssize_t
url_socket_read(int * errn,int fd,char * buf,size_t count,void * closure)1836 url_socket_read (int * errn, int fd, char * buf, size_t count, void * closure)
1837 {
1838 return vu_sys_read (errn, fd, buf, count, 0);
1839 }
1840
1841
1842 static int
url_socket_readdir(int * errn,struct alloc_limits * limits,char ** file_ret,DIR * dir,void * closure)1843 url_socket_readdir (int * errn, struct alloc_limits * limits, char ** file_ret, DIR * dir, void * closure)
1844 {
1845 *errn = EINVAL;
1846 return -1;
1847 }
1848
1849
1850 static int
url_socket_readlink(int * errn,const char * path,char * buf,int bufsize,void * closure)1851 url_socket_readlink (int * errn, const char * path, char * buf, int bufsize, void * closure)
1852 {
1853 *errn = EINVAL;
1854 return -1;
1855 }
1856
1857
1858 static int
url_socket_rename(int * errn,const char * from,const char * to,void * closure)1859 url_socket_rename (int * errn, const char * from, const char * to, void * closure)
1860 {
1861 *errn = EINVAL;
1862 return -1;
1863 }
1864
1865
1866 static int
url_socket_rmdir(int * errn,const char * path,void * closure)1867 url_socket_rmdir (int * errn, const char * path, void * closure)
1868 {
1869 *errn = EINVAL;
1870 return -1;
1871 }
1872
1873
1874 static int
url_socket_stat(int * errn,const char * path,struct stat * buf,void * closure)1875 url_socket_stat (int * errn, const char * path, struct stat * buf, void * closure)
1876 {
1877 *errn = EINVAL;
1878 return -1;
1879 }
1880
1881
1882 static int
url_socket_symlink(int * errn,const char * from,const char * to,void * closure)1883 url_socket_symlink (int * errn, const char * from, const char * to, void * closure)
1884 {
1885 *errn = EINVAL;
1886 return -1;
1887 }
1888
1889
1890 static int
url_socket_truncate(int * errn,const char * path,off_t where,void * closure)1891 url_socket_truncate (int * errn, const char * path, off_t where, void * closure)
1892 {
1893 *errn = EINVAL;
1894 return -1;
1895 }
1896
1897
1898 static int
url_socket_unlink(int * errn,const char * path,void * closure)1899 url_socket_unlink (int * errn, const char * path, void * closure)
1900 {
1901 *errn = EINVAL;
1902 return -1;
1903 }
1904
1905
1906 static int
url_socket_utime(int * errn,const char * path,struct utimbuf * times,void * closure)1907 url_socket_utime (int * errn, const char * path, struct utimbuf * times, void * closure)
1908 {
1909 *errn = EINVAL;
1910 return -1;
1911 }
1912
1913
1914 static ssize_t
url_socket_write(int * errn,int fd,const char * buf,size_t count,void * closure)1915 url_socket_write (int * errn, int fd, const char * buf, size_t count, void * closure)
1916 {
1917 return vu_sys_write (errn, fd, buf, count, 0);
1918 }
1919
1920 static int
url_socket_fcntl(int * errn,int fd,int cmd,long arg,void * closure)1921 url_socket_fcntl (int * errn, int fd, int cmd, long arg, void * closure)
1922 {
1923 return vu_sys_fcntl (errn, fd, cmd, arg, 0);
1924 }
1925
1926
1927 static int
url_socket_dup(int * errn,int fd,void * closure)1928 url_socket_dup (int * errn, int fd, void * closure)
1929 {
1930 return vu_sys_dup (errn, fd, 0);
1931 }
1932
1933
1934 static int
url_socket_dup2(int * errn,int fd,int newfd,void * closure)1935 url_socket_dup2 (int * errn, int fd, int newfd, void * closure)
1936 {
1937 return vu_sys_dup2 (errn, fd, newfd, 0);
1938 }
1939
1940
1941
1942 static int
url_socket_move_state(int * errn,int fd,int newfd,void * closure)1943 url_socket_move_state (int * errn, int fd, int newfd, void * closure)
1944 {
1945 if (fd == newfd)
1946 return fd;
1947 vu_set_fd_handler (newfd, &url_socket_vtable, closure);
1948 return 0;
1949 }
1950
1951
1952 static struct vu_fs_discipline url_socket_vtable = { VU_FS_DISCIPLINE_INITIALIZERS (url_socket_) };
1953
1954
1955 /****************************************************************
1956 * VU Vtable Functions for Server Sockets
1957 */
1958
1959
1960 /*c int url_server_socket_close (int * errn, int fd, void * closure);
1961 *
1962 * A `vu_close_fn' implementation.
1963 *
1964 * Close a descriptor which is a server-socket created by
1965 * `url_socket_open' or `url_socket_create_server_socket'.
1966 *
1967 */
1968 static int
url_server_socket_close(int * errn,int fd,void * closure)1969 url_server_socket_close (int * errn, int fd, void * closure)
1970 {
1971 struct url_socket_params * params;
1972 struct server_memo * memo;
1973 struct sockaddr * addr;
1974 int addr_len;
1975 char addr_space[SOCK_MAXADDRLEN];
1976
1977 params = (struct url_socket_params *)closure;
1978 memo = find_memo_for_server_fd (fd);
1979 if (close (fd) < 0)
1980 {
1981 *errn = errno;
1982 return -1;
1983 }
1984 if (memo->path)
1985 {
1986 int errn2;
1987 vu_unlink (&errn2, memo->path);
1988 }
1989 addr = (struct sockaddr *)memo->addr_data;
1990 addr_len = (addr->sa_family ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_un));
1991 mem_move (addr_space, (t_uchar *)addr, addr_len);
1992 addr = (struct sockaddr *)addr_space;
1993 remove_memo_for_server_fd (fd);
1994 if (params->server_close_callback)
1995 params->server_close_callback (fd, addr, addr_len, params->closure);
1996 return 0;
1997 }
1998
1999 #define url_server_socket_make_closure url_socket_make_closure
2000 #define url_server_socket_free_closure url_socket_free_closure
2001
2002 #define url_server_socket_access (vu_access_fn)vu_bad_arg
2003 #define url_server_socket_chdir (vu_chdir_fn)vu_bad_arg
2004 #define url_server_socket_chmod (vu_chmod_fn)vu_bad_arg
2005 #define url_server_socket_chown (vu_chown_fn)vu_bad_arg
2006 #define url_server_socket_chroot (vu_chroot_fn)vu_bad_arg
2007 #define url_server_socket_closedir (vu_closedir_fn)vu_bad_arg
2008 #define url_server_socket_fchdir (vu_fchdir_fn)vu_bad_arg
2009 #define url_server_socket_fchmod (vu_fchmod_fn)vu_bad_arg
2010 #define url_server_socket_fchown (vu_fchown_fn)vu_bad_arg
2011 #define url_server_socket_fstat (vu_fstat_fn)vu_bad_arg
2012 #define url_server_socket_fsync (vu_fsync_fn)vu_bad_arg
2013 #define url_server_socket_ftruncate (vu_ftruncate_fn)vu_bad_arg
2014 #define url_server_socket_link (vu_link_fn)vu_bad_arg
2015 #define url_server_socket_lseek (vu_lseek_fn)vu_bad_arg
2016 #define url_server_socket_lstat (vu_lstat_fn)vu_bad_arg
2017 #define url_server_socket_mkdir (vu_mkdir_fn)vu_bad_arg
2018 #define url_server_socket_open (vu_open_fn)vu_bad_arg
2019 #define url_server_socket_opendir (vu_opendir_fn)vu_bad_arg
2020 #define url_server_socket_read (vu_read_fn)vu_bad_arg
2021 #define url_server_socket_readdir (vu_readdir_fn)vu_bad_arg
2022 #define url_server_socket_readlink (vu_readlink_fn)vu_bad_arg
2023 #define url_server_socket_rename (vu_rename_fn)vu_bad_arg
2024 #define url_server_socket_rmdir (vu_rmdir_fn)vu_bad_arg
2025 #define url_server_socket_stat (vu_stat_fn)vu_bad_arg
2026 #define url_server_socket_symlink (vu_symlink_fn)vu_bad_arg
2027 #define url_server_socket_truncate (vu_truncate_fn)vu_bad_arg
2028 #define url_server_socket_unlink (vu_unlink_fn)vu_bad_arg
2029 #define url_server_socket_utime (vu_utime_fn)vu_bad_arg
2030 #define url_server_socket_write (vu_write_fn)vu_bad_arg
2031 #define url_server_socket_fcntl (vu_fcntl_fn)vu_bad_arg
2032 #define url_server_socket_dup (vu_dup_fn)vu_bad_arg
2033 #define url_server_socket_dup2 (vu_dup2_fn)vu_bad_arg
2034 #define url_server_socket_move_state (vu_dup2_fn)vu_bad_arg
2035
2036 static struct vu_fs_discipline url_server_socket_vtable = { VU_FS_DISCIPLINE_INITIALIZERS (url_server_socket_) };
2037