2 * Copyright (C) 2015-2018 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
28 #include <sys/types.h>
29 #include <sys/socket.h>
33 #include "afb-socket.h"
34 #include "afb-systemd.h"
40 /******************************************************************************/
42 static int open_unix(const char *spec, int server)
45 struct sockaddr_un addr;
48 abstract = spec[0] == '@';
50 /* check the length */
51 length = strlen(spec);
57 /* remove the file on need */
58 if (server && !abstract)
62 fd = socket(AF_UNIX, SOCK_STREAM, 0);
67 memset(&addr, 0, sizeof addr);
68 addr.sun_family = AF_UNIX;
69 strcpy(addr.sun_path, spec);
71 addr.sun_path[0] = 0; /* implement abstract sockets */
74 rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
76 rc = connect(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
85 static int open_inet(const char *spec, int server)
88 const char *service, *host, *api;
89 struct addrinfo hint, *rai, *iai;
92 api = strrchr(spec, '/');
93 service = strrchr(spec, ':');
94 if (api == NULL || service == NULL || api < service) {
98 host = strndupa(spec, service++ - spec);
99 service = strndupa(service, api - service);
102 memset(&hint, 0, sizeof hint);
103 hint.ai_family = AF_INET;
104 hint.ai_socktype = SOCK_STREAM;
105 rc = getaddrinfo(host, service, &hint, &rai);
113 while (iai != NULL) {
114 fd = socket(iai->ai_family, iai->ai_socktype, iai->ai_protocol);
117 rc = bind(fd, iai->ai_addr, iai->ai_addrlen);
119 rc = connect(fd, iai->ai_addr, iai->ai_addrlen);
133 static int open_systemd(const char *spec)
135 #if defined(NO_SYSTEMD_ACTIVATION)
136 errno = EAFNOSUPPORT;
139 return afb_systemd_fds_for(spec);
143 /******************************************************************************/
155 unsigned noreuseaddr: 1;
156 unsigned nolisten: 1;
159 static struct entry entries[] = { /* default at first place */
166 .type = Type_Systemd,
176 /******************************************************************************/
178 /* get the entry of the uri by searching to its prefix */
179 static struct entry *get_entry(const char *uri, int *offset)
181 int l, search = 1, i = (int)(sizeof entries / sizeof * entries);
189 l = (int)strlen(entries[i].prefix);
190 search = strncmp(uri, entries[i].prefix, l);
198 static int open_any(const char *uri, int server)
203 /* search for the entry */
204 e = get_entry(uri, &offset);
210 /* open the socket */
213 fd = open_unix(uri, server);
216 fd = open_inet(uri, server);
219 fd = open_systemd(uri);
222 errno = EAFNOSUPPORT;
230 fcntl(fd, F_SETFD, FD_CLOEXEC);
231 fcntl(fd, F_SETFL, O_NONBLOCK);
233 if (!e->noreuseaddr) {
235 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof rc);
243 struct fdev *afb_socket_open(const char *uri, int server)
248 fd = open_any(uri, server);
252 fdev = afb_fdev_create(fd);
261 ERROR("can't make %s socket for %s", server ? "server" : "client", uri);