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 (&regex, "^unix:", 0))
211               panic ("unable to compile socket url regexp");
212             initialized = 1;
213           }
214         *name = "client/unix";
215         *doc = docstr;
216         return &regex;
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 (&regex, "^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 &regex;
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 (&regex, "^[[:(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 &regex;
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 (&regex, "^[[:(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 &regex;
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 (&regex, "^[[:(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 &regex;
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 (&regex, "^[[:(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 &regex;
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 (&regex, "^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 &regex;
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 (&regex, "^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 &regex;
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 (&regex, "^[[:(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 &regex;
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 *)&params, 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 *)&params, 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 *)&params);
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 *)&params);
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 *)&params, 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, &params);
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