nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* source: xio-unix.c */ |
2 | /* Copyright Gerhard Rieger */ |
||
3 | /* Published under the GNU General Public License V.2, see file COPYING */ |
||
4 | |||
5 | /* this file contains the source for opening addresses of UNIX socket type */ |
||
6 | |||
7 | #include "xiosysincludes.h" |
||
8 | #include "xioopen.h" |
||
9 | |||
10 | #include "xio-socket.h" |
||
11 | #include "xio-listen.h" |
||
12 | #include "xio-unix.h" |
||
13 | #include "xio-named.h" |
||
14 | |||
15 | |||
16 | #if WITH_UNIX |
||
17 | |||
18 | /* to avoid unneccessary "live" if () conditionals when no abstract support is |
||
19 | compiled in (or at least to give optimizing compilers a good chance) we need |
||
20 | a constant that can be used in C expressions */ |
||
21 | #if WITH_ABSTRACT_UNIXSOCKET |
||
22 | # define ABSTRACT 1 |
||
23 | #else |
||
24 | # define ABSTRACT 0 |
||
25 | #endif |
||
26 | static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3); |
||
27 | static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3); |
||
28 | static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3); |
||
29 | static int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3); |
||
30 | static |
||
31 | int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, |
||
32 | int xioflags, xiofile_t *xxfd, unsigned groups, |
||
33 | int abstract, int dummy2, int dummy3); |
||
34 | static |
||
35 | int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3); |
||
36 | |||
37 | /* the first free parameter is 0 for "normal" unix domain sockets, or 1 for |
||
38 | abstract unix sockets (Linux); the second and third parameters are unsused */ |
||
39 | static const struct xioaddr_endpoint_desc xioendpoint_unix_connect1 = { XIOADDR_SYS, "unix-connect", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_connect, 0, 0, 0 HELP(":<filename>") }; |
||
40 | const union xioaddr_desc *xioaddrs_unix_connect[] = { (union xioaddr_desc *)&xioendpoint_unix_connect1, NULL }; |
||
41 | |||
42 | #if WITH_LISTEN |
||
43 | static const struct xioaddr_endpoint_desc xioendpoint_unix_listen1 = { XIOADDR_SYS, "unix-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_listen, 0, 0, 0 HELP(":<filename>") }; |
||
44 | const union xioaddr_desc *xioaddrs_unix_listen[] = { (union xioaddr_desc *)&xioendpoint_unix_listen1, NULL }; |
||
45 | #endif /* WITH_LISTEN */ |
||
46 | |||
47 | static const struct xioaddr_endpoint_desc xioendpoint_unix_sendto1 = { XIOADDR_SYS, "unix-sendto", 1, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_sendto, 0, 0, 0 HELP(":<filename>") }; |
||
48 | const union xioaddr_desc *xioaddrs_unix_sendto[] = { (union xioaddr_desc *)&xioendpoint_unix_sendto1, NULL }; |
||
49 | |||
50 | static const struct xioaddr_endpoint_desc xioendpoint_unix_recvfrom1= { XIOADDR_SYS, "unix-recvfrom",1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recvfrom, 0, 0, 0 HELP(":<filename>") }; |
||
51 | const union xioaddr_desc *xioaddrs_unix_recvfrom[]= { (union xioaddr_desc *)&xioendpoint_unix_recvfrom1, NULL }; |
||
52 | |||
53 | static const struct xioaddr_endpoint_desc xioendpoint_unix_recv1 = { XIOADDR_SYS, "unix-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recv, 0, 0, 0 HELP(":<filename>") }; |
||
54 | const union xioaddr_desc *xioaddrs_unix_recv[] = { (union xioaddr_desc *)&xioendpoint_unix_recv1, NULL }; |
||
55 | |||
56 | static const struct xioaddr_endpoint_desc xioendpoint_unix_client1 = { XIOADDR_SYS, "unix-client", 1, XIOBIT_ALL, GROUP_FD|GROUP_NAMED|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_client, 0, 0, 0 HELP(":<filename>") }; |
||
57 | const union xioaddr_desc *xioaddrs_unix_client[] = { (union xioaddr_desc *)&xioendpoint_unix_client1, NULL }; |
||
58 | |||
59 | #if WITH_ABSTRACT_UNIXSOCKET |
||
60 | static const struct xioaddr_endpoint_desc xioendpoint_abstract_connect1 = { XIOADDR_SYS, "abstract-connect", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_connect, 1, 0, 0 HELP(":<filename>") }; |
||
61 | const union xioaddr_desc *xioaddrs_abstract_connect[] = { (union xioaddr_desc *)&xioendpoint_abstract_connect1, NULL }; |
||
62 | #if WITH_LISTEN |
||
63 | static const struct xioaddr_endpoint_desc xioendpoint_abstract_listen1 = { XIOADDR_SYS, "abstract-listen", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_LISTEN|GROUP_CHILD|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_listen, 1, 0, 0 HELP(":<filename>") }; |
||
64 | const union xioaddr_desc *xioaddrs_abstract_listen[] = { (union xioaddr_desc *)&xioendpoint_abstract_listen1, NULL }; |
||
65 | #endif /* WITH_LISTEN */ |
||
66 | static const struct xioaddr_endpoint_desc xioendpoint_abstract_sendto1 = { XIOADDR_SYS, "abstract-sendto", 1, XIOBIT_WRONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_sendto, 1, 0, 0 HELP(":<filename>") }; |
||
67 | const union xioaddr_desc *xioaddrs_abstract_sendto[] = { (union xioaddr_desc *)&xioendpoint_abstract_sendto1, NULL }; |
||
68 | static const struct xioaddr_endpoint_desc xioendpoint_abstract_recvfrom1= { XIOADDR_SYS, "abstract-recvfrom", 1, XIOBIT_RDONLY|XIOBIT_RDWR, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY|GROUP_CHILD, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recvfrom, 1, 0, 0 HELP(":<filename>") }; |
||
69 | const union xioaddr_desc *xioaddrs_abstract_recvfrom[] = { (union xioaddr_desc *)&xioendpoint_abstract_recvfrom1, NULL }; |
||
70 | static const struct xioaddr_endpoint_desc xioendpoint_abstract_recv1 = { XIOADDR_SYS, "abstract-recv", 1, XIOBIT_RDONLY, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_NONE, xioopen_unix_recv, 1, 0, 0 HELP(":<filename>") }; |
||
71 | const union xioaddr_desc *xioaddrs_abstract_recv[] = { (union xioaddr_desc *)&xioendpoint_abstract_recv1, NULL }; |
||
72 | static const struct xioaddr_endpoint_desc xioendpoint_abstract_client1 = { XIOADDR_SYS, "abstract-client", 1, XIOBIT_ALL, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_UNIX|GROUP_RETRY, XIOSHUT_DOWN, XIOCLOSE_CLOSE, xioopen_unix_client, 1, 0, 0 HELP(":<filename>") }; |
||
73 | const union xioaddr_desc *xioaddrs_abstract_client[] = { (union xioaddr_desc *)&xioendpoint_abstract_client1, NULL }; |
||
74 | #endif /* WITH_ABSTRACT_UNIXSOCKET */ |
||
75 | |||
76 | const struct optdesc xioopt_unix_tightsocklen = { "unix-tightsocklen", "tightsocklen", OPT_UNIX_TIGHTSOCKLEN, GROUP_SOCK_UNIX, PH_PREBIND, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.un.tight), XIO_SIZEOF(para.socket.un.tight) }; |
||
77 | |||
78 | |||
79 | /* fills the socket address struct and returns its effective length. |
||
80 | abstract is usually 0; != 0 generates an abstract socket address on Linux. |
||
81 | tight!=0 calculates the resulting length from the path length, not from the |
||
82 | structures length; this is more common (see option unix-tightsocklen) |
||
83 | the struct need not be initialized when calling this function. |
||
84 | */ |
||
85 | socklen_t |
||
86 | xiosetunix(int pf, |
||
87 | struct sockaddr_un *saun, |
||
88 | const char *path, |
||
89 | bool abstract, |
||
90 | bool tight) { |
||
91 | size_t pathlen; |
||
92 | socklen_t len; |
||
93 | |||
94 | socket_un_init(saun); |
||
95 | #ifdef WITH_ABSTRACT_UNIXSOCKET |
||
96 | if (abstract) { |
||
97 | if ((pathlen = strlen(path)) >= sizeof(saun->sun_path)) { |
||
98 | Warn2("socket address "F_Zu" characters long, truncating to "F_Zu"", |
||
99 | pathlen+1, sizeof(saun->sun_path)); |
||
100 | } |
||
101 | saun->sun_path[0] = '\0'; /* so it's abstract */ |
||
102 | strncpy(saun->sun_path+1, path, sizeof(saun->sun_path)-1); /* ok */ |
||
103 | if (tight) { |
||
104 | len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+ |
||
105 | MIN(pathlen+1, sizeof(saun->sun_path)); |
||
106 | #if HAVE_STRUCT_SOCKADDR_SALEN |
||
107 | saun->sun_len = len; |
||
108 | #endif |
||
109 | } else { |
||
110 | len = sizeof(struct sockaddr_un); |
||
111 | } |
||
112 | return len; |
||
113 | } |
||
114 | #endif /* WITH_ABSTRACT_UNIXSOCKET */ |
||
115 | |||
116 | if ((pathlen = strlen(path)) > sizeof(saun->sun_path)) { |
||
117 | Warn2("unix socket address "F_Zu" characters long, truncating to "F_Zu"", |
||
118 | pathlen, sizeof(saun->sun_path)); |
||
119 | } |
||
120 | strncpy(saun->sun_path, path, sizeof(saun->sun_path)); /* ok */ |
||
121 | if (tight) { |
||
122 | len = sizeof(struct sockaddr_un)-sizeof(saun->sun_path)+ |
||
123 | MIN(pathlen, sizeof(saun->sun_path)); |
||
124 | #if HAVE_STRUCT_SOCKADDR_SALEN |
||
125 | saun->sun_len = len; |
||
126 | #endif |
||
127 | } else { |
||
128 | len = sizeof(struct sockaddr_un); |
||
129 | } |
||
130 | return len; |
||
131 | } |
||
132 | |||
133 | #if WITH_LISTEN |
||
134 | static int xioopen_unix_listen(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) { |
||
135 | /* we expect the form: filename */ |
||
136 | const char *name; |
||
137 | xiosingle_t *xfd = &xxfd->stream; |
||
138 | int pf = PF_UNIX; |
||
139 | int socktype = SOCK_STREAM; |
||
140 | int protocol = 0; |
||
141 | struct sockaddr_un us; |
||
142 | socklen_t uslen; |
||
143 | struct opt *opts0 = NULL; |
||
144 | pid_t pid = Getpid(); |
||
145 | bool opt_unlink_early = false; |
||
146 | bool opt_unlink_close = true; |
||
147 | int result; |
||
148 | |||
149 | if (argc != 2) { |
||
150 | Error2("%s: wrong number of parameters (%d instead of 1)", |
||
151 | argv[0], argc-1); |
||
152 | return STAT_NORETRY; |
||
153 | } |
||
154 | name = argv[1]; |
||
155 | |||
156 | xfd->para.socket.un.tight = true; |
||
157 | retropt_socket_pf(opts, &pf); |
||
158 | |||
159 | if (!(ABSTRACT && abstract)) { |
||
160 | /* only for non abstract because abstract do not work in file system */ |
||
161 | retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); |
||
162 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
163 | } |
||
164 | |||
165 | if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; |
||
166 | applyopts(-1, opts, PH_INIT); |
||
167 | applyopts_named(name, opts, PH_EARLY); /* umask! */ |
||
168 | applyopts_offset(xfd, opts); |
||
169 | applyopts(-1, opts, PH_EARLY); |
||
170 | |||
171 | uslen = xiosetunix(pf, &us, name, abstract, xfd->para.socket.un.tight); |
||
172 | |||
173 | if (!(ABSTRACT && abstract)) { |
||
174 | if (opt_unlink_early) { |
||
175 | if (Unlink(name) < 0) { |
||
176 | if (errno == ENOENT) { |
||
177 | Warn2("unlink(\"%s\"): %s", name, strerror(errno)); |
||
178 | } else { |
||
179 | Error2("unlink(\"%s\"): %s", name, strerror(errno)); |
||
180 | } |
||
181 | } |
||
182 | } else { |
||
183 | struct stat buf; |
||
184 | if (Lstat(name, &buf) == 0) { |
||
185 | Error1("\"%s\" exists", name); |
||
186 | return STAT_RETRYLATER; |
||
187 | } |
||
188 | } |
||
189 | if (opt_unlink_close) { |
||
190 | if ((xfd->unlink_close = strdup(name)) == NULL) { |
||
191 | Error1("strdup(\"%s\"): out of memory", name); |
||
192 | } |
||
193 | xfd->opt_unlink_close = true; |
||
194 | } |
||
195 | |||
196 | /* trying to set user-early, perm-early etc. here is useless because |
||
197 | file system entry is available only past bind() call. */ |
||
198 | } |
||
199 | |||
200 | opts0 = copyopts(opts, GROUP_ALL); |
||
201 | |||
202 | /* this may fork() */ |
||
203 | if ((result = |
||
204 | xioopen_listen(xfd, xioflags, |
||
205 | (struct sockaddr *)&us, uslen, |
||
206 | opts, opts0, pf, socktype, protocol)) |
||
207 | != 0) |
||
208 | return result; |
||
209 | |||
210 | if (!(ABSTRACT && abstract)) { |
||
211 | if (opt_unlink_close) { |
||
212 | if (pid != Getpid()) { |
||
213 | /* in a child process - do not unlink-close here! */ |
||
214 | xfd->opt_unlink_close = false; |
||
215 | } |
||
216 | } |
||
217 | } |
||
218 | |||
219 | return 0; |
||
220 | } |
||
221 | #endif /* WITH_LISTEN */ |
||
222 | |||
223 | |||
224 | static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) { |
||
225 | /* we expect the form: filename */ |
||
226 | const char *name; |
||
227 | struct single *xfd = &xxfd->stream; |
||
228 | int rw = (xioflags&XIO_ACCMODE); |
||
229 | int pf = PF_UNIX; |
||
230 | int socktype = SOCK_STREAM; |
||
231 | int protocol = 0; |
||
232 | struct sockaddr_un them, us; |
||
233 | socklen_t themlen, uslen = sizeof(us); |
||
234 | bool needbind = false; |
||
235 | bool opt_unlink_close = false; |
||
236 | int result; |
||
237 | |||
238 | if (argc != 2) { |
||
239 | Error2("%s: wrong number of parameters (%d instead of 1)", |
||
240 | argv[0], argc-1); |
||
241 | return STAT_NORETRY; |
||
242 | } |
||
243 | |||
244 | name = argv[1]; |
||
245 | |||
246 | xfd->para.socket.un.tight = true; |
||
247 | retropt_socket_pf(opts, &pf); |
||
248 | xfd->howtoshut = XIOSHUT_DOWN; |
||
249 | if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; |
||
250 | applyopts(-1, opts, PH_INIT); |
||
251 | applyopts_offset(xfd, opts); |
||
252 | applyopts(-1, opts, PH_EARLY); |
||
253 | |||
254 | themlen = xiosetunix(pf, &them, name, abstract, xfd->para.socket.un.tight); |
||
255 | if (!(ABSTRACT && abstract)) { |
||
256 | /* only for non abstract because abstract do not work in file system */ |
||
257 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
258 | } |
||
259 | if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, |
||
260 | (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) { |
||
261 | needbind = true; |
||
262 | } |
||
263 | |||
264 | if (opt_unlink_close) { |
||
265 | if ((xfd->unlink_close = strdup(name)) == NULL) { |
||
266 | Error1("strdup(\"%s\"): out of memory", name); |
||
267 | } |
||
268 | xfd->opt_unlink_close = true; |
||
269 | } |
||
270 | |||
271 | if ((result = |
||
272 | xioopen_connect(xfd, |
||
273 | needbind?(struct sockaddr *)&us:NULL, uslen, |
||
274 | (struct sockaddr *)&them, themlen, |
||
275 | opts, pf, socktype, protocol, false)) != 0) { |
||
276 | return result; |
||
277 | } |
||
278 | if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd; |
||
279 | if (!XIOWITHRD(rw)) xfd->rfd = -1; |
||
280 | if ((result = _xio_openlate(xfd, opts)) < 0) { |
||
281 | return result; |
||
282 | } |
||
283 | return STAT_OK; |
||
284 | } |
||
285 | |||
286 | |||
287 | /* |
||
288 | returns the resulting FD in xfd->rfd, independend of xioflags |
||
289 | */ |
||
290 | static int xioopen_unix_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy, int dummy3) { |
||
291 | /* we expect the form: filename */ |
||
292 | const char *name; |
||
293 | xiosingle_t *xfd = &xxfd->stream; |
||
294 | int rw = (xioflags&XIO_ACCMODE); |
||
295 | int pf = PF_UNIX; |
||
296 | int socktype = SOCK_DGRAM; |
||
297 | int protocol = 0; |
||
298 | union sockaddr_union us; |
||
299 | socklen_t uslen = sizeof(us); |
||
300 | bool needbind = false; |
||
301 | bool opt_unlink_close = false; |
||
302 | int result; |
||
303 | |||
304 | if (argc != 2) { |
||
305 | Error2("%s: wrong number of parameters (%d instead of 1)", |
||
306 | argv[0], argc-1); |
||
307 | return STAT_NORETRY; |
||
308 | } |
||
309 | |||
310 | uslen = socket_init(pf, &us); |
||
311 | xfd->salen = socket_init(pf, &xfd->peersa); |
||
312 | |||
313 | retropt_int(opts, OPT_SO_TYPE, &socktype); |
||
314 | |||
315 | name = argv[1]; |
||
316 | |||
317 | xfd->para.socket.un.tight = true; |
||
318 | retropt_socket_pf(opts, &pf); |
||
319 | applyopts_offset(xfd, opts); |
||
320 | |||
321 | xfd->salen = xiosetunix(pf, &xfd->peersa.un, name, abstract, xfd->para.socket.un.tight); |
||
322 | |||
323 | if (!(ABSTRACT && abstract)) { |
||
324 | /* only for non abstract because abstract do not work in file system */ |
||
325 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
326 | } |
||
327 | |||
328 | xfd->dtype = XIODATA_RECVFROM; |
||
329 | |||
330 | if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, |
||
331 | (abstract<<1)| xfd->para.socket.un.tight, 0, 0) == STAT_OK) { |
||
332 | needbind = true; |
||
333 | } |
||
334 | |||
335 | if (opt_unlink_close) { |
||
336 | if ((xfd->unlink_close = strdup(name)) == NULL) { |
||
337 | Error1("strdup(\"%s\"): out of memory", name); |
||
338 | } |
||
339 | xfd->opt_unlink_close = true; |
||
340 | } |
||
341 | |||
342 | if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; |
||
343 | applyopts(-1, opts, PH_INIT); |
||
344 | |||
345 | if ((result = |
||
346 | _xioopen_dgram_sendto(needbind?&us:NULL, uslen, |
||
347 | opts, xioflags, xfd, groups, |
||
348 | pf, socktype, protocol)) != STAT_OK) { |
||
349 | return result; |
||
350 | } |
||
351 | if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd; |
||
352 | if (!XIOWITHRD(rw)) xfd->rfd = -1; |
||
353 | return STAT_OK; |
||
354 | } |
||
355 | |||
356 | |||
357 | static |
||
358 | int xioopen_unix_recvfrom(int argc, const char *argv[], struct opt *opts, |
||
359 | int xioflags, xiofile_t *xxfd, unsigned groups, |
||
360 | int abstract, int dummy2, int dummy3) { |
||
361 | /* we expect the form: filename */ |
||
362 | const char *name; |
||
363 | xiosingle_t *xfd = &xxfd->stream; |
||
364 | int pf = PF_UNIX; |
||
365 | int socktype = SOCK_DGRAM; |
||
366 | int protocol = 0; |
||
367 | struct sockaddr_un us; |
||
368 | socklen_t uslen; |
||
369 | bool needbind = true; |
||
370 | bool opt_unlink_early = false; |
||
371 | bool opt_unlink_close = true; |
||
372 | |||
373 | if (argc != 2) { |
||
374 | Error2("%s: wrong number of parameters (%d instead of 1)", |
||
375 | argv[0], argc-1); |
||
376 | return STAT_NORETRY; |
||
377 | } |
||
378 | name = argv[1]; |
||
379 | |||
380 | xfd->para.socket.un.tight = true; |
||
381 | retropt_socket_pf(opts, &pf); |
||
382 | retropt_int(opts, OPT_SO_TYPE, &socktype); |
||
383 | |||
384 | if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; |
||
385 | applyopts(-1, opts, PH_INIT); |
||
386 | applyopts_named(name, opts, PH_EARLY); /* umask! */ |
||
387 | applyopts_offset(xfd, opts); |
||
388 | retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); |
||
389 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
390 | |||
391 | if (!(ABSTRACT && abstract)) { |
||
392 | /* only for non abstract because abstract do not work in file system */ |
||
393 | retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); |
||
394 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
395 | } |
||
396 | applyopts(-1, opts, PH_EARLY); |
||
397 | |||
398 | uslen = xiosetunix(pf, &us, name, abstract, xfd->para.socket.un.tight); |
||
399 | |||
400 | #if 0 |
||
401 | if (retropt_bind(opts, pf, socktype, protocol, (struct sockaddr *)&us, &uslen, |
||
402 | (abstract<<1)|xfd->para.socket.un.tight, 0, 0) == STAT_OK) { |
||
403 | } |
||
404 | #endif |
||
405 | |||
406 | if (!(ABSTRACT && abstract)) { |
||
407 | if (opt_unlink_early) { |
||
408 | if (Unlink(name) < 0) { |
||
409 | if (errno == ENOENT) { |
||
410 | Warn2("unlink(\"%s\"): %s", name, strerror(errno)); |
||
411 | } else { |
||
412 | Error2("unlink(\"%s\"): %s", name, strerror(errno)); |
||
413 | } |
||
414 | } |
||
415 | } else { |
||
416 | struct stat buf; |
||
417 | if (Lstat(name, &buf) == 0) { |
||
418 | Error1("\"%s\" exists", name); |
||
419 | return STAT_RETRYLATER; |
||
420 | } |
||
421 | } |
||
422 | if (opt_unlink_close) { |
||
423 | if ((xfd->unlink_close = strdup(name)) == NULL) { |
||
424 | Error1("strdup(\"%s\"): out of memory", name); |
||
425 | } |
||
426 | xfd->opt_unlink_close = true; |
||
427 | } |
||
428 | |||
429 | /* trying to set user-early, perm-early etc. here is useless because |
||
430 | file system entry is available only past bind() call. */ |
||
431 | } |
||
432 | applyopts_named(name, opts, PH_EARLY); /* umask! */ |
||
433 | |||
434 | xfd->para.socket.la.soa.sa_family = pf; |
||
435 | |||
436 | xfd->dtype = XIODATA_RECVFROM_ONE; |
||
437 | |||
438 | /* this may fork */ |
||
439 | return |
||
440 | _xioopen_dgram_recvfrom(xfd, xioflags, |
||
441 | needbind?(struct sockaddr *)&us:NULL, uslen, |
||
442 | opts, pf, socktype, protocol, E_ERROR); |
||
443 | } |
||
444 | |||
445 | |||
446 | static |
||
447 | int xioopen_unix_recv(int argc, const char *argv[], struct opt *opts, |
||
448 | int xioflags, xiofile_t *xxfd, unsigned groups, |
||
449 | int abstract, int dummy2, int dummy3) { |
||
450 | /* we expect the form: filename */ |
||
451 | const char *name; |
||
452 | xiosingle_t *xfd = &xxfd->stream; |
||
453 | int pf = PF_UNIX; |
||
454 | int socktype = SOCK_DGRAM; |
||
455 | int protocol = 0; |
||
456 | union sockaddr_union us; |
||
457 | socklen_t uslen; |
||
458 | bool opt_unlink_early = false; |
||
459 | bool opt_unlink_close = true; |
||
460 | int result; |
||
461 | |||
462 | if (argc != 2) { |
||
463 | Error2("%s: wrong number of parameters (%d instead of 1)", |
||
464 | argv[0], argc-1); |
||
465 | return STAT_NORETRY; |
||
466 | } |
||
467 | name = argv[1]; |
||
468 | |||
469 | xfd->para.socket.un.tight = true; |
||
470 | retropt_socket_pf(opts, &pf); |
||
471 | if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; |
||
472 | applyopts(-1, opts, PH_INIT); |
||
473 | applyopts_named(name, opts, PH_EARLY); /* umask! */ |
||
474 | applyopts_offset(xfd, opts); |
||
475 | |||
476 | if (!(ABSTRACT && abstract)) { |
||
477 | /* only for non abstract because abstract do not work in file system */ |
||
478 | retropt_bool(opts, OPT_UNLINK_EARLY, &opt_unlink_early); |
||
479 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
480 | |||
481 | } |
||
482 | applyopts(-1, opts, PH_EARLY); |
||
483 | |||
484 | uslen = xiosetunix(pf, &us.un, name, abstract, xfd->para.socket.un.tight); |
||
485 | |||
486 | #if 0 |
||
487 | if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, |
||
488 | (abstract<<1)|xfd->para.socket.un.tight, 0, 0) |
||
489 | == STAT_OK) { |
||
490 | } |
||
491 | #endif |
||
492 | |||
493 | if (!(ABSTRACT && abstract)) { |
||
494 | if (opt_unlink_early) { |
||
495 | if (Unlink(name) < 0) { |
||
496 | if (errno == ENOENT) { |
||
497 | Warn2("unlink(\"%s\"): %s", name, strerror(errno)); |
||
498 | } else { |
||
499 | Error2("unlink(\"%s\"): %s", name, strerror(errno)); |
||
500 | } |
||
501 | } |
||
502 | } else { |
||
503 | struct stat buf; |
||
504 | if (Lstat(name, &buf) == 0) { |
||
505 | Error1("\"%s\" exists", name); |
||
506 | return STAT_RETRYLATER; |
||
507 | } |
||
508 | } |
||
509 | if (opt_unlink_close) { |
||
510 | if ((xfd->unlink_close = strdup(name)) == NULL) { |
||
511 | Error1("strdup(\"%s\"): out of memory", name); |
||
512 | } |
||
513 | xfd->opt_unlink_close = true; |
||
514 | } |
||
515 | } |
||
516 | applyopts_named(name, opts, PH_EARLY); /* umask! */ |
||
517 | |||
518 | xfd->para.socket.la.soa.sa_family = pf; |
||
519 | |||
520 | xfd->dtype = XIODATA_RECV; |
||
521 | result = _xioopen_dgram_recv(xfd, xioflags, &us.soa, uslen, |
||
522 | opts, pf, socktype, protocol, E_ERROR); |
||
523 | return result; |
||
524 | } |
||
525 | |||
526 | |||
527 | static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) { |
||
528 | /* we expect the form: filename */ |
||
529 | if (argc != 2) { |
||
530 | Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1); |
||
531 | } |
||
532 | |||
533 | return |
||
534 | _xioopen_unix_client(&xxfd->stream, xioflags, groups, abstract, opts, |
||
535 | argv[1]); |
||
536 | } |
||
537 | |||
538 | /* establishes communication with an existing UNIX type socket. supports stream |
||
539 | and datagram socket types: first tries to connect(), but when this fails it |
||
540 | falls back to sendto(). |
||
541 | applies and consumes the following option: |
||
542 | PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, |
||
543 | PH_CONNECTED, PH_LATE, ?PH_CONNECT |
||
544 | OFUNC_OFFSET, |
||
545 | OPT_PROTOCOL_FAMILY, OPT_UNIX_TIGHTSOCKLEN, OPT_UNLINK_CLOSE, OPT_BIND, |
||
546 | OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_CLOEXEC, OPT_USER, OPT_GROUP, ?OPT_FORK, |
||
547 | */ |
||
548 | int |
||
549 | _xioopen_unix_client(xiosingle_t *xfd, int xioflags, unsigned groups, |
||
550 | int abstract, struct opt *opts, const char *name) { |
||
551 | int rw = (xioflags&XIO_ACCMODE); |
||
552 | int pf = PF_UNIX; |
||
553 | int socktype = 0; /* to be determined by server socket type */ |
||
554 | int protocol = 0; |
||
555 | union sockaddr_union them, us; |
||
556 | socklen_t themlen, uslen = sizeof(us); |
||
557 | bool needbind = false; |
||
558 | bool opt_unlink_close = false; |
||
559 | struct opt *opts0; |
||
560 | int result; |
||
561 | |||
562 | xfd->para.socket.un.tight = true; |
||
563 | retropt_socket_pf(opts, &pf); |
||
564 | if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY; |
||
565 | applyopts(-1, opts, PH_INIT); |
||
566 | applyopts_offset(xfd, opts); |
||
567 | applyopts(-1, opts, PH_EARLY); |
||
568 | |||
569 | themlen = xiosetunix(pf, &them.un, name, abstract, xfd->para.socket.un.tight); |
||
570 | if (!(ABSTRACT && abstract)) { |
||
571 | /* only for non abstract because abstract do not work in file system */ |
||
572 | retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close); |
||
573 | } |
||
574 | if (retropt_bind(opts, pf, socktype, protocol, &us.soa, &uslen, |
||
575 | (abstract<<1)|xfd->para.socket.un.tight, 0, 0) |
||
576 | != STAT_NOACTION) { |
||
577 | needbind = true; |
||
578 | } |
||
579 | |||
580 | if (opt_unlink_close) { |
||
581 | if ((xfd->unlink_close = strdup(name)) == NULL) { |
||
582 | Error1("strdup(\"%s\"): out of memory", name); |
||
583 | } |
||
584 | xfd->opt_unlink_close = true; |
||
585 | } |
||
586 | |||
587 | /* save options, because we might have to start again */ |
||
588 | opts0 = copyopts(opts, GROUP_ALL); |
||
589 | |||
590 | /* xfd->dtype = DATA_STREAM; // is default */ |
||
591 | if ((result = |
||
592 | xioopen_connect(xfd, |
||
593 | needbind?(struct sockaddr *)&us:NULL, uslen, |
||
594 | (struct sockaddr *)&them, themlen, |
||
595 | opts, pf, socktype?socktype:SOCK_STREAM, protocol, |
||
596 | false)) != 0) { |
||
597 | if (errno == EPROTOTYPE) { |
||
598 | if (needbind) { |
||
599 | Unlink(us.un.sun_path); |
||
600 | } |
||
601 | |||
602 | dropopts2(opts, PH_INIT, PH_SPEC); opts = opts0; |
||
603 | |||
604 | xfd->peersa = them; |
||
605 | xfd->salen = sizeof(struct sockaddr_un); |
||
606 | if ((result = |
||
607 | _xioopen_dgram_sendto(needbind?&us:NULL, uslen, |
||
608 | opts, xioflags, xfd, groups, |
||
609 | pf, socktype?socktype:SOCK_DGRAM, protocol)) |
||
610 | != 0) { |
||
611 | return result; |
||
612 | } |
||
613 | xfd->dtype = XIODATA_RECVFROM; |
||
614 | } |
||
615 | } |
||
616 | if (XIOWITHWR(rw)) xfd->wfd = xfd->rfd; |
||
617 | if (!XIOWITHRD(rw)) xfd->rfd = -1; |
||
618 | if ((result = _xio_openlate(xfd, opts)) < 0) { |
||
619 | return result; |
||
620 | } |
||
621 | return 0; |
||
622 | } |
||
623 | |||
624 | |||
625 | /* returns information that can be used for constructing an environment |
||
626 | variable describing the socket address. |
||
627 | if idx is 0, this function writes "ADDR" into namebuff and the path into |
||
628 | valuebuff, and returns 0 (which means that no more info is there). |
||
629 | if idx is != 0, it returns -1 |
||
630 | namelen and valuelen contain the max. allowed length of output chars in the |
||
631 | respective buffer. |
||
632 | on error this function returns -1. |
||
633 | */ |
||
634 | int |
||
635 | xiosetsockaddrenv_unix(int idx, char *namebuff, size_t namelen, |
||
636 | char *valuebuff, size_t valuelen, |
||
637 | struct sockaddr_un *sa, socklen_t salen, int ipproto) { |
||
638 | if (idx != 0) { |
||
639 | return -1; |
||
640 | } |
||
641 | strcpy(namebuff, "ADDR"); |
||
642 | sockaddr_unix_info(sa, salen, valuebuff, valuelen); |
||
643 | return 0; |
||
644 | } |
||
645 | |||
646 | #endif /* WITH_UNIX */ |