1 /*-
2 * Copyright (c) 2018 UPLEX - Nils Goroll Systemoptimierung
3 * All rights reserved.
4 *
5 * Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/socket.h>
32 #include <sys/un.h>
33
34 #include <unistd.h>
35 #include <string.h>
36 #include <poll.h>
37 #include <stdio.h>
38
39 #include "vdef.h"
40 #include "vas.h"
41 #include "vus.h"
42 #include "vtcp.h"
43
44 int
VUS_resolver(const char * path,vus_resolved_f * func,void * priv,const char ** err)45 VUS_resolver(const char *path, vus_resolved_f *func, void *priv,
46 const char **err)
47 {
48 struct sockaddr_un uds;
49 int ret = 0;
50
51 AN(path);
52 assert(*path == '/');
53
54 AN(err);
55 *err = NULL;
56 if (strlen(path) + 1 > sizeof(uds.sun_path)) {
57 *err = "Path too long for a Unix domain socket";
58 return (-1);
59 }
60 bprintf(uds.sun_path, "%s", path);
61 uds.sun_family = PF_UNIX;
62 if (func != NULL)
63 ret = func(priv, &uds);
64 return (ret);
65 }
66
67 int
VUS_bind(const struct sockaddr_un * uds,const char ** errp)68 VUS_bind(const struct sockaddr_un *uds, const char **errp)
69 {
70 int sd, e;
71 socklen_t sl = sizeof(*uds);
72
73 if (errp != NULL)
74 *errp = NULL;
75
76 sd = socket(PF_UNIX, SOCK_STREAM, 0);
77 if (sd < 0) {
78 if (errp != NULL)
79 *errp = "socket(2)";
80 return (-1);
81 }
82
83 if (unlink(uds->sun_path) != 0 && errno != ENOENT) {
84 if (errp != NULL)
85 *errp = "unlink(2)";
86 e = errno;
87 closefd(&sd);
88 errno = e;
89 return (-1);
90 }
91
92 if (bind(sd, (const void*)uds, sl) != 0) {
93 if (errp != NULL)
94 *errp = "bind(2)";
95 e = errno;
96 closefd(&sd);
97 errno = e;
98 return (-1);
99 }
100 return (sd);
101 }
102
103 int
VUS_connect(const char * path,int msec)104 VUS_connect(const char *path, int msec)
105 {
106 int s, i;
107 struct pollfd fds[1];
108 struct sockaddr_un uds;
109 socklen_t sl = (socklen_t) sizeof(uds);
110
111 if (path == NULL)
112 return (-1);
113 uds.sun_family = PF_UNIX;
114 bprintf(uds.sun_path, "%s", path);
115 AN(sl);
116
117 s = socket(PF_UNIX, SOCK_STREAM, 0);
118 if (s < 0)
119 return (s);
120
121 /* Set the socket non-blocking */
122 if (msec != 0)
123 VTCP_nonblocking(s);
124
125 i = connect(s, (const void*)&uds, sl);
126 if (i == 0)
127 return (s);
128 if (errno != EINPROGRESS) {
129 closefd(&s);
130 return (-1);
131 }
132
133 if (msec < 0) {
134 /*
135 * Caller is responsible for waiting and
136 * calling VTCP_connected
137 */
138 return (s);
139 }
140
141 assert(msec > 0);
142 /* Exercise our patience, polling for write */
143 fds[0].fd = s;
144 fds[0].events = POLLWRNORM;
145 fds[0].revents = 0;
146 i = poll(fds, 1, msec);
147
148 if (i == 0) {
149 /* Timeout, close and give up */
150 closefd(&s);
151 errno = ETIMEDOUT;
152 return (-1);
153 }
154
155 return (VTCP_connected(s));
156 }
157