4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 #include "spdk/stdinc.h"
36 #if defined(__linux__)
37 #include <sys/epoll.h>
38 #elif defined(__FreeBSD__)
39 #include <sys/event.h>
43 #include "spdk/sock.h"
44 #include "spdk_internal/sock.h"
46 #define MAX_TMPBUF 1024
49 struct spdk_posix_sock
{
50 struct spdk_sock base
;
54 struct spdk_posix_sock_group_impl
{
55 struct spdk_sock_group_impl base
;
60 get_addr_str(struct sockaddr
*sa
, char *host
, size_t hlen
)
62 const char *result
= NULL
;
64 if (sa
== NULL
|| host
== NULL
) {
68 switch (sa
->sa_family
) {
70 result
= inet_ntop(AF_INET
, &(((struct sockaddr_in
*)sa
)->sin_addr
),
74 result
= inet_ntop(AF_INET6
, &(((struct sockaddr_in6
*)sa
)->sin6_addr
),
88 #define __posix_sock(sock) (struct spdk_posix_sock *)sock
89 #define __posix_group_impl(group) (struct spdk_posix_sock_group_impl *)group
92 spdk_posix_sock_getaddr(struct spdk_sock
*_sock
, char *saddr
, int slen
, uint16_t *sport
,
93 char *caddr
, int clen
, uint16_t *cport
)
95 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
96 struct sockaddr_storage sa
;
100 assert(sock
!= NULL
);
102 memset(&sa
, 0, sizeof sa
);
104 rc
= getsockname(sock
->fd
, (struct sockaddr
*) &sa
, &salen
);
106 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno
);
110 switch (sa
.ss_family
) {
112 /* Acceptable connection types that don't have IPs */
116 /* Code below will get IP addresses */
119 /* Unsupported socket family */
123 rc
= get_addr_str((struct sockaddr
*)&sa
, saddr
, slen
);
125 SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno
);
130 if (sa
.ss_family
== AF_INET
) {
131 *sport
= ntohs(((struct sockaddr_in
*) &sa
)->sin_port
);
132 } else if (sa
.ss_family
== AF_INET6
) {
133 *sport
= ntohs(((struct sockaddr_in6
*) &sa
)->sin6_port
);
137 memset(&sa
, 0, sizeof sa
);
139 rc
= getpeername(sock
->fd
, (struct sockaddr
*) &sa
, &salen
);
141 SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno
);
145 rc
= get_addr_str((struct sockaddr
*)&sa
, caddr
, clen
);
147 SPDK_ERRLOG("getnameinfo() failed (errno=%d)\n", errno
);
152 if (sa
.ss_family
== AF_INET
) {
153 *cport
= ntohs(((struct sockaddr_in
*) &sa
)->sin_port
);
154 } else if (sa
.ss_family
== AF_INET6
) {
155 *cport
= ntohs(((struct sockaddr_in6
*) &sa
)->sin6_port
);
162 enum spdk_posix_sock_create_type
{
163 SPDK_SOCK_CREATE_LISTEN
,
164 SPDK_SOCK_CREATE_CONNECT
,
167 static struct spdk_sock
*
168 spdk_posix_sock_create(const char *ip
, int port
, enum spdk_posix_sock_create_type type
)
170 struct spdk_posix_sock
*sock
;
171 char buf
[MAX_TMPBUF
];
172 char portnum
[PORTNUMLEN
];
174 struct addrinfo hints
, *res
, *res0
;
183 snprintf(buf
, sizeof(buf
), "%s", ip
+ 1);
184 p
= strchr(buf
, ']');
188 ip
= (const char *) &buf
[0];
191 snprintf(portnum
, sizeof portnum
, "%d", port
);
192 memset(&hints
, 0, sizeof hints
);
193 hints
.ai_family
= PF_UNSPEC
;
194 hints
.ai_socktype
= SOCK_STREAM
;
195 hints
.ai_flags
= AI_NUMERICSERV
;
196 hints
.ai_flags
|= AI_PASSIVE
;
197 hints
.ai_flags
|= AI_NUMERICHOST
;
198 rc
= getaddrinfo(ip
, portnum
, &hints
, &res0
);
200 SPDK_ERRLOG("getaddrinfo() failed (errno=%d)\n", errno
);
206 for (res
= res0
; res
!= NULL
; res
= res
->ai_next
) {
208 fd
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
213 rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof val
);
219 rc
= setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &val
, sizeof val
);
226 if (res
->ai_family
== AF_INET6
) {
227 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &val
, sizeof val
);
235 if (type
== SPDK_SOCK_CREATE_LISTEN
) {
236 rc
= bind(fd
, res
->ai_addr
, res
->ai_addrlen
);
238 SPDK_ERRLOG("bind() failed, errno = %d\n", errno
);
245 SPDK_ERRLOG("IP address %s not available. "
246 "Verify IP address in config file "
247 "and make sure setup script is "
248 "run before starting spdk app.\n", ip
);
251 /* try next family */
258 rc
= listen(fd
, 512);
260 SPDK_ERRLOG("listen() failed, errno = %d\n", errno
);
265 } else if (type
== SPDK_SOCK_CREATE_CONNECT
) {
266 rc
= connect(fd
, res
->ai_addr
, res
->ai_addrlen
);
268 SPDK_ERRLOG("connect() failed, errno = %d\n", errno
);
269 /* try next family */
276 flag
= fcntl(fd
, F_GETFL
);
277 if (fcntl(fd
, F_SETFL
, flag
| O_NONBLOCK
) < 0) {
278 SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", fd
, errno
);
291 sock
= calloc(1, sizeof(*sock
));
293 SPDK_ERRLOG("sock allocation failed\n");
302 static struct spdk_sock
*
303 spdk_posix_sock_listen(const char *ip
, int port
)
305 return spdk_posix_sock_create(ip
, port
, SPDK_SOCK_CREATE_LISTEN
);
308 static struct spdk_sock
*
309 spdk_posix_sock_connect(const char *ip
, int port
)
311 return spdk_posix_sock_create(ip
, port
, SPDK_SOCK_CREATE_CONNECT
);
314 static struct spdk_sock
*
315 spdk_posix_sock_accept(struct spdk_sock
*_sock
)
317 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
318 struct sockaddr_storage sa
;
321 struct spdk_posix_sock
*new_sock
;
324 memset(&sa
, 0, sizeof(sa
));
327 assert(sock
!= NULL
);
329 rc
= accept(sock
->fd
, (struct sockaddr
*)&sa
, &salen
);
335 flag
= fcntl(rc
, F_GETFL
);
336 if ((!(flag
& O_NONBLOCK
)) && (fcntl(rc
, F_SETFL
, flag
| O_NONBLOCK
) < 0)) {
337 SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%d)\n", rc
, errno
);
342 new_sock
= calloc(1, sizeof(*sock
));
343 if (new_sock
== NULL
) {
344 SPDK_ERRLOG("sock allocation failed\n");
350 return &new_sock
->base
;
354 spdk_posix_sock_close(struct spdk_sock
*_sock
)
356 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
359 rc
= close(sock
->fd
);
368 spdk_posix_sock_recv(struct spdk_sock
*_sock
, void *buf
, size_t len
)
370 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
372 return recv(sock
->fd
, buf
, len
, MSG_DONTWAIT
);
376 spdk_posix_sock_writev(struct spdk_sock
*_sock
, struct iovec
*iov
, int iovcnt
)
378 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
380 return writev(sock
->fd
, iov
, iovcnt
);
384 spdk_posix_sock_set_recvlowat(struct spdk_sock
*_sock
, int nbytes
)
386 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
390 assert(sock
!= NULL
);
393 rc
= setsockopt(sock
->fd
, SOL_SOCKET
, SO_RCVLOWAT
, &val
, sizeof val
);
401 spdk_posix_sock_set_recvbuf(struct spdk_sock
*_sock
, int sz
)
403 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
405 assert(sock
!= NULL
);
407 return setsockopt(sock
->fd
, SOL_SOCKET
, SO_RCVBUF
,
412 spdk_posix_sock_set_sendbuf(struct spdk_sock
*_sock
, int sz
)
414 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
416 assert(sock
!= NULL
);
418 return setsockopt(sock
->fd
, SOL_SOCKET
, SO_SNDBUF
,
423 spdk_posix_sock_is_ipv6(struct spdk_sock
*_sock
)
425 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
426 struct sockaddr_storage sa
;
430 assert(sock
!= NULL
);
432 memset(&sa
, 0, sizeof sa
);
434 rc
= getsockname(sock
->fd
, (struct sockaddr
*) &sa
, &salen
);
436 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno
);
440 return (sa
.ss_family
== AF_INET6
);
444 spdk_posix_sock_is_ipv4(struct spdk_sock
*_sock
)
446 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
447 struct sockaddr_storage sa
;
451 assert(sock
!= NULL
);
453 memset(&sa
, 0, sizeof sa
);
455 rc
= getsockname(sock
->fd
, (struct sockaddr
*) &sa
, &salen
);
457 SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno
);
461 return (sa
.ss_family
== AF_INET
);
464 static struct spdk_sock_group_impl
*
465 spdk_posix_sock_group_impl_create(void)
467 struct spdk_posix_sock_group_impl
*group_impl
;
470 #if defined(__linux__)
471 fd
= epoll_create1(0);
472 #elif defined(__FreeBSD__)
479 group_impl
= calloc(1, sizeof(*group_impl
));
480 if (group_impl
== NULL
) {
481 SPDK_ERRLOG("group_impl allocation failed\n");
488 return &group_impl
->base
;
492 spdk_posix_sock_group_impl_add_sock(struct spdk_sock_group_impl
*_group
, struct spdk_sock
*_sock
)
494 struct spdk_posix_sock_group_impl
*group
= __posix_group_impl(_group
);
495 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
498 #if defined(__linux__)
499 struct epoll_event event
;
501 event
.events
= EPOLLIN
;
502 event
.data
.ptr
= sock
;
504 rc
= epoll_ctl(group
->fd
, EPOLL_CTL_ADD
, sock
->fd
, &event
);
505 #elif defined(__FreeBSD__)
507 struct timespec ts
= {0};
509 EV_SET(&event
, sock
->fd
, EVFILT_READ
, EV_ADD
, 0, 0, sock
);
511 rc
= kevent(group
->fd
, &event
, 1, NULL
, 0, &ts
);
517 spdk_posix_sock_group_impl_remove_sock(struct spdk_sock_group_impl
*_group
, struct spdk_sock
*_sock
)
519 struct spdk_posix_sock_group_impl
*group
= __posix_group_impl(_group
);
520 struct spdk_posix_sock
*sock
= __posix_sock(_sock
);
522 #if defined(__linux__)
523 struct epoll_event event
;
525 /* Event parameter is ignored but some old kernel version still require it. */
526 rc
= epoll_ctl(group
->fd
, EPOLL_CTL_DEL
, sock
->fd
, &event
);
527 #elif defined(__FreeBSD__)
529 struct timespec ts
= {0};
531 EV_SET(&event
, sock
->fd
, EVFILT_READ
, EV_DELETE
, 0, 0, NULL
);
533 rc
= kevent(group
->fd
, &event
, 1, NULL
, 0, &ts
);
534 if (rc
== 0 && event
.flags
& EV_ERROR
) {
543 spdk_posix_sock_group_impl_poll(struct spdk_sock_group_impl
*_group
, int max_events
,
544 struct spdk_sock
**socks
)
546 struct spdk_posix_sock_group_impl
*group
= __posix_group_impl(_group
);
549 #if defined(__linux__)
550 struct epoll_event events
[MAX_EVENTS_PER_POLL
];
552 num_events
= epoll_wait(group
->fd
, events
, max_events
, 0);
553 #elif defined(__FreeBSD__)
554 struct kevent events
[MAX_EVENTS_PER_POLL
];
555 struct timespec ts
= {0};
557 num_events
= kevent(group
->fd
, NULL
, 0, events
, max_events
, &ts
);
560 if (num_events
== -1) {
564 for (i
= 0; i
< num_events
; i
++) {
565 #if defined(__linux__)
566 socks
[i
] = events
[i
].data
.ptr
;
567 #elif defined(__FreeBSD__)
568 socks
[i
] = events
[i
].udata
;
576 spdk_posix_sock_group_impl_close(struct spdk_sock_group_impl
*_group
)
578 struct spdk_posix_sock_group_impl
*group
= __posix_group_impl(_group
);
580 return close(group
->fd
);
583 static struct spdk_net_impl g_posix_net_impl
= {
585 .getaddr
= spdk_posix_sock_getaddr
,
586 .connect
= spdk_posix_sock_connect
,
587 .listen
= spdk_posix_sock_listen
,
588 .accept
= spdk_posix_sock_accept
,
589 .close
= spdk_posix_sock_close
,
590 .recv
= spdk_posix_sock_recv
,
591 .writev
= spdk_posix_sock_writev
,
592 .set_recvlowat
= spdk_posix_sock_set_recvlowat
,
593 .set_recvbuf
= spdk_posix_sock_set_recvbuf
,
594 .set_sendbuf
= spdk_posix_sock_set_sendbuf
,
595 .is_ipv6
= spdk_posix_sock_is_ipv6
,
596 .is_ipv4
= spdk_posix_sock_is_ipv4
,
597 .group_impl_create
= spdk_posix_sock_group_impl_create
,
598 .group_impl_add_sock
= spdk_posix_sock_group_impl_add_sock
,
599 .group_impl_remove_sock
= spdk_posix_sock_group_impl_remove_sock
,
600 .group_impl_poll
= spdk_posix_sock_group_impl_poll
,
601 .group_impl_close
= spdk_posix_sock_group_impl_close
,
604 SPDK_NET_IMPL_REGISTER(posix
, &g_posix_net_impl
);