34 #include <netinet/in.h> 35 #include <netinet/tcp.h> 47 if (flextcp_fd_init() != 0) {
48 fprintf(stderr,
"flextcp_fd_init failed\n");
53 fprintf(stderr,
"flextcp_init failed\n");
60 int tas_socket(
int domain,
int type,
int protocol)
64 int nonblock = 0, cloexec = 0;
66 if ((type & SOCK_NONBLOCK) == SOCK_NONBLOCK) {
69 if ((type & SOCK_CLOEXEC) == SOCK_CLOEXEC) {
73 type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
74 if (domain != AF_INET || type != SOCK_STREAM) {
79 if ((fd = flextcp_fd_salloc(&s)) < 0) {
83 s->type = SOCK_SOCKET;
85 flextcp_epoll_sockinit(s);
88 s->flags |= SOF_NONBLOCK;
91 s->flags |= SOF_CLOEXEC;
94 flextcp_fd_srelease(fd, s);
98 int tas_close(
int sockfd)
103 if (flextcp_fd_slookup(sockfd, &s) == 0) {
104 flextcp_fd_close(sockfd);
107 if (s->refcnt != 0) {
108 flextcp_fd_srelease(sockfd, s);
113 }
else if (flextcp_fd_elookup(sockfd, &ep) == 0) {
114 flextcp_fd_close(sockfd);
117 if (ep->refcnt != 0) {
118 flextcp_fd_erelease(sockfd, ep);
123 flextcp_epoll_destroy(ep);
132 int tas_sock_close(
struct socket *s)
136 assert(s->refcnt == 0);
139 flextcp_epoll_sockclose(s);
141 ctx = flextcp_sockctx_get();
142 if (s->type == SOCK_CONNECTION) {
144 }
else if (s->type == SOCK_SOCKET) {
147 fprintf(stderr,
"TODO: close for non-connections. (leak)\n");
156 s->data.connection.status = SOC_CLOSED;
158 if ((s->data.connection.st_flags & CSTF_TXCLOSED_ACK) &&
159 (s->data.connection.st_flags & CSTF_RXCLOSED))
162 flextcp_sockclose_finish(ctx, s);
163 }
else if (!(s->data.connection.st_flags & CSTF_TXCLOSED)) {
165 fprintf(stderr,
"conn_close: flextcp_connection_tx_close failed\n");
169 s->data.connection.st_flags |= CSTF_TXCLOSED;
184 fprintf(stderr,
"close: flextcp_connection_close failed (unhandled, " 185 "results in leak)\n");
191 int tas_shutdown(
int sockfd,
int how)
197 if (flextcp_fd_slookup(sockfd, &s) != 0) {
204 if (s->type != SOCK_CONNECTION) {
211 if (s->data.connection.status != SOC_CONNECTED) {
217 if (how != SHUT_WR) {
218 fprintf(stderr,
"flextcp shutdown: TODO how != SHUT_WR\n");
225 if ((s->data.connection.st_flags & CSTF_TXCLOSED) == CSTF_TXCLOSED) {
229 ctx = flextcp_sockctx_get();
237 s->data.connection.st_flags |= CSTF_TXCLOSED;
240 flextcp_fd_srelease(sockfd, s);
244 int tas_bind(
int sockfd,
const struct sockaddr *addr, socklen_t addrlen)
249 if (flextcp_fd_slookup(sockfd, &s) != 0) {
254 if (addrlen !=
sizeof(s->addr) || addr->sa_family != AF_INET) {
260 memcpy(&s->addr, addr,
sizeof(s->addr));
261 s->flags |= SOF_BOUND;
264 flextcp_fd_srelease(sockfd, s);
268 int tas_connect(
int sockfd,
const struct sockaddr *addr, socklen_t addrlen)
272 struct sockaddr_in *sin = (
struct sockaddr_in *) addr;
275 if (flextcp_fd_slookup(sockfd, &s) != 0) {
281 if (s->type == SOCK_LISTENER ||
282 (s->type == SOCK_CONNECTION && s->data.connection.status == SOC_CONNECTED))
290 if (s->type == SOCK_CONNECTION && s->data.connection.status == SOC_CONNECTING) {
297 if (addrlen !=
sizeof(s->addr) || addr->sa_family != AF_INET) {
304 ctx = flextcp_sockctx_get();
306 ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port)))
309 errno = ECONNREFUSED;
314 assert(s->type == SOCK_CONNECTION || s->type == SOCK_SOCKET);
315 s->type = SOCK_CONNECTION;
316 s->data.connection.status = SOC_CONNECTING;
317 s->data.connection.listener = NULL;
318 s->data.connection.rx_len_1 = 0;
319 s->data.connection.rx_len_2 = 0;
320 s->data.connection.ctx = ctx;
323 if ((s->flags & SOF_NONBLOCK) == SOF_NONBLOCK) {
336 flextcp_sockctx_poll(ctx);
338 }
while (s->data.connection.status == SOC_CONNECTING);
341 if (s->data.connection.status == SOC_FAILED) {
343 errno = ECONNREFUSED;
349 flextcp_fd_srelease(sockfd, s);
353 int tas_listen(
int sockfd,
int backlog)
360 if (flextcp_fd_slookup(sockfd, &s) != 0) {
366 if (s->type != SOCK_SOCKET) {
374 if ((s->flags & SOF_BOUND) != SOF_BOUND) {
381 if ((s->flags & SOF_REUSEPORT) == SOF_REUSEPORT) {
382 flags |= FLEXTCP_LISTEN_REUSEPORT;
391 ctx = flextcp_sockctx_get();
396 errno = ECONNREFUSED;
401 s->type = SOCK_LISTENER;
402 s->data.listener.backlog = backlog;
403 s->data.listener.status = SOL_OPENING;
404 s->data.listener.pending = NULL;
413 flextcp_sockctx_poll(ctx);
415 }
while (s->data.listener.status == SOL_OPENING);
418 if (s->data.listener.status == SOL_FAILED) {
426 flextcp_fd_srelease(sockfd, s);
430 int tas_accept4(
int sockfd,
struct sockaddr *addr, socklen_t *addrlen,
436 int ret = 0, nonblock = 0, cloexec = 0, newfd, block;
438 if (flextcp_fd_slookup(sockfd, &s) != 0) {
444 if ((flags & SOCK_NONBLOCK) == SOCK_NONBLOCK) {
447 if ((flags & SOCK_CLOEXEC) == SOCK_CLOEXEC) {
451 flags &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
459 if (s->type != SOCK_LISTENER) {
465 ctx = flextcp_sockctx_get();
468 for (sp = s->data.listener.pending; sp != NULL; sp = sp->next) {
469 if (sp->ctx == ctx) {
476 if ((sp = malloc(
sizeof(*sp))) == NULL) {
483 if ((newfd = flextcp_fd_salloc(&ns)) < 0) {
489 ns->type = SOCK_CONNECTION;
490 ns->flags = (nonblock ? SOF_NONBLOCK : 0) | (cloexec ? SOF_CLOEXEC : 0);
491 ns->data.connection.status = SOC_CONNECTING;
492 ns->data.connection.listener = s;
493 ns->data.connection.rx_len_1 = 0;
494 ns->data.connection.rx_len_2 = 0;
495 ns->data.connection.ctx = ctx;
504 &ns->data.connection.c) != 0)
510 flextcp_fd_close(newfd);
516 spp = s->data.listener.pending;
518 s->data.listener.pending = sp;
520 while (spp->next != NULL) {
531 if (ns->data.connection.status == SOC_CONNECTING) {
532 flextcp_epoll_clear(s, EPOLLIN);
533 if ((s->flags & SOF_NONBLOCK) == SOF_NONBLOCK) {
537 flextcp_fd_srelease(newfd, ns);
547 flextcp_sockctx_poll(ctx);
551 }
while (ns->data.connection.status == SOC_CONNECTING);
556 assert(ns->data.connection.status == SOC_CONNECTED);
559 if (s->data.listener.pending == sp) {
560 s->data.listener.pending = sp->next;
562 spp = s->data.listener.pending;
564 while (spp->next != sp) {
565 assert(spp->next != NULL);
568 spp->next = sp->next;
571 flextcp_fd_srelease(newfd, ns);
575 int r = tas_getpeername(newfd, addr, addrlen);
581 flextcp_fd_srelease(sockfd, s);
586 int tas_accept(
int sockfd,
struct sockaddr *addr, socklen_t *addrlen)
588 return tas_accept4(sockfd, addr, addrlen, 0);
591 int tas_fcntl(
int sockfd,
int cmd, ...)
598 if (flextcp_fd_slookup(sockfd, &s) != 0) {
608 if ((s->flags & SOF_NONBLOCK) == SOF_NONBLOCK) {
616 iarg = va_arg(arg,
int);
620 if ((iarg & ~(O_NONBLOCK | O_ACCMODE)) != 0) {
621 fprintf(stderr,
"flextcp fcntl: unsupported flags set (%x)\n",
630 if ((iarg & O_NONBLOCK) == 0) {
631 s->flags &= ~SOF_NONBLOCK;
633 s->flags |= SOF_NONBLOCK;
638 if ((s->flags & SOF_CLOEXEC) == SOF_CLOEXEC) {
646 iarg = va_arg(arg,
int);
649 if ((iarg & ~FD_CLOEXEC) != 0) {
650 fprintf(stderr,
"flextcp fcntl: setfd unsupported flag (%x)\n",
657 if ((iarg & FD_CLOEXEC) == FD_CLOEXEC)
658 s->flags |= SOF_CLOEXEC;
660 s->flags &= ~SOF_CLOEXEC;
664 fprintf(stderr,
"flextcp fcntl: unsupported cmd\n");
671 flextcp_fd_srelease(sockfd, s);
675 int tas_getsockopt(
int sockfd,
int level,
int optname,
void *optval,
679 int ret = 0, res, len;
681 if (flextcp_fd_slookup(sockfd, &s) != 0) {
688 if(level == IPPROTO_TCP && optname == TCP_NODELAY) {
692 }
else if(level == SOL_SOCKET &&
693 (optname == SO_RCVBUF || optname == SO_SNDBUF))
697 }
else if (level == SOL_SOCKET && optname == SO_ERROR) {
699 if (s->type == SOCK_LISTENER) {
700 res = (s->data.listener.status == SOL_OPEN ? 0 : EINPROGRESS);
701 }
else if (s->type == SOCK_CONNECTION) {
704 if (s->data.connection.status == SOC_CONNECTING) {
706 flextcp_sockctx_poll(flextcp_sockctx_get());
710 if (s->data.connection.status == SOC_CONNECTED) {
712 }
else if (s->data.connection.status == SOC_CONNECTING) {
722 }
else if (level == SOL_SOCKET && optname == SO_REUSEPORT) {
723 res = !!(s->flags & SOF_REUSEPORT);
724 }
else if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
727 }
else if (level == SOL_SOCKET && optname == SO_KEEPALIVE) {
730 }
else if (level == IPPROTO_TCP && (optname == TCP_KEEPIDLE ||
731 optname == TCP_KEEPINTVL || optname == TCP_KEEPCNT)) {
733 }
else if (level == SOL_SOCKET && optname == SO_LINGER) {
734 fprintf(stderr,
"flextcp getsockopt: SO_LINGER not implemented\n");
740 fprintf(stderr,
"flextcp getsockopt: unknown level optname combination " 741 "(l=%u, o=%u)\n", level, optname);
748 len = MIN(*optlen,
sizeof(res));
749 memcpy(optval, &res, len);
753 flextcp_fd_srelease(sockfd, s);
757 int tas_setsockopt(
int sockfd,
int level,
int optname,
const void *optval,
763 if (flextcp_fd_slookup(sockfd, &s) != 0) {
770 if(level == IPPROTO_TCP && optname == TCP_NODELAY) {
772 if (optlen !=
sizeof(
int)) {
777 }
else if(level == SOL_SOCKET &&
778 (optname == SO_RCVBUF || optname == SO_SNDBUF))
780 if (optlen <
sizeof(
int)) {
787 res = * ((
int *) optval);
788 if (res <= 1024 * 1024) {
795 }
else if (level == SOL_SOCKET && optname == SO_REUSEPORT) {
796 if (optlen !=
sizeof(
int)) {
802 if (*(
int *) optval != 0) {
803 s->flags |= SOF_REUSEPORT;
805 s->flags &= ~SOF_REUSEPORT;
807 }
else if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
809 }
else if (level == SOL_SOCKET && optname == SO_KEEPALIVE) {
811 }
else if (level == SOL_SOCKET && optname == SO_PRIORITY) {
813 }
else if (level == IPPROTO_TCP && (optname == TCP_KEEPIDLE ||
814 optname == TCP_KEEPINTVL || optname == TCP_KEEPCNT)) {
816 }
else if (level == SOL_SOCKET && optname == SO_LINGER) {
817 fprintf(stderr,
"flextcp setsockopt: SO_LINGER not implemented\n");
823 fprintf(stderr,
"flextcp setsockopt: unknown level optname combination " 824 "(l=%u, o=%u)\n", level, optname);
831 flextcp_fd_srelease(sockfd, s);
835 int tas_getsockname(
int sockfd,
struct sockaddr *addr, socklen_t *addrlen)
840 struct sockaddr_in sin;
842 if (flextcp_fd_slookup(sockfd, &s) != 0) {
849 if ((s->flags & SOF_BOUND) == SOF_BOUND) {
851 }
else if (s->type == SOCK_CONNECTION &&
852 s->data.connection.status == SOC_CONNECTED)
854 memset(&sin, 0,
sizeof(sin));
855 sin.sin_family = AF_INET;
857 sin.sin_addr.s_addr = htonl(s->data.connection.c.local_ip);
858 sin.sin_port = htons(s->data.connection.c.local_port);
865 len = MIN(*addrlen,
sizeof(sin));
867 memcpy(addr, &sin, len);
870 flextcp_fd_srelease(sockfd, s);
874 int tas_getpeername(
int sockfd,
struct sockaddr *addr, socklen_t *addrlen)
879 struct sockaddr_in sin;
881 if (flextcp_fd_slookup(sockfd, &s) != 0) {
889 if (s->type != SOCK_CONNECTION ||
890 s->data.connection.status != SOC_CONNECTED)
897 memset(&sin, 0,
sizeof(sin));
898 sin.sin_family = AF_INET;
900 sin.sin_addr.s_addr = htonl(s->data.connection.c.remote_ip);
901 sin.sin_port = htons(s->data.connection.c.remote_port);
903 len = MIN(*addrlen,
sizeof(sin));
905 memcpy(addr, &sin, len);
908 flextcp_fd_srelease(sockfd, s);
912 int tas_move_conn(
int sockfd)
917 if (flextcp_fd_slookup(sockfd, &s) != 0) {
922 ret = tas_sock_move(s);
924 flextcp_fd_srelease(sockfd, s);
928 int tas_sock_move(
struct socket *s)
934 if (s->type != SOCK_CONNECTION ||
935 s->data.connection.status != SOC_CONNECTED)
942 ctx = flextcp_sockctx_get();
943 if (s->data.connection.ctx == ctx) {
947 s->data.connection.move_status = INT_MIN;
960 flextcp_sockctx_poll(ctx);
962 }
while (s->data.connection.move_status == INT_MIN);
963 ret = s->data.connection.move_status;
965 s->data.connection.ctx = ctx;
int flextcp_context_wait(struct flextcp_context *ctx, int timeout_ms)
int tas_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
int flextcp_listen_open(struct flextcp_context *ctx, struct flextcp_listener *lst, uint16_t port, uint32_t backlog, uint32_t flags)
int flextcp_connection_tx_close(struct flextcp_context *ctx, struct flextcp_connection *conn)
int flextcp_connection_close(struct flextcp_context *ctx, struct flextcp_connection *conn)
Public low-level application interface for TAS.
int flextcp_connection_move(struct flextcp_context *ctx, struct flextcp_connection *conn)
int flextcp_connection_open(struct flextcp_context *ctx, struct flextcp_connection *conn, uint32_t dst_ip, uint16_t dst_port)
int flextcp_listen_accept(struct flextcp_context *ctx, struct flextcp_listener *lst, struct flextcp_connection *conn)