]> git.proxmox.com Git - mirror_kronosnet.git/blame - libknet/transport_sctp.c
[sctp] free access list only if the socket is valid
[mirror_kronosnet.git] / libknet / transport_sctp.c
CommitLineData
16a7e6cb 1/*
a1bbd0e1 2 * Copyright (C) 2016-2019 Red Hat, Inc. All rights reserved.
16a7e6cb
FDN
3 *
4 * Author: Christine Caulfield <ccaulfie@redhat.com>
5 *
dd52554d 6 * This software licensed under LGPL-2.0+
16a7e6cb
FDN
7 */
8
e3e37ffd
CC
9#include "config.h"
10
e3e37ffd
CC
11#include <string.h>
12#include <unistd.h>
13#include <errno.h>
14#include <pthread.h>
e3e37ffd
CC
15#include <sys/types.h>
16#include <sys/socket.h>
f762bb6e 17#include <stdlib.h>
e3e37ffd 18
f762bb6e 19#include "compat.h"
e3e37ffd 20#include "host.h"
eee77df6 21#include "links.h"
d2333aab 22#include "links_acl.h"
0cb8e8ba 23#include "links_acl_ip.h"
e3e37ffd
CC
24#include "logging.h"
25#include "common.h"
4ac6704d 26#include "transport_common.h"
82d1d36e 27#include "threads_common.h"
e3e37ffd 28
3c62178c
FDN
29#ifdef HAVE_NETINET_SCTP_H
30#include <netinet/sctp.h>
4ac6704d 31#include "transport_sctp.h"
e3e37ffd 32
e3e37ffd 33typedef struct sctp_handle_info {
82d1d36e
FDN
34 struct knet_list_head listen_links_list;
35 struct knet_list_head connect_links_list;
e3e37ffd 36 int connect_epollfd;
82d1d36e 37 int connectsockfd[2];
e3e37ffd 38 int listen_epollfd;
82d1d36e 39 int listensockfd[2];
e3e37ffd
CC
40 pthread_t connect_thread;
41 pthread_t listen_thread;
57ebf58c
FW
42 socklen_t event_subscribe_kernel_size;
43 char *event_subscribe_buffer;
e3e37ffd
CC
44} sctp_handle_info_t;
45
82d1d36e
FDN
46/*
47 * use by fd_tracker data type
48 */
d56e3615
FDN
49#define SCTP_NO_LINK_INFO 0
50#define SCTP_LISTENER_LINK_INFO 1
51#define SCTP_ACCEPTED_LINK_INFO 2
52#define SCTP_CONNECT_LINK_INFO 3
82d1d36e
FDN
53
54/*
55 * this value is per listener
56 */
57#define MAX_ACCEPTED_SOCKS 256
58
59typedef struct sctp_listen_link_info {
60 struct knet_list_head list;
e3e37ffd
CC
61 int listen_sock;
62 int accepted_socks[MAX_ACCEPTED_SOCKS];
82d1d36e
FDN
63 struct sockaddr_storage src_address;
64 int on_listener_epoll;
65 int on_rx_epoll;
66} sctp_listen_link_info_t;
67
d56e3615
FDN
68typedef struct sctp_accepted_link_info {
69 char mread_buf[KNET_DATABUFSIZE];
70 ssize_t mread_len;
71 sctp_listen_link_info_t *link_info;
72} sctp_accepted_link_info_t ;
73
82d1d36e 74typedef struct sctp_connect_link_info {
b715c049 75 struct knet_list_head list;
82d1d36e
FDN
76 sctp_listen_link_info_t *listener;
77 struct knet_link *link;
78 struct sockaddr_storage dst_address;
79 int connect_sock;
80 int on_connected_epoll;
81 int on_rx_epoll;
82 int close_sock;
83} sctp_connect_link_info_t;
e3e37ffd 84
82d1d36e
FDN
85/*
86 * socket handling functions
87 *
88 * those functions do NOT perform locking. locking
89 * should be handled in the right context from callers
90 */
91
92/*
93 * sockets are removed from rx_epoll from callers
94 * see also error handling functions
95 */
8a142f48 96static int _close_connect_socket(knet_handle_t knet_h, struct knet_link *kn_link)
e3e37ffd 97{
82d1d36e 98 int err = 0, savederrno = 0;
8a142f48 99 sctp_connect_link_info_t *info = kn_link->transport_link;
82d1d36e
FDN
100 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
101 struct epoll_event ev;
e3e37ffd 102
82d1d36e
FDN
103 if (info->on_connected_epoll) {
104 memset(&ev, 0, sizeof(struct epoll_event));
105 ev.events = EPOLLOUT;
106 ev.data.fd = info->connect_sock;
107 if (epoll_ctl(handle_info->connect_epollfd, EPOLL_CTL_DEL, info->connect_sock, &ev)) {
108 savederrno = errno;
109 err = -1;
110 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove connected socket from the epoll pool: %s",
111 strerror(errno));
112 goto exit_error;
113 }
114 info->on_connected_epoll = 0;
e3e37ffd
CC
115 }
116
82d1d36e
FDN
117exit_error:
118 if (info->connect_sock != -1) {
119 if (_set_fd_tracker(knet_h, info->connect_sock, KNET_MAX_TRANSPORTS, SCTP_NO_LINK_INFO, NULL) < 0) {
120 savederrno = errno;
121 err = -1;
122 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set fd tracker: %s",
123 strerror(savederrno));
124 goto exit_error;
125 }
126 close(info->connect_sock);
127 info->connect_sock = -1;
e3e37ffd
CC
128 }
129
82d1d36e
FDN
130 errno = savederrno;
131 return err;
132}
133
134static int _enable_sctp_notifications(knet_handle_t knet_h, int sock, const char *type)
135{
136 int err = 0, savederrno = 0;
57ebf58c
FW
137 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
138
139 if (setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS,
140 handle_info->event_subscribe_buffer,
141 handle_info->event_subscribe_kernel_size) < 0) {
e3e37ffd
CC
142 savederrno = errno;
143 err = -1;
815929bf 144 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to enable %s events: %s",
e3e37ffd 145 type, strerror(savederrno));
e3e37ffd
CC
146 }
147
82d1d36e 148 errno = savederrno;
e3e37ffd
CC
149 return err;
150}
151
c58507f9 152static int _configure_sctp_socket(knet_handle_t knet_h, int sock, struct sockaddr_storage *address, uint64_t flags, const char *type)
e3e37ffd 153{
82d1d36e
FDN
154 int err = 0, savederrno = 0;
155 int value;
f762bb6e
CC
156 int level;
157
158#ifdef SOL_SCTP
159 level = SOL_SCTP;
160#else
161 level = IPPROTO_SCTP;
162#endif
e3e37ffd 163
c58507f9 164 if (_configure_transport_socket(knet_h, sock, address, flags, type) < 0) {
82d1d36e
FDN
165 savederrno = errno;
166 err = -1;
167 goto exit_error;
e3e37ffd
CC
168 }
169
82d1d36e 170 value = 1;
f762bb6e 171 if (setsockopt(sock, level, SCTP_NODELAY, &value, sizeof(value)) < 0) {
82d1d36e
FDN
172 savederrno = errno;
173 err = -1;
174 log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set sctp nodelay: %s",
175 strerror(savederrno));
176 goto exit_error;
e3e37ffd
CC
177 }
178
82d1d36e
FDN
179 if (_enable_sctp_notifications(knet_h, sock, type) < 0) {
180 savederrno = errno;
181 err = -1;
769deace
FDN
182 }
183
82d1d36e
FDN
184exit_error:
185 errno = savederrno;
186 return err;
e3e37ffd
CC
187}
188
940833bf 189static int _reconnect_socket(knet_handle_t knet_h, struct knet_link *kn_link)
e3e37ffd 190{
82d1d36e 191 int err = 0, savederrno = 0;
940833bf 192 sctp_connect_link_info_t *info = kn_link->transport_link;
82d1d36e 193 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
e3e37ffd 194 struct epoll_event ev;
e3e37ffd 195
940833bf 196 if (connect(info->connect_sock, (struct sockaddr *)&kn_link->dst_addr, sockaddr_len(&kn_link->dst_addr)) < 0) {
82d1d36e 197 if ((errno != EALREADY) && (errno != EINPROGRESS) && (errno != EISCONN)) {
e3e37ffd 198 savederrno = errno;
82d1d36e
FDN
199 err = -1;
200 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to connect SCTP socket %d: %s",
201 info->connect_sock, strerror(savederrno));
e3e37ffd
CC
202 goto exit_error;
203 }
e3e37ffd
CC
204 }
205
82d1d36e
FDN
206 if (!info->on_connected_epoll) {
207 memset(&ev, 0, sizeof(struct epoll_event));
208 ev.events = EPOLLOUT;
209 ev.data.fd = info->connect_sock;
210 if (epoll_ctl(handle_info->connect_epollfd, EPOLL_CTL_ADD, info->connect_sock, &ev)) {
e3e37ffd 211 savederrno = errno;
82d1d36e
FDN
212 err = -1;
213 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to add send/recv to epoll pool: %s",
e3e37ffd
CC
214 strerror(savederrno));
215 goto exit_error;
216 }
82d1d36e 217 info->on_connected_epoll = 1;
e3e37ffd
CC
218 }
219
82d1d36e
FDN
220exit_error:
221 errno = savederrno;
222 return err;
223}
224
940833bf 225static int _create_connect_socket(knet_handle_t knet_h, struct knet_link *kn_link)
82d1d36e
FDN
226{
227 int err = 0, savederrno = 0;
940833bf 228 sctp_connect_link_info_t *info = kn_link->transport_link;
82d1d36e
FDN
229 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
230 struct epoll_event ev;
231 int connect_sock;
232
940833bf 233 connect_sock = socket(kn_link->dst_addr.ss_family, SOCK_STREAM, IPPROTO_SCTP);
82d1d36e 234 if (connect_sock < 0) {
e3e37ffd 235 savederrno = errno;
82d1d36e
FDN
236 err = -1;
237 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to create send/recv socket: %s",
e3e37ffd
CC
238 strerror(savederrno));
239 goto exit_error;
240 }
241
c58507f9 242 if (_configure_sctp_socket(knet_h, connect_sock, &kn_link->dst_addr, kn_link->flags, "SCTP connect") < 0) {
82d1d36e
FDN
243 savederrno = errno;
244 err = -1;
245 goto exit_error;
246 }
247
248 if (_set_fd_tracker(knet_h, connect_sock, KNET_TRANSPORT_SCTP, SCTP_CONNECT_LINK_INFO, info) < 0) {
249 savederrno = errno;
250 err = -1;
251 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set fd tracker: %s",
252 strerror(savederrno));
253 goto exit_error;
254 }
b715c049 255
82d1d36e
FDN
256 info->connect_sock = connect_sock;
257 info->close_sock = 0;
940833bf 258 if (_reconnect_socket(knet_h, kn_link) < 0) {
82d1d36e
FDN
259 savederrno = errno;
260 err = -1;
261 goto exit_error;
262 }
e3e37ffd 263
e3e37ffd 264exit_error:
82d1d36e
FDN
265 if (err) {
266 if (info->on_connected_epoll) {
267 epoll_ctl(handle_info->connect_epollfd, EPOLL_CTL_DEL, connect_sock, &ev);
268 }
269 if (connect_sock >= 0) {
270 close(connect_sock);
271 }
272 }
273 errno = savederrno;
274 return err;
e3e37ffd
CC
275}
276
4ac6704d 277int sctp_transport_tx_sock_error(knet_handle_t knet_h, int sockfd, int recv_err, int recv_errno)
22d0a556 278{
6a6d337d
FDN
279 sctp_connect_link_info_t *connect_info = knet_h->knet_transport_fd_tracker[sockfd].data;
280 sctp_accepted_link_info_t *accepted_info = knet_h->knet_transport_fd_tracker[sockfd].data;
281 sctp_listen_link_info_t *listen_info;
282
22d0a556 283 if (recv_err < 0) {
6a6d337d
FDN
284 switch (knet_h->knet_transport_fd_tracker[sockfd].data_type) {
285 case SCTP_CONNECT_LINK_INFO:
286 if (connect_info->link->transport_connected == 0) {
287 return -1;
288 }
289 break;
290 case SCTP_ACCEPTED_LINK_INFO:
291 listen_info = accepted_info->link_info;
292 if (listen_info->listen_sock != sockfd) {
293 if (listen_info->on_rx_epoll == 0) {
294 return -1;
295 }
296 }
297 break;
298 }
22d0a556 299 if (recv_errno == EAGAIN) {
63ceb592 300#ifdef DEBUG
22d0a556 301 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Sock: %d is overloaded. Slowing TX down", sockfd);
63ceb592 302#endif
c49af4e3
CC
303 /* Don't hold onto the lock while sleeping */
304 pthread_rwlock_unlock(&knet_h->global_rwlock);
63ceb592 305 usleep(KNET_THREADS_TIMERES / 16);
c49af4e3 306 pthread_rwlock_rdlock(&knet_h->global_rwlock);
22d0a556
FDN
307 return 1;
308 }
309 return -1;
310 }
311 return 0;
312}
313
82d1d36e
FDN
314/*
315 * socket error management functions
316 *
317 * both called with global read lock.
318 *
319 * NOTE: we need to remove the fd from the epoll as soon as possible
320 * even before we notify the respective thread to take care of it
321 * because scheduling can make it so that this thread will overload
322 * and the threads supposed to take care of the error will never
323 * be able to take action.
324 * we CANNOT handle FDs here diretly (close/reconnect/etc) due
325 * to locking context. We need to delegate that to their respective
326 * management threads within global write lock.
327 *
328 * this function is called from:
329 * - RX thread with recv_err <= 0 directly on recvmmsg error
330 * - transport_rx_is_data when msg_len == 0 (recv_err = 1)
331 * - transport_rx_is_data on notification (recv_err = 2)
332 *
333 * basically this small abouse of recv_err is to detect notifications
334 * generated by sockets created by listen().
335 */
4ac6704d 336int sctp_transport_rx_sock_error(knet_handle_t knet_h, int sockfd, int recv_err, int recv_errno)
e3e37ffd 337{
e3e37ffd 338 struct epoll_event ev;
82d1d36e 339 sctp_connect_link_info_t *connect_info = knet_h->knet_transport_fd_tracker[sockfd].data;
d56e3615
FDN
340 sctp_accepted_link_info_t *accepted_info = knet_h->knet_transport_fd_tracker[sockfd].data;
341 sctp_listen_link_info_t *listen_info;
82d1d36e
FDN
342 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
343
344 switch (knet_h->knet_transport_fd_tracker[sockfd].data_type) {
345 case SCTP_CONNECT_LINK_INFO:
346 /*
347 * all connect link have notifications enabled
348 * and we accept only data from notification and
349 * generic recvmmsg errors.
350 *
351 * Errors generated by msg_len 0 can be ignored because
352 * they follow a notification (double notification)
353 */
354 if (recv_err != 1) {
355 connect_info->link->transport_connected = 0;
356 if (connect_info->on_rx_epoll) {
357 memset(&ev, 0, sizeof(struct epoll_event));
358 ev.events = EPOLLIN;
359 ev.data.fd = sockfd;
360 if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, sockfd, &ev)) {
361 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove EOFed socket from epoll pool: %s",
362 strerror(errno));
363 return -1;
364 }
365 connect_info->on_rx_epoll = 0;
366 }
367 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Notifying connect thread that sockfd %d received an error", sockfd);
368 if (sendto(handle_info->connectsockfd[1], &sockfd, sizeof(int), MSG_DONTWAIT | MSG_NOSIGNAL, NULL, 0) != sizeof(int)) {
369 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to notify connect thread: %s", strerror(errno));
370 }
371 }
372 break;
d56e3615
FDN
373 case SCTP_ACCEPTED_LINK_INFO:
374 listen_info = accepted_info->link_info;
82d1d36e
FDN
375 if (listen_info->listen_sock != sockfd) {
376 if (recv_err != 1) {
377 if (listen_info->on_rx_epoll) {
378 memset(&ev, 0, sizeof(struct epoll_event));
379 ev.events = EPOLLIN;
380 ev.data.fd = sockfd;
381 if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, sockfd, &ev)) {
382 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove EOFed socket from epoll pool: %s",
383 strerror(errno));
384 return -1;
385 }
386 listen_info->on_rx_epoll = 0;
387 }
388 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Notifying listen thread that sockfd %d received an error", sockfd);
389 if (sendto(handle_info->listensockfd[1], &sockfd, sizeof(int), MSG_DONTWAIT | MSG_NOSIGNAL, NULL, 0) != sizeof(int)) {
390 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to notify listen thread: %s", strerror(errno));
391 }
392 }
393 } else {
394 /*
395 * this means the listen() socket has generated
396 * a notification. now what? :-)
397 */
398 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received stray notification for listen() socket %d", sockfd);
399 }
400 break;
401 default:
45a6124b 402 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received unknown notification? %d", sockfd);
82d1d36e
FDN
403 break;
404 }
45a6124b
FDN
405 /*
406 * Under RX pressure we need to give time to IPC to pick up the message
407 */
c49af4e3
CC
408
409 /* Don't hold onto the lock while sleeping */
410 pthread_rwlock_unlock(&knet_h->global_rwlock);
45a6124b 411 usleep(KNET_THREADS_TIMERES / 2);
c49af4e3 412 pthread_rwlock_rdlock(&knet_h->global_rwlock);
82d1d36e
FDN
413 return 0;
414}
415
416/*
417 * NOTE: sctp_transport_rx_is_data is called with global rdlock
418 * delegate any FD error management to sctp_transport_rx_sock_error
419 * and keep this code to parsing incoming data only
420 */
4ac6704d 421int sctp_transport_rx_is_data(knet_handle_t knet_h, int sockfd, struct knet_mmsghdr *msg)
82d1d36e 422{
801bb12d 423 size_t i;
d56e3615
FDN
424 struct iovec *iov = msg->msg_hdr.msg_iov;
425 size_t iovlen = msg->msg_hdr.msg_iovlen;
82d1d36e
FDN
426 struct sctp_assoc_change *sac;
427 union sctp_notification *snp;
d56e3615 428 sctp_accepted_link_info_t *info = knet_h->knet_transport_fd_tracker[sockfd].data;
82d1d36e 429
d56e3615
FDN
430 if (!(msg->msg_hdr.msg_flags & MSG_NOTIFICATION)) {
431 if (msg->msg_len == 0) {
82d1d36e
FDN
432 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "received 0 bytes len packet: %d", sockfd);
433 /*
434 * NOTE: with event notification enabled, we receive error twice:
435 * 1) from the event notification
436 * 2) followed by a 0 byte msg_len
437 *
438 * This is generally not a problem if not for causing extra
439 * handling for the same issue. Should we drop notifications
440 * and keep the code generic (handle all errors via msg_len = 0)
441 * or keep the duplication as safety measure, or drop msg_len = 0
442 * handling (what about sockets without events enabled?)
443 */
444 sctp_transport_rx_sock_error(knet_h, sockfd, 1, 0);
445 return 1;
446 }
d56e3615
FDN
447 /*
448 * missing MSG_EOR has to be treated as a short read
449 * from the socket and we need to fill in the mread buf
450 * while we wait for MSG_EOR
451 */
452 if (!(msg->msg_hdr.msg_flags & MSG_EOR)) {
453 /*
454 * copy the incoming data into mread_buf + mread_len (incremental)
455 * and increase mread_len
456 */
457 memmove(info->mread_buf + info->mread_len, iov->iov_base, msg->msg_len);
458 info->mread_len = info->mread_len + msg->msg_len;
459 return 0;
460 }
461 /*
462 * got EOR.
463 * if mread_len is > 0 we are completing a packet from short reads
464 * complete reassembling the packet in mread_buf, copy it back in the iov
465 * and set the iov/msg len numbers (size) correctly
466 */
467 if (info->mread_len) {
468 /*
469 * add last fragment to mread_buf
470 */
471 memmove(info->mread_buf + info->mread_len, iov->iov_base, msg->msg_len);
472 info->mread_len = info->mread_len + msg->msg_len;
473 /*
474 * move all back into the iovec
475 */
476 memmove(iov->iov_base, info->mread_buf, info->mread_len);
477 msg->msg_len = info->mread_len;
478 info->mread_len = 0;
479 }
82d1d36e
FDN
480 return 2;
481 }
482
d56e3615 483 if (!(msg->msg_hdr.msg_flags & MSG_EOR)) {
82d1d36e
FDN
484 return 1;
485 }
486
487 for (i=0; i< iovlen; i++) {
488 snp = iov[i].iov_base;
489
490 switch (snp->sn_header.sn_type) {
491 case SCTP_ASSOC_CHANGE:
492 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] sctp assoc change");
493 sac = &snp->sn_assoc_change;
494 if (sac->sac_state == SCTP_COMM_LOST) {
495 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] sctp assoc change: comm_lost");
496 sctp_transport_rx_sock_error(knet_h, sockfd, 2, 0);
497 }
498 break;
499 case SCTP_SHUTDOWN_EVENT:
500 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] sctp shutdown event");
501 sctp_transport_rx_sock_error(knet_h, sockfd, 2, 0);
502 break;
503 case SCTP_SEND_FAILED:
504 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] sctp send failed");
505 break;
506 case SCTP_PEER_ADDR_CHANGE:
507 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] sctp peer addr change");
508 break;
509 case SCTP_REMOTE_ERROR:
510 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] sctp remote error");
511 break;
512 default:
513 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "[event] unknown sctp event type: %hu\n", snp->sn_header.sn_type);
514 break;
515 }
516 }
517 return 0;
518}
519
520/*
521 * connect / outgoing socket management thread
522 */
523
524/*
525 * _handle_connected_sctp* are called with a global write lock
526 * from the connect_thread
527 */
528static void _handle_connected_sctp(knet_handle_t knet_h, int connect_sock)
529{
e3e37ffd 530 int err;
82d1d36e 531 struct epoll_event ev;
e3e37ffd 532 unsigned int status, len = sizeof(status);
82d1d36e
FDN
533 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
534 sctp_connect_link_info_t *info = knet_h->knet_transport_fd_tracker[connect_sock].data;
940833bf 535 struct knet_link *kn_link = info->link;
e3e37ffd 536
82d1d36e
FDN
537 err = getsockopt(connect_sock, SOL_SOCKET, SO_ERROR, &status, &len);
538 if (err) {
539 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP getsockopt() on connecting socket %d failed: %s",
540 connect_sock, strerror(errno));
541 return;
542 }
e3e37ffd 543
82d1d36e 544 if (info->close_sock) {
940833bf 545 if (_close_connect_socket(knet_h, kn_link) < 0) {
82d1d36e
FDN
546 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to close sock %d from _handle_connected_sctp: %s", connect_sock, strerror(errno));
547 return;
e3e37ffd 548 }
82d1d36e 549 info->close_sock = 0;
940833bf 550 if (_create_connect_socket(knet_h, kn_link) < 0) {
82d1d36e
FDN
551 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to recreate connecting sock! %s", strerror(errno));
552 return;
e3e37ffd 553 }
82d1d36e
FDN
554 }
555
556 if (status) {
557 log_info(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP connect on %d to %s port %s failed: %s",
940833bf 558 connect_sock, kn_link->status.dst_ipaddr, kn_link->status.dst_port,
82d1d36e
FDN
559 strerror(status));
560
561 /*
562 * No need to create a new socket if connect failed,
563 * just retry connect
564 */
565 _reconnect_socket(knet_h, info->link);
e3e37ffd
CC
566 return;
567 }
568
82d1d36e
FDN
569 /*
570 * Connected - Remove us from the connect epoll
571 */
572 memset(&ev, 0, sizeof(struct epoll_event));
e3e37ffd 573 ev.events = EPOLLOUT;
82d1d36e
FDN
574 ev.data.fd = connect_sock;
575 if (epoll_ctl(handle_info->connect_epollfd, EPOLL_CTL_DEL, connect_sock, &ev)) {
815929bf 576 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove connected socket %d from epoll pool: %s",
82d1d36e 577 connect_sock, strerror(errno));
e3e37ffd 578 }
82d1d36e
FDN
579 info->on_connected_epoll = 0;
580
940833bf
CC
581 kn_link->transport_connected = 1;
582 kn_link->outsock = info->connect_sock;
e3e37ffd 583
82d1d36e 584 memset(&ev, 0, sizeof(struct epoll_event));
d26576a8 585 ev.events = EPOLLIN;
82d1d36e
FDN
586 ev.data.fd = connect_sock;
587 if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_ADD, connect_sock, &ev)) {
815929bf 588 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to add connected socket to epoll pool: %s",
d26576a8 589 strerror(errno));
e3e37ffd 590 }
82d1d36e 591 info->on_rx_epoll = 1;
b715c049 592
82d1d36e
FDN
593 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP handler fd %d now connected to %s port %s",
594 connect_sock,
940833bf 595 kn_link->status.dst_ipaddr, kn_link->status.dst_port);
e3e37ffd
CC
596}
597
82d1d36e 598static void _handle_connected_sctp_errors(knet_handle_t knet_h)
e3e37ffd 599{
82d1d36e
FDN
600 int sockfd = -1;
601 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
602 sctp_connect_link_info_t *info;
e3e37ffd 603
82d1d36e
FDN
604 if (recv(handle_info->connectsockfd[0], &sockfd, sizeof(int), MSG_DONTWAIT | MSG_NOSIGNAL) != sizeof(int)) {
605 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Short read on connectsockfd");
606 return;
607 }
e3e37ffd 608
82d1d36e
FDN
609 if (_is_valid_fd(knet_h, sockfd) < 1) {
610 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received stray notification for connected socket fd error");
611 return;
612 }
e3e37ffd 613
82d1d36e 614 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Processing connected error on socket: %d", sockfd);
e3e37ffd 615
82d1d36e 616 info = knet_h->knet_transport_fd_tracker[sockfd].data;
e3e37ffd 617
82d1d36e
FDN
618 info->close_sock = 1;
619 info->link->transport_connected = 0;
620 _reconnect_socket(knet_h, info->link);
621}
e3e37ffd
CC
622
623static void *_sctp_connect_thread(void *data)
624{
82d1d36e 625 int savederrno;
e3e37ffd 626 int i, nev;
82d1d36e
FDN
627 knet_handle_t knet_h = (knet_handle_t) data;
628 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
e3e37ffd
CC
629 struct epoll_event events[KNET_EPOLL_MAX_EVENTS];
630
6394d892 631 set_thread_status(knet_h, KNET_THREAD_SCTP_CONN, KNET_THREAD_STARTED);
aed6b5db 632
82d1d36e 633 while (!shutdown_in_progress(knet_h)) {
aed6b5db
FDN
634 nev = epoll_wait(handle_info->connect_epollfd, events, KNET_EPOLL_MAX_EVENTS, KNET_THREADS_TIMERES / 1000);
635
636 /*
637 * we use timeout to detect if thread is shutting down
638 */
639 if (nev == 0) {
640 continue;
641 }
e3e37ffd 642
82d1d36e
FDN
643 if (nev < 0) {
644 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP connect handler EPOLL ERROR: %s",
645 strerror(errno));
646 continue;
e3e37ffd
CC
647 }
648
82d1d36e
FDN
649 /*
650 * Sort out which FD has a connection
651 */
1dfc8220 652 savederrno = get_global_wrlock(knet_h);
82d1d36e
FDN
653 if (savederrno) {
654 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to get write lock: %s",
655 strerror(savederrno));
e3e37ffd
CC
656 continue;
657 }
658
82d1d36e
FDN
659 /*
660 * minor optimization: deduplicate events
661 *
662 * in some cases we can receive multiple notifcations
663 * of the same FD having issues or need handling.
664 * It's enough to process it once even tho it's safe
665 * to handle them multiple times.
666 */
e3e37ffd 667 for (i = 0; i < nev; i++) {
82d1d36e
FDN
668 if (events[i].data.fd == handle_info->connectsockfd[0]) {
669 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received notification from rx_error for connected socket");
670 _handle_connected_sctp_errors(knet_h);
671 } else {
672 if (_is_valid_fd(knet_h, events[i].data.fd) == 1) {
673 _handle_connected_sctp(knet_h, events[i].data.fd);
674 } else {
675 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received stray notification for dead fd %d\n", events[i].data.fd);
676 }
677 }
e3e37ffd 678 }
82d1d36e
FDN
679 pthread_rwlock_unlock(&knet_h->global_rwlock);
680 /*
681 * this thread can generate events for itself.
682 * we need to sleep in between loops to allow other threads
683 * to be scheduled
684 */
047e0362 685 usleep(knet_h->reconnect_int * 1000);
e3e37ffd 686 }
aed6b5db
FDN
687
688 set_thread_status(knet_h, KNET_THREAD_SCTP_CONN, KNET_THREAD_STOPPED);
689
e3e37ffd
CC
690 return NULL;
691}
692
693/*
82d1d36e
FDN
694 * listen/incoming connections management thread
695 */
696
697/*
698 * Listener received a new connection
699 * called with a write lock from main thread
e3e37ffd 700 */
82d1d36e 701static void _handle_incoming_sctp(knet_handle_t knet_h, int listen_sock)
e3e37ffd 702{
82d1d36e
FDN
703 int err = 0, savederrno = 0;
704 int new_fd;
705 int i = -1;
706 sctp_listen_link_info_t *info = knet_h->knet_transport_fd_tracker[listen_sock].data;
707 struct epoll_event ev;
708 struct sockaddr_storage ss;
709 socklen_t sock_len = sizeof(ss);
762c0098
FDN
710 char addr_str[KNET_MAX_HOST_LEN];
711 char port_str[KNET_MAX_PORT_LEN];
d56e3615 712 sctp_accepted_link_info_t *accept_info = NULL;
e3e37ffd 713
82d1d36e
FDN
714 new_fd = accept(listen_sock, (struct sockaddr *)&ss, &sock_len);
715 if (new_fd < 0) {
716 savederrno = errno;
717 err = -1;
718 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Incoming: accept error: %s", strerror(errno));
719 goto exit_error;
e3e37ffd
CC
720 }
721
762c0098
FDN
722 if (knet_addrtostr(&ss, sizeof(ss),
723 addr_str, KNET_MAX_HOST_LEN,
724 port_str, KNET_MAX_PORT_LEN) < 0) {
82d1d36e
FDN
725 savederrno = errno;
726 err = -1;
727 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Incoming: unable to gather socket info");
728 goto exit_error;
729 }
e3e37ffd 730
82d1d36e 731 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Incoming: received connection from: %s port: %s",
762c0098 732 addr_str, port_str);
d2333aab 733 if (knet_h->use_access_lists) {
fb462d4f 734 if (!check_validate(knet_h, listen_sock, KNET_TRANSPORT_SCTP, &ss)) {
d2333aab 735 savederrno = EINVAL;
d2333aab
FDN
736 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Connection rejected from %s/%s", addr_str, port_str);
737 close(new_fd);
0cb8e8ba
FDN
738 errno = savederrno;
739 return;
d2333aab
FDN
740 }
741 }
e3e37ffd 742
82d1d36e
FDN
743 /*
744 * Keep a track of all accepted FDs
745 */
746 for (i=0; i<MAX_ACCEPTED_SOCKS; i++) {
747 if (info->accepted_socks[i] == -1) {
748 info->accepted_socks[i] = new_fd;
749 break;
750 }
751 }
e3e37ffd 752
82d1d36e
FDN
753 if (i == MAX_ACCEPTED_SOCKS) {
754 errno = EBUSY;
755 err = -1;
756 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Incoming: too many connections!");
757 goto exit_error;
758 }
e3e37ffd 759
c58507f9 760 if (_configure_common_socket(knet_h, new_fd, 0, "SCTP incoming") < 0) { /* Inherit flags from listener? */
82d1d36e
FDN
761 savederrno = errno;
762 err = -1;
763 goto exit_error;
764 }
765
766 if (_enable_sctp_notifications(knet_h, new_fd, "Incoming connection") < 0) {
767 savederrno = errno;
768 err = -1;
769 goto exit_error;
770 }
e3e37ffd 771
d56e3615
FDN
772 accept_info = malloc(sizeof(sctp_accepted_link_info_t));
773 if (!accept_info) {
774 savederrno = errno;
775 err = -1;
776 goto exit_error;
777 }
778 memset(accept_info, 0, sizeof(sctp_accepted_link_info_t));
779
780 accept_info->link_info = info;
781
782 if (_set_fd_tracker(knet_h, new_fd, KNET_TRANSPORT_SCTP, SCTP_ACCEPTED_LINK_INFO, accept_info) < 0) {
82d1d36e
FDN
783 savederrno = errno;
784 err = -1;
785 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set fd tracker: %s",
786 strerror(errno));
787 goto exit_error;
788 }
e3e37ffd 789
82d1d36e
FDN
790 memset(&ev, 0, sizeof(struct epoll_event));
791 ev.events = EPOLLIN;
792 ev.data.fd = new_fd;
793 if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_ADD, new_fd, &ev)) {
794 savederrno = errno;
795 err = -1;
796 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Incoming: unable to add accepted socket %d to epoll pool: %s",
797 new_fd, strerror(errno));
798 goto exit_error;
799 }
800 info->on_rx_epoll = 1;
e3e37ffd 801
762c0098
FDN
802 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Incoming: accepted new fd %d for %s/%s (listen fd: %d). index: %d",
803 new_fd, addr_str, port_str, info->listen_sock, i);
82d1d36e
FDN
804
805exit_error:
82d1d36e
FDN
806 if (err) {
807 if ((i >= 0) || (i < MAX_ACCEPTED_SOCKS)) {
808 info->accepted_socks[i] = -1;
e3e37ffd 809 }
82d1d36e 810 _set_fd_tracker(knet_h, new_fd, KNET_MAX_TRANSPORTS, SCTP_NO_LINK_INFO, NULL);
d56e3615 811 free(accept_info);
82d1d36e 812 close(new_fd);
e3e37ffd 813 }
82d1d36e
FDN
814 errno = savederrno;
815 return;
e3e37ffd
CC
816}
817
82d1d36e
FDN
818/*
819 * Listen thread received a notification of a bad socket that needs closing
820 * called with a write lock from main thread
821 */
822static void _handle_listen_sctp_errors(knet_handle_t knet_h)
e3e37ffd 823{
82d1d36e
FDN
824 int sockfd = -1;
825 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
d56e3615 826 sctp_accepted_link_info_t *accept_info;
82d1d36e 827 sctp_listen_link_info_t *info;
f66ebfd6
FDN
828 struct knet_host *host;
829 int link_idx;
82d1d36e 830 int i;
e3e37ffd 831
82d1d36e
FDN
832 if (recv(handle_info->listensockfd[0], &sockfd, sizeof(int), MSG_DONTWAIT | MSG_NOSIGNAL) != sizeof(int)) {
833 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Short read on listensockfd");
834 return;
e3e37ffd 835 }
e3e37ffd 836
82d1d36e
FDN
837 if (_is_valid_fd(knet_h, sockfd) < 1) {
838 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received stray notification for listen socket fd error");
839 return;
840 }
e3e37ffd 841
82d1d36e 842 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Processing listen error on socket: %d", sockfd);
e3e37ffd 843
d56e3615
FDN
844 accept_info = knet_h->knet_transport_fd_tracker[sockfd].data;
845 info = accept_info->link_info;
e3e37ffd 846
f66ebfd6
FDN
847 /*
848 * clear all links using this accepted socket as
849 * outbound dynamically connected socket
850 */
851
852 for (host = knet_h->host_head; host != NULL; host = host->next) {
853 for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
854 if ((host->link[link_idx].dynamic == KNET_LINK_DYNIP) &&
855 (host->link[link_idx].outsock == sockfd)) {
856 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Found dynamic connection on host %d link %d (%d)",
857 host->host_id, link_idx, sockfd);
858 host->link[link_idx].status.dynconnected = 0;
859 host->link[link_idx].transport_connected = 0;
860 host->link[link_idx].outsock = 0;
861 memset(&host->link[link_idx].dst_addr, 0, sizeof(struct sockaddr_storage));
862 }
863 }
864 }
865
82d1d36e
FDN
866 for (i=0; i<MAX_ACCEPTED_SOCKS; i++) {
867 if (sockfd == info->accepted_socks[i]) {
868 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Closing accepted socket %d", sockfd);
869 _set_fd_tracker(knet_h, sockfd, KNET_MAX_TRANSPORTS, SCTP_NO_LINK_INFO, NULL);
870 info->accepted_socks[i] = -1;
d56e3615 871 free(accept_info);
82d1d36e 872 close(sockfd);
ded574d1 873 break; /* Keeps covscan happy */
82d1d36e
FDN
874 }
875 }
e3e37ffd
CC
876}
877
82d1d36e 878static void *_sctp_listen_thread(void *data)
e3e37ffd 879{
82d1d36e
FDN
880 int savederrno;
881 int i, nev;
882 knet_handle_t knet_h = (knet_handle_t) data;
883 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
884 struct epoll_event events[KNET_EPOLL_MAX_EVENTS];
e3e37ffd 885
6394d892 886 set_thread_status(knet_h, KNET_THREAD_SCTP_LISTEN, KNET_THREAD_STARTED);
aed6b5db 887
82d1d36e 888 while (!shutdown_in_progress(knet_h)) {
aed6b5db
FDN
889 nev = epoll_wait(handle_info->listen_epollfd, events, KNET_EPOLL_MAX_EVENTS, KNET_THREADS_TIMERES / 1000);
890
891 /*
892 * we use timeout to detect if thread is shutting down
893 */
894 if (nev == 0) {
895 continue;
896 }
e3e37ffd 897
82d1d36e
FDN
898 if (nev < 0) {
899 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP listen handler EPOLL ERROR: %s",
900 strerror(errno));
901 continue;
902 }
e3e37ffd 903
1dfc8220 904 savederrno = get_global_wrlock(knet_h);
82d1d36e
FDN
905 if (savederrno) {
906 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to get write lock: %s",
907 strerror(savederrno));
908 continue;
909 }
910 /*
911 * Sort out which FD has an incoming connection
912 */
913 for (i = 0; i < nev; i++) {
914 if (events[i].data.fd == handle_info->listensockfd[0]) {
915 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received notification from rx_error for listener/accepted socket");
916 _handle_listen_sctp_errors(knet_h);
917 } else {
918 if (_is_valid_fd(knet_h, events[i].data.fd) == 1) {
919 _handle_incoming_sctp(knet_h, events[i].data.fd);
920 } else {
921 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Received listen notification from invalid socket");
922 }
923 }
e3e37ffd 924
82d1d36e
FDN
925 }
926 pthread_rwlock_unlock(&knet_h->global_rwlock);
e3e37ffd 927 }
aed6b5db
FDN
928
929 set_thread_status(knet_h, KNET_THREAD_SCTP_LISTEN, KNET_THREAD_STOPPED);
930
82d1d36e 931 return NULL;
e3e37ffd
CC
932}
933
82d1d36e
FDN
934/*
935 * sctp_link_listener_start/stop are called in global write lock
936 * context from set_config and clear_config.
937 */
8a142f48 938static sctp_listen_link_info_t *sctp_link_listener_start(knet_handle_t knet_h, struct knet_link *kn_link)
e3e37ffd 939{
82d1d36e
FDN
940 int err = 0, savederrno = 0;
941 int listen_sock = -1;
e3e37ffd 942 struct epoll_event ev;
82d1d36e
FDN
943 sctp_listen_link_info_t *info = NULL;
944 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
945
946 /*
947 * Only allocate a new listener if src address is different
948 */
949 knet_list_for_each_entry(info, &handle_info->listen_links_list, list) {
8a142f48 950 if (memcmp(&info->src_address, &kn_link->src_addr, sizeof(struct sockaddr_storage)) == 0) {
6373dd23 951 if ((check_add(knet_h, info->listen_sock, KNET_TRANSPORT_SCTP, -1,
9a5babce 952 &kn_link->dst_addr, &kn_link->dst_addr, CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != EEXIST)) {
d2333aab
FDN
953 return NULL;
954 }
82d1d36e
FDN
955 return info;
956 }
957 }
e3e37ffd 958
82d1d36e
FDN
959 info = malloc(sizeof(sctp_listen_link_info_t));
960 if (!info) {
961 err = -1;
962 goto exit_error;
963 }
964
965 memset(info, 0, sizeof(sctp_listen_link_info_t));
966
967 memset(info->accepted_socks, -1, sizeof(info->accepted_socks));
535a4bf7 968 memmove(&info->src_address, &kn_link->src_addr, sizeof(struct sockaddr_storage));
e3e37ffd 969
8a142f48 970 listen_sock = socket(kn_link->src_addr.ss_family, SOCK_STREAM, IPPROTO_SCTP);
e3e37ffd
CC
971 if (listen_sock < 0) {
972 savederrno = errno;
973 err = -1;
815929bf 974 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to create listener socket: %s",
e3e37ffd
CC
975 strerror(savederrno));
976 goto exit_error;
977 }
978
c58507f9 979 if (_configure_sctp_socket(knet_h, listen_sock, &kn_link->src_addr, kn_link->flags, "SCTP listener") < 0) {
82d1d36e
FDN
980 savederrno = errno;
981 err = -1;
e3e37ffd
CC
982 goto exit_error;
983 }
984
8a142f48 985 if (bind(listen_sock, (struct sockaddr *)&kn_link->src_addr, sockaddr_len(&kn_link->src_addr)) < 0) {
e3e37ffd
CC
986 savederrno = errno;
987 err = -1;
815929bf 988 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to bind listener socket: %s",
e3e37ffd
CC
989 strerror(savederrno));
990 goto exit_error;
991 }
992
993 if (listen(listen_sock, 5) < 0) {
994 savederrno = errno;
995 err = -1;
815929bf 996 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to listen on listener socket: %s",
e3e37ffd
CC
997 strerror(savederrno));
998 goto exit_error;
999 }
1000
d56e3615 1001 if (_set_fd_tracker(knet_h, listen_sock, KNET_TRANSPORT_SCTP, SCTP_LISTENER_LINK_INFO, info) < 0) {
82d1d36e
FDN
1002 savederrno = errno;
1003 err = -1;
1004 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set fd tracker: %s",
1005 strerror(savederrno));
1006 goto exit_error;
1007 }
1008
6373dd23 1009 if ((check_add(knet_h, listen_sock, KNET_TRANSPORT_SCTP, -1,
9a5babce 1010 &kn_link->dst_addr, &kn_link->dst_addr, CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != EEXIST)) {
d2333aab
FDN
1011 savederrno = errno;
1012 err = -1;
1013 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to configure default access lists: %s",
1014 strerror(savederrno));
1015 goto exit_error;
1016 }
1017
e3e37ffd
CC
1018 memset(&ev, 0, sizeof(struct epoll_event));
1019 ev.events = EPOLLIN;
82d1d36e 1020 ev.data.fd = listen_sock;
e3e37ffd
CC
1021 if (epoll_ctl(handle_info->listen_epollfd, EPOLL_CTL_ADD, listen_sock, &ev)) {
1022 savederrno = errno;
1023 err = -1;
815929bf 1024 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to add listener to epoll pool: %s",
e3e37ffd
CC
1025 strerror(savederrno));
1026 goto exit_error;
1027 }
82d1d36e
FDN
1028 info->on_listener_epoll = 1;
1029
e3e37ffd 1030 info->listen_sock = listen_sock;
82d1d36e 1031 knet_list_add(&info->list, &handle_info->listen_links_list);
b715c049 1032
8a142f48 1033 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Listening on fd %d for %s:%s", listen_sock, kn_link->status.src_ipaddr, kn_link->status.src_port);
b715c049 1034
82d1d36e
FDN
1035exit_error:
1036 if (err) {
021e57d3 1037 if ((info) && (info->on_listener_epoll)) {
82d1d36e
FDN
1038 epoll_ctl(handle_info->listen_epollfd, EPOLL_CTL_DEL, listen_sock, &ev);
1039 }
1040 if (listen_sock >= 0) {
95c6335c 1041 check_rmall(knet_h, listen_sock, KNET_TRANSPORT_SCTP);
82d1d36e
FDN
1042 close(listen_sock);
1043 }
1044 if (info) {
1045 free(info);
1046 info = NULL;
1047 }
1048 }
1049 errno = savederrno;
1050 return info;
1051}
1052
8a142f48 1053static int sctp_link_listener_stop(knet_handle_t knet_h, struct knet_link *kn_link)
82d1d36e
FDN
1054{
1055 int err = 0, savederrno = 0;
1056 int found = 0, i;
1057 struct knet_host *host;
1058 int link_idx;
1059 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
8a142f48 1060 sctp_connect_link_info_t *this_link_info = kn_link->transport_link;
82d1d36e
FDN
1061 sctp_listen_link_info_t *info = this_link_info->listener;
1062 sctp_connect_link_info_t *link_info;
1063 struct epoll_event ev;
1064
1065 for (host = knet_h->host_head; host != NULL; host = host->next) {
1066 for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
8a142f48 1067 if (&host->link[link_idx] == kn_link)
82d1d36e
FDN
1068 continue;
1069
1070 link_info = host->link[link_idx].transport_link;
1071 if ((link_info) &&
a9ca6afa 1072 (link_info->listener == info)) {
82d1d36e
FDN
1073 found = 1;
1074 break;
1075 }
1076 }
1077 }
1078
9a5babce
FDN
1079 if ((check_rm(knet_h, info->listen_sock, KNET_TRANSPORT_SCTP,
1080 &kn_link->dst_addr, &kn_link->dst_addr, CHECK_TYPE_ADDRESS, CHECK_ACCEPT) < 0) && (errno != ENOENT)) {
d2333aab
FDN
1081 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove default access lists for %d", info->listen_sock);
1082 }
1083
82d1d36e
FDN
1084 if (found) {
1085 this_link_info->listener = NULL;
1086 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP listener socket %d still in use", info->listen_sock);
1087 savederrno = EBUSY;
1088 err = -1;
1089 goto exit_error;
1090 }
1091
1092 if (info->on_listener_epoll) {
1093 memset(&ev, 0, sizeof(struct epoll_event));
1094 ev.events = EPOLLIN;
1095 ev.data.fd = info->listen_sock;
1096 if (epoll_ctl(handle_info->listen_epollfd, EPOLL_CTL_DEL, info->listen_sock, &ev)) {
1097 savederrno = errno;
1098 err = -1;
1099 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove listener to epoll pool: %s",
1100 strerror(savederrno));
1101 goto exit_error;
1102 }
1103 info->on_listener_epoll = 0;
1104 }
1105
1106 if (_set_fd_tracker(knet_h, info->listen_sock, KNET_MAX_TRANSPORTS, SCTP_NO_LINK_INFO, NULL) < 0) {
1107 savederrno = errno;
1108 err = -1;
1109 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set fd tracker: %s",
1110 strerror(savederrno));
1111 goto exit_error;
1112 }
1113
0cb8e8ba 1114 check_rmall(knet_h, info->listen_sock, KNET_TRANSPORT_SCTP);
d2333aab 1115
82d1d36e
FDN
1116 close(info->listen_sock);
1117
1118 for (i=0; i< MAX_ACCEPTED_SOCKS; i++) {
1119 if (info->accepted_socks[i] > -1) {
1120 memset(&ev, 0, sizeof(struct epoll_event));
1121 ev.events = EPOLLIN;
1122 ev.data.fd = info->accepted_socks[i];
1123 if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, info->accepted_socks[i], &ev)) {
1124 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove EOFed socket from epoll pool: %s",
1125 strerror(errno));
1126 }
1127 info->on_rx_epoll = 0;
d56e3615 1128 free(knet_h->knet_transport_fd_tracker[info->accepted_socks[i]].data);
82d1d36e
FDN
1129 close(info->accepted_socks[i]);
1130 if (_set_fd_tracker(knet_h, info->accepted_socks[i], KNET_MAX_TRANSPORTS, SCTP_NO_LINK_INFO, NULL) < 0) {
1131 savederrno = errno;
1132 err = -1;
1133 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set fd tracker: %s",
1134 strerror(savederrno));
1135 goto exit_error;
1136 }
1137 info->accepted_socks[i] = -1;
1138 }
1139 }
1140
1141 knet_list_del(&info->list);
1142 free(info);
1143 this_link_info->listener = NULL;
e3e37ffd
CC
1144
1145exit_error:
1146 errno = savederrno;
1147 return err;
1148}
1149
82d1d36e
FDN
1150/*
1151 * Links config/clear. Both called with global wrlock from link_set_config/clear_config
1152 */
4ac6704d 1153int sctp_transport_link_set_config(knet_handle_t knet_h, struct knet_link *kn_link)
e3e37ffd 1154{
82d1d36e
FDN
1155 int savederrno = 0, err = 0;
1156 sctp_connect_link_info_t *info;
1157 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
e3e37ffd 1158
82d1d36e 1159 info = malloc(sizeof(sctp_connect_link_info_t));
e3e37ffd 1160 if (!info) {
82d1d36e 1161 goto exit_error;
e3e37ffd 1162 }
82d1d36e
FDN
1163
1164 memset(info, 0, sizeof(sctp_connect_link_info_t));
1165
8a142f48
FDN
1166 kn_link->transport_link = info;
1167 info->link = kn_link;
e3e37ffd 1168
535a4bf7 1169 memmove(&info->dst_address, &kn_link->dst_addr, sizeof(struct sockaddr_storage));
82d1d36e
FDN
1170 info->on_connected_epoll = 0;
1171 info->connect_sock = -1;
1172
8a142f48 1173 info->listener = sctp_link_listener_start(knet_h, kn_link);
82d1d36e
FDN
1174 if (!info->listener) {
1175 savederrno = errno;
1176 err = -1;
1177 goto exit_error;
e3e37ffd
CC
1178 }
1179
8a142f48
FDN
1180 if (kn_link->dynamic == KNET_LINK_STATIC) {
1181 if (_create_connect_socket(knet_h, kn_link) < 0) {
f66ebfd6
FDN
1182 savederrno = errno;
1183 err = -1;
1184 goto exit_error;
1185 }
8a142f48 1186 kn_link->outsock = info->connect_sock;
e3e37ffd
CC
1187 }
1188
82d1d36e 1189 knet_list_add(&info->list, &handle_info->connect_links_list);
e3e37ffd 1190
e3e37ffd 1191exit_error:
82d1d36e
FDN
1192 if (err) {
1193 if (info) {
1194 if (info->connect_sock) {
1195 close(info->connect_sock);
1196 }
1197 if (info->listener) {
8a142f48 1198 sctp_link_listener_stop(knet_h, kn_link);
82d1d36e 1199 }
8a142f48 1200 kn_link->transport_link = NULL;
82d1d36e
FDN
1201 free(info);
1202 }
1203 }
e3e37ffd
CC
1204 errno = savederrno;
1205 return err;
1206}
1207
82d1d36e
FDN
1208/*
1209 * called with global wrlock
82d1d36e 1210 */
4ac6704d 1211int sctp_transport_link_clear_config(knet_handle_t knet_h, struct knet_link *kn_link)
e3e37ffd 1212{
82d1d36e
FDN
1213 int err = 0, savederrno = 0;
1214 sctp_connect_link_info_t *info;
d26576a8
CC
1215 struct epoll_event ev;
1216
8a142f48 1217 if (!kn_link) {
82d1d36e
FDN
1218 errno = EINVAL;
1219 return -1;
d26576a8 1220 }
82d1d36e 1221
8a142f48 1222 info = kn_link->transport_link;
82d1d36e
FDN
1223
1224 if (!info) {
1225 errno = EINVAL;
1226 return -1;
d26576a8 1227 }
e3e37ffd 1228
8a142f48 1229 if ((sctp_link_listener_stop(knet_h, kn_link) <0) && (errno != EBUSY)) {
82d1d36e
FDN
1230 savederrno = errno;
1231 err = -1;
1232 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove listener trasport: %s",
1233 strerror(savederrno));
1234 goto exit_error;
1235 }
1236
1237 if (info->on_rx_epoll) {
1238 memset(&ev, 0, sizeof(struct epoll_event));
1239 ev.events = EPOLLIN;
1240 ev.data.fd = info->connect_sock;
1241 if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, info->connect_sock, &ev)) {
1242 savederrno = errno;
1243 err = -1;
1244 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to remove connected socket from epoll pool: %s",
1245 strerror(savederrno));
1246 goto exit_error;
e3e37ffd 1247 }
82d1d36e
FDN
1248 info->on_rx_epoll = 0;
1249 }
1250
8a142f48 1251 if (_close_connect_socket(knet_h, kn_link) < 0) {
82d1d36e
FDN
1252 savederrno = errno;
1253 err = -1;
1254 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to close connected socket: %s",
1255 strerror(savederrno));
1256 goto exit_error;
e3e37ffd
CC
1257 }
1258
b715c049 1259 knet_list_del(&info->list);
e3e37ffd 1260
82d1d36e 1261 free(info);
8a142f48 1262 kn_link->transport_link = NULL;
e3e37ffd 1263
82d1d36e
FDN
1264exit_error:
1265 errno = savederrno;
1266 return err;
e3e37ffd
CC
1267}
1268
82d1d36e
FDN
1269/*
1270 * transport_free and transport_init are
1271 * called only from knet_handle_new and knet_handle_free.
1272 * all resources (hosts/links) should have been already freed at this point
1273 * and they are called in a write locked context, hence they
1274 * don't need their own locking.
1275 */
1276
4ac6704d 1277int sctp_transport_free(knet_handle_t knet_h)
e3e37ffd 1278{
82d1d36e
FDN
1279 sctp_handle_info_t *handle_info;
1280 void *thread_status;
1281 struct epoll_event ev;
e3e37ffd 1282
82d1d36e
FDN
1283 if (!knet_h->transports[KNET_TRANSPORT_SCTP]) {
1284 errno = EINVAL;
1285 return -1;
1286 }
1287
1288 handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
1289
1290 /*
1291 * keep it here while we debug list usage and such
1292 */
1293 if (!knet_list_empty(&handle_info->listen_links_list)) {
1294 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Internal error. listen links list is not empty");
1295 }
1296 if (!knet_list_empty(&handle_info->connect_links_list)) {
1297 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Internal error. connect links list is not empty");
1298 }
1299
1300 if (handle_info->listen_thread) {
1301 pthread_cancel(handle_info->listen_thread);
1302 pthread_join(handle_info->listen_thread, &thread_status);
1303 }
1304
1305 if (handle_info->connect_thread) {
1306 pthread_cancel(handle_info->connect_thread);
1307 pthread_join(handle_info->connect_thread, &thread_status);
e3e37ffd 1308 }
82d1d36e
FDN
1309
1310 if (handle_info->listensockfd[0] >= 0) {
1311 memset(&ev, 0, sizeof(struct epoll_event));
1312 ev.events = EPOLLIN;
1313 ev.data.fd = handle_info->listensockfd[0];
1314 epoll_ctl(handle_info->listen_epollfd, EPOLL_CTL_DEL, handle_info->listensockfd[0], &ev);
1315 }
1316
1317 if (handle_info->connectsockfd[0] >= 0) {
1318 memset(&ev, 0, sizeof(struct epoll_event));
1319 ev.events = EPOLLIN;
1320 ev.data.fd = handle_info->connectsockfd[0];
1321 epoll_ctl(handle_info->connect_epollfd, EPOLL_CTL_DEL, handle_info->connectsockfd[0], &ev);
1322 }
1323
1324 _close_socketpair(knet_h, handle_info->connectsockfd);
1325 _close_socketpair(knet_h, handle_info->listensockfd);
1326
1327 if (handle_info->listen_epollfd >= 0) {
1328 close(handle_info->listen_epollfd);
1329 }
1330
1331 if (handle_info->connect_epollfd >= 0) {
1332 close(handle_info->connect_epollfd);
1333 }
1334
57ebf58c 1335 free(handle_info->event_subscribe_buffer);
82d1d36e
FDN
1336 free(handle_info);
1337 knet_h->transports[KNET_TRANSPORT_SCTP] = NULL;
1338
1339 return 0;
e3e37ffd
CC
1340}
1341
57ebf58c
FW
1342static int _sctp_subscribe_init(knet_handle_t knet_h)
1343{
1344 int test_socket, savederrno;
1345 sctp_handle_info_t *handle_info = knet_h->transports[KNET_TRANSPORT_SCTP];
1346 char dummy_events[100];
1347 struct sctp_event_subscribe *events;
1348 /* Below we set the first 6 fields of this expanding struct.
1349 * SCTP_EVENTS is deprecated, but SCTP_EVENT is not available
1350 * on Linux; on the other hand, FreeBSD and old Linux does not
1351 * accept small transfers, so we can't simply use this minimum
1352 * everywhere. Thus we query and store the native size. */
1353 const unsigned int subscribe_min = 6;
1354
1355 test_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
1356 if (test_socket < 0) {
276499a1
FW
1357 if (errno == EPROTONOSUPPORT) {
1358 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "SCTP not supported, skipping initialization");
1359 return 0;
1360 }
57ebf58c
FW
1361 savederrno = errno;
1362 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to create test socket: %s",
1363 strerror(savederrno));
1364 return savederrno;
1365 }
1366 handle_info->event_subscribe_kernel_size = sizeof dummy_events;
1367 if (getsockopt(test_socket, IPPROTO_SCTP, SCTP_EVENTS, &dummy_events,
1368 &handle_info->event_subscribe_kernel_size)) {
1369 close(test_socket);
1370 savederrno = errno;
1371 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to query kernel size of struct sctp_event_subscribe: %s",
1372 strerror(savederrno));
1373 return savederrno;
1374 }
1375 close(test_socket);
1376 if (handle_info->event_subscribe_kernel_size < subscribe_min) {
1377 savederrno = ERANGE;
1378 log_err(knet_h, KNET_SUB_TRANSP_SCTP,
1379 "No kernel support for the necessary notifications: struct sctp_event_subscribe is %u bytes, %u needed",
1380 handle_info->event_subscribe_kernel_size, subscribe_min);
1381 return savederrno;
1382 }
1383 events = malloc(handle_info->event_subscribe_kernel_size);
1384 if (!events) {
1385 savederrno = errno;
1386 log_err(knet_h, KNET_SUB_TRANSP_SCTP,
1387 "Failed to allocate event subscribe buffer: %s", strerror(savederrno));
1388 return savederrno;
1389 }
1390 memset(events, 0, handle_info->event_subscribe_kernel_size);
1391 events->sctp_data_io_event = 1;
1392 events->sctp_association_event = 1;
1393 events->sctp_address_event = 1;
1394 events->sctp_send_failure_event = 1;
1395 events->sctp_peer_error_event = 1;
1396 events->sctp_shutdown_event = 1;
1397 handle_info->event_subscribe_buffer = (char *)events;
1398 log_debug(knet_h, KNET_SUB_TRANSP_SCTP, "Size of struct sctp_event_subscribe is %u in kernel, %zu in user space",
1399 handle_info->event_subscribe_kernel_size, sizeof(struct sctp_event_subscribe));
1400 return 0;
1401}
1402
4ac6704d 1403int sctp_transport_init(knet_handle_t knet_h)
e3e37ffd 1404{
82d1d36e
FDN
1405 int err = 0, savederrno = 0;
1406 sctp_handle_info_t *handle_info;
1407 struct epoll_event ev;
e3e37ffd 1408
82d1d36e
FDN
1409 if (knet_h->transports[KNET_TRANSPORT_SCTP]) {
1410 errno = EEXIST;
1411 return -1;
1412 }
1413
1414 handle_info = malloc(sizeof(sctp_handle_info_t));
1415 if (!handle_info) {
1416 return -1;
1417 }
1418
1419 memset(handle_info, 0,sizeof(sctp_handle_info_t));
1420
1421 knet_h->transports[KNET_TRANSPORT_SCTP] = handle_info;
1422
57ebf58c
FW
1423 savederrno = _sctp_subscribe_init(knet_h);
1424 if (savederrno) {
1425 err = -1;
1426 goto exit_fail;
1427 }
1428
82d1d36e
FDN
1429 knet_list_init(&handle_info->listen_links_list);
1430 knet_list_init(&handle_info->connect_links_list);
1431
1432 handle_info->listen_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS + 1);
d14d75d2
FW
1433 if (handle_info->listen_epollfd < 0) {
1434 savederrno = errno;
82d1d36e 1435 err = -1;
d14d75d2
FW
1436 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to create epoll listen fd: %s",
1437 strerror(savederrno));
1438 goto exit_fail;
82d1d36e
FDN
1439 }
1440
1441 if (_fdset_cloexec(handle_info->listen_epollfd)) {
1442 savederrno = errno;
1443 err = -1;
1444 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set CLOEXEC on listen_epollfd: %s",
1445 strerror(savederrno));
1446 goto exit_fail;
1447 }
1448
1449 handle_info->connect_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS + 1);
1450 if (handle_info->connect_epollfd < 0) {
1451 savederrno = errno;
1452 err = -1;
1453 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to create epoll connect fd: %s",
1454 strerror(savederrno));
1455 goto exit_fail;
1456 }
1457
1458 if (_fdset_cloexec(handle_info->connect_epollfd)) {
1459 savederrno = errno;
1460 err = -1;
1461 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to set CLOEXEC on connect_epollfd: %s",
1462 strerror(savederrno));
1463 goto exit_fail;
1464 }
e3e37ffd 1465
82d1d36e
FDN
1466 if (_init_socketpair(knet_h, handle_info->connectsockfd) < 0) {
1467 savederrno = errno;
1468 err = -1;
1469 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to init connect socketpair: %s",
1470 strerror(savederrno));
1471 goto exit_fail;
1472 }
e3e37ffd 1473
82d1d36e
FDN
1474 memset(&ev, 0, sizeof(struct epoll_event));
1475 ev.events = EPOLLIN;
1476 ev.data.fd = handle_info->connectsockfd[0];
1477 if (epoll_ctl(handle_info->connect_epollfd, EPOLL_CTL_ADD, handle_info->connectsockfd[0], &ev)) {
1478 savederrno = errno;
1479 err = -1;
1480 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to add connectsockfd[0] to connect epoll pool: %s",
1481 strerror(savederrno));
1482 goto exit_fail;
1483 }
1484
1485 if (_init_socketpair(knet_h, handle_info->listensockfd) < 0) {
1486 savederrno = errno;
1487 err = -1;
1488 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to init listen socketpair: %s",
1489 strerror(savederrno));
1490 goto exit_fail;
1491 }
1492
1493 memset(&ev, 0, sizeof(struct epoll_event));
1494 ev.events = EPOLLIN;
1495 ev.data.fd = handle_info->listensockfd[0];
1496 if (epoll_ctl(handle_info->listen_epollfd, EPOLL_CTL_ADD, handle_info->listensockfd[0], &ev)) {
1497 savederrno = errno;
1498 err = -1;
1499 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to add listensockfd[0] to listen epoll pool: %s",
1500 strerror(savederrno));
1501 goto exit_fail;
1502 }
1503
1504 /*
1505 * Start connect & listener threads
1506 */
6394d892 1507 set_thread_status(knet_h, KNET_THREAD_SCTP_LISTEN, KNET_THREAD_REGISTERED);
82d1d36e 1508 savederrno = pthread_create(&handle_info->listen_thread, 0, _sctp_listen_thread, (void *) knet_h);
d56e3615 1509 if (savederrno) {
82d1d36e 1510 err = -1;
d56e3615
FDN
1511 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to start sctp listen thread: %s",
1512 strerror(savederrno));
1513 goto exit_fail;
1514 }
82d1d36e 1515
6394d892 1516 set_thread_status(knet_h, KNET_THREAD_SCTP_CONN, KNET_THREAD_REGISTERED);
82d1d36e 1517 savederrno = pthread_create(&handle_info->connect_thread, 0, _sctp_connect_thread, (void *) knet_h);
d56e3615 1518 if (savederrno) {
82d1d36e 1519 err = -1;
d56e3615
FDN
1520 log_err(knet_h, KNET_SUB_TRANSP_SCTP, "Unable to start sctp connect thread: %s",
1521 strerror(savederrno));
1522 goto exit_fail;
1523 }
82d1d36e
FDN
1524
1525exit_fail:
1526 if (err < 0) {
1527 sctp_transport_free(knet_h);
1528 }
1529 errno = savederrno;
1530 return err;
1531}
1532
4ac6704d 1533int sctp_transport_link_dyn_connect(knet_handle_t knet_h, int sockfd, struct knet_link *kn_link)
f66ebfd6
FDN
1534{
1535 kn_link->outsock = sockfd;
1536 kn_link->status.dynconnected = 1;
1537 kn_link->transport_connected = 1;
1538 return 0;
1539}
2eb0040c
FDN
1540
1541int sctp_transport_link_get_acl_fd(knet_handle_t knet_h, struct knet_link *kn_link)
1542{
1543 sctp_connect_link_info_t *this_link_info = kn_link->transport_link;
1544 sctp_listen_link_info_t *info = this_link_info->listener;
1545 return info->listen_sock;
1546}
3c62178c 1547#endif