1 /*
2  * DGRAM protocol layer on top of AF_UNIX
3  *
4  * Copyright 2020 HAProxy Technologies, Emeric Brun <ebrun@haproxy.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  *
11  */
12 
13 #include <ctype.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20 
21 #include <sys/param.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <sys/un.h>
25 
26 #include <haproxy/fd.h>
27 #include <haproxy/listener.h>
28 #include <haproxy/log.h>
29 #include <haproxy/namespace.h>
30 #include <haproxy/protocol.h>
31 #include <haproxy/sock.h>
32 #include <haproxy/sock_unix.h>
33 
34 static int uxdg_bind_listener(struct listener *listener, char *errmsg, int errlen);
35 static void uxdg_enable_listener(struct listener *listener);
36 static void uxdg_disable_listener(struct listener *listener);
37 static int uxdg_suspend_receiver(struct receiver *rx);
38 
39 /* Note: must not be declared <const> as its list will be overwritten */
40 struct protocol proto_uxdg = {
41 	.name           = "uxdg",
42 
43 	/* connection layer */
44 	.ctrl_type      = SOCK_DGRAM,
45 	.listen         = uxdg_bind_listener,
46 	.enable         = uxdg_enable_listener,
47 	.disable        = uxdg_disable_listener,
48 	.add            = default_add_listener,
49 	.unbind         = default_unbind_listener,
50 	.suspend        = default_suspend_listener,
51 	.resume         = default_resume_listener,
52 
53 	/* binding layer */
54 	.rx_suspend     = uxdg_suspend_receiver,
55 
56 	/* address family */
57 	.fam            = &proto_fam_unix,
58 
59 	/* socket layer */
60 	.sock_type      = SOCK_DGRAM,
61 	.sock_prot      = 0,
62 	.rx_enable      = sock_enable,
63 	.rx_disable     = sock_disable,
64 	.rx_unbind      = sock_unbind,
65 	.receivers      = LIST_HEAD_INIT(proto_uxdg.receivers),
66 	.nb_receivers   = 0,
67 };
68 
69 INITCALL1(STG_REGISTER, protocol_register, &proto_uxdg);
70 
71 /* This function tries to bind dgram unix socket listener. It may return a warning or
72  * an error message in <errmsg> if the message is at most <errlen> bytes long
73  * (including '\0'). Note that <errmsg> may be NULL if <errlen> is also zero.
74  * The return value is composed from ERR_ABORT, ERR_WARN,
75  * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything
76  * was alright and that no message was returned. ERR_RETRYABLE means that an
77  * error occurred but that it may vanish after a retry (eg: port in use), and
78  * ERR_FATAL indicates a non-fixable error. ERR_WARN and ERR_ALERT do not alter
79  * the meaning of the error, but just indicate that a message is present which
80  * should be displayed with the respective level. Last, ERR_ABORT indicates
81  * that it's pointless to try to start other listeners. No error message is
82  * returned if errlen is NULL.
83  */
uxdg_bind_listener(struct listener * listener,char * errmsg,int errlen)84 int uxdg_bind_listener(struct listener *listener, char *errmsg, int errlen)
85 {
86 	int err = ERR_NONE;
87 	char *msg = NULL;
88 
89 	/* ensure we never return garbage */
90 	if (errlen)
91 		*errmsg = 0;
92 
93 	if (listener->state != LI_ASSIGNED)
94 		return ERR_NONE; /* already bound */
95 
96 	if (!(listener->rx.flags & RX_F_BOUND)) {
97 		msg = "receiving socket not bound";
98 		goto uxdg_return;
99 	}
100 
101 	listener_set_state(listener, LI_LISTEN);
102 
103  uxdg_return:
104 	if (msg && errlen) {
105 		const char *path = ((struct sockaddr_un *)&listener->rx.addr)->sun_path;
106                 snprintf(errmsg, errlen, "%s [%s]", msg, path);
107 	}
108 	return err;
109 }
110 
111 /* Enable receipt of incoming connections for listener <l>. The receiver must
112  * still be valid.
113  */
uxdg_enable_listener(struct listener * l)114 static void uxdg_enable_listener(struct listener *l)
115 {
116 	fd_want_recv_safe(l->rx.fd);
117 }
118 
119 /* Disable receipt of incoming connections for listener <l>. The receiver must
120  * still be valid.
121  */
uxdg_disable_listener(struct listener * l)122 static void uxdg_disable_listener(struct listener *l)
123 {
124 	fd_stop_recv(l->rx.fd);
125 }
126 
127 /* Suspend a receiver. Returns < 0 in case of failure, 0 if the receiver
128  * was totally stopped, or > 0 if correctly suspended. Nothing is done for
129  * plain unix sockets since currently it's the new process which handles
130  * the renaming. Abstract sockets are completely unbound and closed so
131  * there's no need to stop the poller.
132  */
uxdg_suspend_receiver(struct receiver * rx)133 static int uxdg_suspend_receiver(struct receiver *rx)
134 {
135         struct listener *l = LIST_ELEM(rx, struct listener *, rx);
136 
137         if (((struct sockaddr_un *)&rx->addr)->sun_path[0])
138                 return 1;
139 
140         /* Listener's lock already held. Call lockless version of
141          * unbind_listener. */
142         do_unbind_listener(l);
143         return 0;
144 }
145 
146 /*
147  * Local variables:
148  *  c-indent-level: 8
149  *  c-basic-offset: 8
150  * End:
151  */
152