]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/net/sock.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / spdk / lib / net / sock.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <errno.h>
35 #include <netdb.h>
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
38 #include <stdbool.h>
39 #include <stddef.h>
40 #include <stdint.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/ioctl.h>
44 #include <sys/socket.h>
45 #include <unistd.h>
46
47 #include "spdk/event.h"
48 #include "spdk/log.h"
49 #include "spdk/net.h"
50
51 #define MAX_TMPBUF 1024
52 #define PORTNUMLEN 32
53
54 static int get_addr_str(struct sockaddr_in *paddr, char *host, size_t hlen)
55 {
56 if (paddr == NULL || host == NULL)
57 return -1;
58
59 uint8_t *pa = (uint8_t *)&paddr->sin_addr.s_addr;
60 snprintf(host, hlen, "%u.%u.%u.%u", pa[0], pa[1], pa[2], pa[3]);
61
62 return 0;
63 }
64
65 int
66 spdk_sock_getaddr(int sock, char *saddr, int slen, char *caddr, int clen)
67 {
68 struct sockaddr_storage sa;
69 socklen_t salen;
70 int rc;
71
72 memset(&sa, 0, sizeof sa);
73 salen = sizeof sa;
74 rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
75 if (rc != 0) {
76 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
77 return -1;
78 }
79
80 switch (sa.ss_family) {
81 case AF_UNIX:
82 /* Acceptable connection types that don't have IPs */
83 return 0;
84 case AF_INET:
85 case AF_INET6:
86 /* Code below will get IP addresses */
87 break;
88 default:
89 /* Unsupported socket family */
90 return -1;
91 }
92
93 rc = get_addr_str((struct sockaddr_in *)&sa, saddr, slen);
94 if (rc != 0) {
95 SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
96 return -1;
97 }
98
99 memset(&sa, 0, sizeof sa);
100 salen = sizeof sa;
101 rc = getpeername(sock, (struct sockaddr *) &sa, &salen);
102 if (rc != 0) {
103 SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno);
104 return -1;
105 }
106
107 rc = get_addr_str((struct sockaddr_in *)&sa, caddr, clen);
108 if (rc != 0) {
109 SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno);
110 return -1;
111 }
112
113 return 0;
114 }
115
116 enum spdk_sock_create_type {
117 SPDK_SOCK_CREATE_LISTEN,
118 SPDK_SOCK_CREATE_CONNECT,
119 };
120
121 static int
122 spdk_sock_create(const char *ip, int port, enum spdk_sock_create_type type)
123 {
124 char buf[MAX_TMPBUF];
125 char portnum[PORTNUMLEN];
126 char *p;
127 struct addrinfo hints, *res, *res0;
128 int sock, nonblock;
129 int val = 1;
130 int rc;
131
132 if (ip == NULL)
133 return -1;
134 if (ip[0] == '[') {
135 snprintf(buf, sizeof(buf), "%s", ip + 1);
136 p = strchr(buf, ']');
137 if (p != NULL)
138 *p = '\0';
139 ip = (const char *) &buf[0];
140 if (strcasecmp(ip, "*") == 0) {
141 snprintf(buf, sizeof(buf), "::");
142 ip = (const char *) &buf[0];
143 }
144 } else if (strcasecmp(ip, "*") == 0) {
145 snprintf(buf, sizeof(buf), "0.0.0.0");
146 ip = (const char *) &buf[0];
147 }
148
149 snprintf(portnum, sizeof portnum, "%d", port);
150 memset(&hints, 0, sizeof hints);
151 hints.ai_family = PF_UNSPEC;
152 hints.ai_socktype = SOCK_STREAM;
153 hints.ai_flags = AI_NUMERICSERV;
154 hints.ai_flags |= AI_PASSIVE;
155 hints.ai_flags |= AI_NUMERICHOST;
156 rc = getaddrinfo(ip, portnum, &hints, &res0);
157 if (rc != 0) {
158 SPDK_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno);
159 return -1;
160 }
161
162 /* try listen */
163 sock = -1;
164 for (res = res0; res != NULL; res = res->ai_next) {
165 retry:
166 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
167 if (sock < 0) {
168 /* error */
169 continue;
170 }
171 rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
172 if (rc != 0) {
173 close(sock);
174 /* error */
175 continue;
176 }
177 rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof val);
178 if (rc != 0) {
179 close(sock);
180 /* error */
181 continue;
182 }
183
184 if (type == SPDK_SOCK_CREATE_LISTEN) {
185 rc = bind(sock, res->ai_addr, res->ai_addrlen);
186 if (rc != 0) {
187 SPDK_ERRLOG("bind() failed, errno = %d\n", errno);
188 switch (errno) {
189 case EINTR:
190 /* interrupted? */
191 close(sock);
192 goto retry;
193 case EADDRNOTAVAIL:
194 SPDK_ERRLOG("IP address %s not available. "
195 "Verify IP address in config file "
196 "and make sure setup script is "
197 "run before starting spdk app.\n", ip);
198 /* fallthrough */
199 default:
200 /* try next family */
201 close(sock);
202 sock = -1;
203 continue;
204 }
205 }
206 /* bind OK */
207 rc = listen(sock, 512);
208 if (rc != 0) {
209 SPDK_ERRLOG("listen() failed, errno = %d\n", errno);
210 close(sock);
211 sock = -1;
212 break;
213 }
214 } else if (type == SPDK_SOCK_CREATE_CONNECT) {
215 rc = connect(sock, res->ai_addr, res->ai_addrlen);
216 if (rc != 0) {
217 SPDK_ERRLOG("connect() failed, errno = %d\n", errno);
218 /* try next family */
219 close(sock);
220 sock = -1;
221 continue;
222 }
223 }
224
225 nonblock = 1;
226 rc = ioctl(sock, FIONBIO, &nonblock);
227 if (rc != 0) {
228 SPDK_ERRLOG("ioctl(FIONBIO) failed\n");
229 close(sock);
230 sock = -1;
231 break;
232 }
233 break;
234 }
235 freeaddrinfo(res0);
236
237 if (sock < 0) {
238 return -1;
239 }
240 return sock;
241 }
242
243 int
244 spdk_sock_listen(const char *ip, int port)
245 {
246 return spdk_sock_create(ip, port, SPDK_SOCK_CREATE_LISTEN);
247 }
248
249 int
250 spdk_sock_connect(const char *ip, int port)
251 {
252 return spdk_sock_create(ip, port, SPDK_SOCK_CREATE_CONNECT);
253 }
254
255 int
256 spdk_sock_accept(int sock)
257 {
258 struct sockaddr_storage sa;
259 socklen_t salen;
260
261 memset(&sa, 0, sizeof(sa));
262 salen = sizeof(sa);
263 return accept(sock, (struct sockaddr *)&sa, &salen);
264 }
265
266 int
267 spdk_sock_close(int sock)
268 {
269 return close(sock);
270 }
271
272 ssize_t
273 spdk_sock_recv(int sock, void *buf, size_t len)
274 {
275 return recv(sock, buf, len, MSG_DONTWAIT);
276 }
277
278 ssize_t
279 spdk_sock_writev(int sock, struct iovec *iov, int iovcnt)
280 {
281 return writev(sock, iov, iovcnt);
282 }
283
284 int
285 spdk_sock_set_recvlowat(int s, int nbytes)
286 {
287 int val;
288 int rc;
289
290 val = nbytes;
291 rc = setsockopt(s, SOL_SOCKET, SO_RCVLOWAT, &val, sizeof val);
292 if (rc != 0)
293 return -1;
294 return 0;
295 }
296
297 int
298 spdk_sock_set_recvbuf(int sock, int sz)
299 {
300 return setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
301 &sz, sizeof(sz));
302 }
303
304 int
305 spdk_sock_set_sendbuf(int sock, int sz)
306 {
307 return setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
308 &sz, sizeof(sz));
309 }
310
311 bool
312 spdk_sock_is_ipv6(int sock)
313 {
314 struct sockaddr_storage sa;
315 socklen_t salen;
316 int rc;
317
318 memset(&sa, 0, sizeof sa);
319 salen = sizeof sa;
320 rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
321 if (rc != 0) {
322 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
323 return false;
324 }
325
326 return (sa.ss_family == AF_INET6);
327 }
328
329 bool
330 spdk_sock_is_ipv4(int sock)
331 {
332 struct sockaddr_storage sa;
333 socklen_t salen;
334 int rc;
335
336 memset(&sa, 0, sizeof sa);
337 salen = sizeof sa;
338 rc = getsockname(sock, (struct sockaddr *) &sa, &salen);
339 if (rc != 0) {
340 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
341 return false;
342 }
343
344 return (sa.ss_family == AF_INET);
345 }