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