diff --git a/README.md b/README.md index 0f0f8b16c..480b2dce3 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,3 @@ This is a userland SCTP stack supporting FreeBSD, Linux, Mac OS X and Windows. See [manual](Manual.md) for more information. -The status of continuous integration testing is available from [grid](http://212.201.121.110:18010/grid) and [waterfall](http://212.201.121.110:18010/waterfall). -If you are only interested in a single branch, just append `?branch=BRANCHNAME` to the URL, for example [waterfall](http://212.201.121.110:18010/waterfall?branch=master). diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index ab4c7fda3..e84dcaf9b 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -83,6 +83,12 @@ set(check_programs test_libmgmt.c test_timer.c tsctp.c + http_client_upcall.c + client_upcall.c + discard_server_upcall.c + echo_server_upcall.c + chargen_server_upcall.c + daytime_server_upcall.c ) foreach (source_file ${check_programs}) diff --git a/programs/chargen_server_upcall.c b/programs/chargen_server_upcall.c new file mode 100644 index 000000000..bb6541115 --- /dev/null +++ b/programs/chargen_server_upcall.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2012-2013 Michael Tuexen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Usage: daytime_server [local_encaps_port] [remote_encaps_port] + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#endif +#include + +#define BUFFERSIZE 10240 +#define PORT 19 + +char buffer[95]; +int done = 0; +int send_done = 0; + +static void +initBuffer() { + int i, j; + for (i = 32, j = 0; i < 126; i++, j++) { + buffer[j] = i; + } +} + +unsigned int signCounter = 0; +static void +handle_upcall(struct socket *sock, void *data, int flgs); + +static void +handle_accept(struct socket *sock, void *data, int flags) +{ + struct socket *conn_sock; + + if (((conn_sock = usrsctp_accept(sock, NULL, NULL)) == NULL) + && (errno != EINPROGRESS)) { + perror("usrsctp_accept"); + return; + } + done = 0; + printf("connection accepted from socket %p\n", (void *)conn_sock); + usrsctp_set_upcall(conn_sock, handle_upcall, NULL); +} + +static void +handle_upcall(struct socket *sock, void *data, int flgs) +{ + int events = usrsctp_get_events(sock); + + if (events & SCTP_EVENT_READ && !send_done) { + char *buf; + struct sctp_recvv_rn rn; + ssize_t n; + struct sockaddr_storage addr; + buf = malloc(BUFFERSIZE); + int flags = 0; + socklen_t len = (socklen_t)sizeof(struct sockaddr_storage); + unsigned int infotype = 0; + socklen_t infolen = sizeof(struct sctp_recvv_rn); + memset(&rn, 0, sizeof(struct sctp_recvv_rn)); + + n = usrsctp_recvv(sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn, + &infolen, &infotype, &flags); + if (n < 0) { + perror("usrsctp_recvv"); + done = 1; + usrsctp_close(sock); + printf("client socket %p closed\n", (void *)sock); + sock = NULL; + return; + } + if (n == 0) { + done = 1; + usrsctp_close(sock); + printf("client socket %p closed\n", (void *)sock); + sock = NULL; + return; + } + if (n > 0) { + if (flags & MSG_NOTIFICATION) { + printf("Notification of length %d received.\n", (int)n); + } else { + printf("data of size %zd received\n", n); + } + } + free(buf); + } + + if ((events & SCTP_EVENT_WRITE) && !done) { + struct sctp_sndinfo snd_info; + snd_info.snd_sid = 0; + snd_info.snd_flags = 0; + snd_info.snd_ppid = 0; + snd_info.snd_context = 0; + snd_info.snd_assoc_id = 0; + if (usrsctp_sendv(sock, buffer, strlen(buffer), NULL, 0, &snd_info, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) { + if (errno != EAGAIN) { + send_done = 1; + usrsctp_close(sock); + printf("client socket %p closed\n", (void *)sock); + return; + } + } + } + + return; +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *listening_socket; + struct sockaddr_in6 addr; + struct sctp_udpencaps encaps; + struct sctp_assoc_value av; + const int on = 1; + + if (argc > 1) { + usrsctp_init(atoi(argv[1]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); +#endif + usrsctp_sysctl_set_sctp_blackhole(2); + + if ((listening_socket = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + } + usrsctp_set_non_blocking(listening_socket, 1); + if (usrsctp_setsockopt(listening_socket, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (const void*)&on, (socklen_t)sizeof(int)) < 0) { + perror("usrsctp_setsockopt SCTP_I_WANT_MAPPED_V4_ADDR"); + } + memset(&av, 0, sizeof(struct sctp_assoc_value)); + av.assoc_id = SCTP_ALL_ASSOC; + av.assoc_value = 47; + + if (usrsctp_setsockopt(listening_socket, IPPROTO_SCTP, SCTP_CONTEXT, (const void*)&av, (socklen_t)sizeof(struct sctp_assoc_value)) < 0) { + perror("usrsctp_setsockopt SCTP_CONTEXT"); + } + if (usrsctp_setsockopt(listening_socket, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(int)) < 0) { + perror("usrsctp_setsockopt SCTP_RECVRCVINFO"); + } + if (argc > 2) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET6; + encaps.sue_port = htons(atoi(argv[2])); + if (usrsctp_setsockopt(listening_socket, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("usrsctp_setsockopt SCTP_REMOTE_UDP_ENCAPS_PORT"); + } + } + + initBuffer(); + + memset((void *)&addr, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(PORT); + addr.sin6_addr = in6addr_any; + if (usrsctp_bind(listening_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) { + perror("usrsctp_bind"); + } + if (usrsctp_listen(listening_socket, 1) < 0) { + perror("usrsctp_listen"); + } + usrsctp_set_upcall(listening_socket, handle_accept, NULL); + + while (1) { +#ifdef _WIN32 + Sleep(1*1000); +#else + sleep(1); +#endif + } + usrsctp_close(listening_socket); + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + return (0); +} diff --git a/programs/client_upcall.c b/programs/client_upcall.c new file mode 100644 index 000000000..2785cd04e --- /dev/null +++ b/programs/client_upcall.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2011-2013 Michael Tuexen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Usage: client remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] + */ + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#ifndef _WIN32 +#include +#include +#include +#else +#include +#endif +#include +#include + +#define BUFFERSIZE (1<<16) + +int done = 0, input_done = 0, connected = 0; + +#ifdef _WIN32 +typedef char* caddr_t; +#endif + +int inputAvailable() +{ + struct timeval tv; + fd_set fds; + tv.tv_sec = 0; + tv.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); + return (FD_ISSET(0, &fds)); +} + +static void +handle_upcall(struct socket *sock, void *arg, int flgs) +{ + int events = usrsctp_get_events(sock); + + if (events & SCTP_EVENT_WRITE && !done && !connected) { + connected = 1; + printf("socket connected\n"); + return; + } + + while (events & SCTP_EVENT_READ && !done && connected) { + struct sctp_recvv_rn rn; + ssize_t n; + struct sockaddr_in addr; + char *buf = calloc(1, BUFFERSIZE); + int flags = 0; + socklen_t len = (socklen_t)sizeof(struct sockaddr_in); + unsigned int infotype = 0; + socklen_t infolen = sizeof(struct sctp_recvv_rn); + memset(&rn, 0, sizeof(struct sctp_recvv_rn)); + n = usrsctp_recvv(sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn, + &infolen, &infotype, &flags); + + if (n > 0) { +#ifdef _WIN32 + _write(_fileno(stdout), buf, (unsigned int)n); +#else + if (write(fileno(stdout), buf, n) < 0) { + perror("write"); + } +#endif + } else if (n == 0) { + done = 1; + input_done = 1; + free(buf); + break; + } else { + perror("\nusrsctp_recvv"); + free (buf); + break; + } + free(buf); + events = usrsctp_get_events(sock); + } + return; +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *sock; + struct sockaddr *addr, *addrs; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + struct sctp_udpencaps encaps; + struct sctpstat stat; + char buffer[200]; + int i, n; + + if (argc > 4) { + usrsctp_init(atoi(argv[4]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); +#endif + usrsctp_sysctl_set_sctp_blackhole(2); + if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + exit(1); + } + + usrsctp_set_non_blocking(sock, 1); + + if (argc > 3) { + memset((void *)&addr6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(atoi(argv[3])); + addr6.sin6_addr = in6addr_any; + if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + perror("bind"); + usrsctp_close(sock); + exit(1); + } + } + if (argc > 5) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET6; + encaps.sue_port = htons(atoi(argv[5])); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("setsockopt"); + usrsctp_close(sock); + exit(1); + } + } + + memset((void *)&addr4, 0, sizeof(struct sockaddr_in)); + memset((void *)&addr6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN_LEN + addr4.sin_len = sizeof(struct sockaddr_in); +#endif +#ifdef HAVE_SIN6_LEN + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr4.sin_family = AF_INET; + addr6.sin6_family = AF_INET6; + addr4.sin_port = htons(atoi(argv[2])); + addr6.sin6_port = htons(atoi(argv[2])); + if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) { + if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + perror("usrsctp_connect"); + } + } else if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) { + if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) { + perror("usrsctp_connect"); + } + } else { + printf("Illegal destination address.\n"); + } + + usrsctp_set_upcall(sock, handle_upcall, NULL); + if ((n = usrsctp_getladdrs(sock, 0, &addrs)) < 0) { + perror("usrsctp_getladdrs"); + } else { + addr = addrs; + printf("Local addresses: "); + for (i = 0; i < n; i++) { + if (i > 0) { + printf("%s", ", "); + } + switch (addr->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin; + char buf[INET_ADDRSTRLEN]; + const char *name; + + sin = (struct sockaddr_in *)addr; + name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); + printf("%s", name); +#ifndef HAVE_SA_LEN + addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in)); +#endif + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6; + char buf[INET6_ADDRSTRLEN]; + const char *name; + + sin6 = (struct sockaddr_in6 *)addr; + name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN); + printf("%s", name); +#ifndef HAVE_SA_LEN + addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6)); +#endif + break; + } + default: + break; + } +#ifdef HAVE_SA_LEN + addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len); +#endif + } + printf(".\n"); + usrsctp_freeladdrs(addrs); + } + if ((n = usrsctp_getpaddrs(sock, 0, &addrs)) < 0) { + perror("usrsctp_getpaddrs"); + } else { + addr = addrs; + printf("Peer addresses: "); + for (i = 0; i < n; i++) { + if (i > 0) { + printf("%s", ", "); + } + switch (addr->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin; + char buf[INET_ADDRSTRLEN]; + const char *name; + + sin = (struct sockaddr_in *)addr; + name = inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); + printf("%s", name); +#ifndef HAVE_SA_LEN + addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in)); +#endif + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6; + char buf[INET6_ADDRSTRLEN]; + const char *name; + + sin6 = (struct sockaddr_in6 *)addr; + name = inet_ntop(AF_INET6, &sin6->sin6_addr, buf, INET6_ADDRSTRLEN); + printf("%s", name); +#ifndef HAVE_SA_LEN + addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6)); +#endif + break; + } + default: + break; + } +#ifdef HAVE_SA_LEN + addr = (struct sockaddr *)((caddr_t)addr + addr->sa_len); +#endif + } + printf(".\n"); + usrsctp_freepaddrs(addrs); + } + while (!done && !input_done) { + if (inputAvailable()) { + if (fgets(buffer, sizeof(buffer), stdin) != NULL) { + buffer[strlen(buffer)] = '\0'; + usrsctp_sendv(sock, buffer, strlen(buffer), NULL, 0, NULL, 0, SCTP_SENDV_NOINFO, 0); + } else { + if (usrsctp_shutdown(sock, SHUT_WR) < 0) { + perror("usrsctp_shutdown"); + } + break; + } + } + } + sleep(1); + usrsctp_close(sock); + + usrsctp_get_stat(&stat); + printf("Number of packets (sent/received): (%u/%u).\n", + stat.sctps_outpackets, stat.sctps_inpackets); + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + printf("Client finished\n"); + return(0); +} diff --git a/programs/daytime_server_upcall.c b/programs/daytime_server_upcall.c new file mode 100644 index 000000000..f2d786b42 --- /dev/null +++ b/programs/daytime_server_upcall.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2012-2013 Michael Tuexen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Usage: daytime_server [local_encaps_port] [remote_encaps_port] + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#endif +#include + +#define DAYTIME_PPID 40 +#define PORT 13 + +static void +handle_accept(struct socket *sock, void *data, int flags) +{ + struct socket *conn_sock; + char buffer[80]; + time_t now; + socklen_t addr_len = 0; + struct sctp_sndinfo sndinfo; + + if (((conn_sock = usrsctp_accept(sock, NULL, &addr_len)) == NULL) + && (errno != EINPROGRESS)) { + perror("usrsctp_accept"); + return; + } + time(&now); +#ifdef _WIN32 + _snprintf(buffer, sizeof(buffer), "%s", ctime(&now)); +#else + snprintf(buffer, sizeof(buffer), "%s", ctime(&now)); +#endif + sndinfo.snd_sid = 0; + sndinfo.snd_flags = 0; + sndinfo.snd_ppid = htonl(DAYTIME_PPID); + sndinfo.snd_context = 0; + sndinfo.snd_assoc_id = 0; + usrsctp_sendv(conn_sock, buffer, strlen(buffer), NULL, 0, (void *)&sndinfo, + (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0); + usrsctp_close(conn_sock); +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *sock; + struct sockaddr_in addr; + struct sctp_udpencaps encaps; + + if (argc > 1) { + usrsctp_init(atoi(argv[1]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); +#endif + usrsctp_sysctl_set_sctp_blackhole(2); + + if ((sock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + } + usrsctp_set_non_blocking(sock, 1); + if (argc > 2) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET; + encaps.sue_port = htons(atoi(argv[2])); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("setsockopt"); + } + } + memset((void *)&addr, 0, sizeof(struct sockaddr_in)); +#ifdef HAVE_SIN_LEN + addr.sin_len = sizeof(struct sockaddr_in); +#endif + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { + perror("usrsctp_bind"); + } + if (usrsctp_listen(sock, 1) < 0) { + perror("usrsctp_listen"); + } + + usrsctp_set_upcall(sock, handle_accept, NULL); + + while (1) { +#ifdef _WIN32 + Sleep(1*1000); +#else + sleep(1); +#endif + } + usrsctp_close(sock); + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + return (0); +} diff --git a/programs/discard_server_upcall.c b/programs/discard_server_upcall.c new file mode 100644 index 000000000..c0c5b8f74 --- /dev/null +++ b/programs/discard_server_upcall.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2011-2013 Michael Tuexen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Usage: discard_server [local_encaps_port] [remote_encaps_port] + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#endif +#include + +#define BUFFERSIZE 10240 +#define PORT 9 + + +static void +handle_upcall(struct socket *sock, void *data, int flgs) +{ + char namebuf[INET6_ADDRSTRLEN]; + const char *name; + uint16_t port; + char *buf; + int events; + + while ((events = usrsctp_get_events(sock)) && (events & SCTP_EVENT_READ)) { + struct sctp_recvv_rn rn; + ssize_t n; + struct sockaddr_storage addr; + buf = malloc(BUFFERSIZE); + int flags = 0; + socklen_t len = (socklen_t)sizeof(struct sockaddr_storage); + unsigned int infotype = 0; + socklen_t infolen = sizeof(struct sctp_recvv_rn); + memset(&rn, 0, sizeof(struct sctp_recvv_rn)); + n = usrsctp_recvv(sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn, + &infolen, &infotype, &flags); + if (n < 0) { + perror("usrsctp_recvv"); + } + if (n > 0) { + if (flags & MSG_NOTIFICATION) { + printf("Notification of length %d received.\n", (int)n); + } else { +/* +#ifdef _WIN32 + _write(_fileno(stdout), buf, (unsigned int)n); +#else + if (write(fileno(stdout), buf, n) < 0) { + perror("write"); + } +#endif +*/ + switch (addr.ss_family) { +#ifdef INET + case AF_INET: { + struct sockaddr_in addr4; + memcpy(&addr4, (struct sockaddr_in *)&addr, sizeof(struct sockaddr_in)); + name = inet_ntop(AF_INET, &addr4.sin_addr, namebuf, INET_ADDRSTRLEN); + port = ntohs(addr4.sin_port); + break; + } +#endif +#ifdef INET6 + case AF_INET6: { + struct sockaddr_in6 addr6; + memcpy(&addr6, (struct sockaddr_in6 *)&addr, sizeof(struct sockaddr_in6)); + name = inet_ntop(AF_INET6, &addr6.sin6_addr, namebuf, INET6_ADDRSTRLEN), + port = ntohs(addr6.sin6_port); + break; + } +#endif + default: + name = NULL; + port = 0; + break; + } + + if (name == NULL) { + printf("inet_ntop failed\n"); + free(buf); + return; + } + + printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", + (int)n, + namebuf, + port, + rn.recvv_rcvinfo.rcv_sid, + rn.recvv_rcvinfo.rcv_ssn, + rn.recvv_rcvinfo.rcv_tsn, + ntohl(rn.recvv_rcvinfo.rcv_ppid), + rn.recvv_rcvinfo.rcv_context); + } + } + free(buf); + } + return; +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *sock; + struct sockaddr_in6 addr; + struct sctp_udpencaps encaps; + struct sctp_event event; + uint16_t event_types[] = {SCTP_ASSOC_CHANGE, + SCTP_PEER_ADDR_CHANGE, + SCTP_REMOTE_ERROR, + SCTP_SHUTDOWN_EVENT, + SCTP_ADAPTATION_INDICATION, + SCTP_PARTIAL_DELIVERY_EVENT}; + unsigned int i; + struct sctp_assoc_value av; + const int on = 1; + + if (argc > 1) { + usrsctp_init(atoi(argv[1]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); +#endif + usrsctp_sysctl_set_sctp_blackhole(2); + + if ((sock = usrsctp_socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + } + usrsctp_set_non_blocking(sock, 1); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (const void*)&on, (socklen_t)sizeof(int)) < 0) { + perror("usrsctp_setsockopt SCTP_I_WANT_MAPPED_V4_ADDR"); + } + memset(&av, 0, sizeof(struct sctp_assoc_value)); + av.assoc_id = SCTP_ALL_ASSOC; + av.assoc_value = 47; + + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_CONTEXT, (const void*)&av, (socklen_t)sizeof(struct sctp_assoc_value)) < 0) { + perror("usrsctp_setsockopt SCTP_CONTEXT"); + } + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(int)) < 0) { + perror("usrsctp_setsockopt SCTP_RECVRCVINFO"); + } + if (argc > 2) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET6; + encaps.sue_port = htons(atoi(argv[2])); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("usrsctp_setsockopt SCTP_REMOTE_UDP_ENCAPS_PORT"); + } + } + memset(&event, 0, sizeof(event)); + event.se_assoc_id = SCTP_FUTURE_ASSOC; + event.se_on = 1; + for (i = 0; i < (unsigned int)(sizeof(event_types)/sizeof(uint16_t)); i++) { + event.se_type = event_types[i]; + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)) < 0) { + perror("usrsctp_setsockopt SCTP_EVENT"); + } + } + + usrsctp_set_upcall(sock, handle_upcall, NULL); + + memset((void *)&addr, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(PORT); + addr.sin6_addr = in6addr_any; + if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) { + perror("usrsctp_bind"); + } + if (usrsctp_listen(sock, 1) < 0) { + perror("usrsctp_listen"); + } + while (1) { +#ifdef _WIN32 + Sleep(1*1000); +#else + sleep(1); +#endif + } + usrsctp_close(sock); + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + return (0); +} diff --git a/programs/echo_server.c b/programs/echo_server.c index 64f12c56d..313eda636 100644 --- a/programs/echo_server.c +++ b/programs/echo_server.c @@ -30,7 +30,7 @@ /* * Usage: echo_server [local_encaps_port] [remote_encaps_port] - * + * * Example * Server: $ ./echo_server 11111 22222 * Client: $ ./client 127.0.0.1 7 0 22222 11111 diff --git a/programs/echo_server_upcall.c b/programs/echo_server_upcall.c new file mode 100644 index 000000000..1a39a019d --- /dev/null +++ b/programs/echo_server_upcall.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2011-2013 Michael Tuexen + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Usage: discard_server [local_encaps_port] [remote_encaps_port] + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#endif +#include + +#define BUFFERSIZE 10240 +#define PORT 7 + +static void +handle_upcall(struct socket *sock, void *data, int flgs) +{ + char namebuf[INET6_ADDRSTRLEN]; + const char *name; + uint16_t port; + char *buf; + int events; + + while ((events = usrsctp_get_events(sock)) && (events & SCTP_EVENT_READ)) { + struct sctp_recvv_rn rn; + ssize_t n; + struct sockaddr_storage addr; + buf = malloc(BUFFERSIZE); + int flags = 0; + socklen_t len = (socklen_t)sizeof(struct sockaddr_storage); + unsigned int infotype = 0; + socklen_t infolen = sizeof(struct sctp_recvv_rn); + memset(&rn, 0, sizeof(struct sctp_recvv_rn)); + n = usrsctp_recvv(sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn, + &infolen, &infotype, &flags); + if (n < 0) { + perror("usrsctp_recvv"); + } + if (n == 0) { + usrsctp_close(sock); + return; + } + if (n > 0) { + if (flags & MSG_NOTIFICATION) { + printf("Notification of length %d received.\n", (int)n); + } else { +#ifdef _WIN32 + _write(_fileno(stdout), buf, (unsigned int)n); +#else + if (write(fileno(stdout), buf, n) < 0) { + perror("write"); + } +#endif + switch (addr.ss_family) { +#ifdef INET + case AF_INET: { + struct sockaddr_in addr4; + memcpy(&addr4, (struct sockaddr_in *)&addr, sizeof(struct sockaddr_in)); + name = inet_ntop(AF_INET, &addr4.sin_addr, namebuf, INET_ADDRSTRLEN); + port = ntohs(addr4.sin_port); + break; + } +#endif +#ifdef INET6 + case AF_INET6: { + struct sockaddr_in6 addr6; + memcpy(&addr6, (struct sockaddr_in6 *)&addr, sizeof(struct sockaddr_in6)); + name = inet_ntop(AF_INET6, &addr6.sin6_addr, namebuf, INET6_ADDRSTRLEN), + port = ntohs(addr6.sin6_port); + break; + } +#endif + default: + name = NULL; + port = 0; + break; + } + + if (name == NULL) { + printf("inet_ntop failed\n"); + free(buf); + return; + } + + printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %u, context %u.\n", + (int)n, + namebuf, + port, + rn.recvv_rcvinfo.rcv_sid, + rn.recvv_rcvinfo.rcv_ssn, + rn.recvv_rcvinfo.rcv_tsn, + ntohl(rn.recvv_rcvinfo.rcv_ppid), + rn.recvv_rcvinfo.rcv_context); + if (flags & MSG_EOR) { + struct sctp_sndinfo snd_info; + + snd_info.snd_sid = rn.recvv_rcvinfo.rcv_sid; + snd_info.snd_flags = 0; + if (rn.recvv_rcvinfo.rcv_flags & SCTP_UNORDERED) { + snd_info.snd_flags |= SCTP_UNORDERED; + } + snd_info.snd_ppid = rn.recvv_rcvinfo.rcv_ppid; + snd_info.snd_context = 0; + snd_info.snd_assoc_id = rn.recvv_rcvinfo.rcv_assoc_id; + if (usrsctp_sendv(sock, buf, n, NULL, 0, &snd_info, sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) { + perror("sctp_sendv"); + } + } + } + } + free(buf); + } + return; +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *sock; + struct sockaddr_in6 addr; + struct sctp_udpencaps encaps; + struct sctp_event event; + uint16_t event_types[] = {SCTP_ASSOC_CHANGE, + SCTP_PEER_ADDR_CHANGE, + SCTP_REMOTE_ERROR, + SCTP_SHUTDOWN_EVENT, + SCTP_ADAPTATION_INDICATION, + SCTP_PARTIAL_DELIVERY_EVENT}; + unsigned int i; + struct sctp_assoc_value av; + const int on = 1; + + if (argc > 1) { + usrsctp_init(atoi(argv[1]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_NONE); +#endif + usrsctp_sysctl_set_sctp_blackhole(2); + + if ((sock = usrsctp_socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + } + usrsctp_set_non_blocking(sock, 1); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (const void*)&on, (socklen_t)sizeof(int)) < 0) { + perror("usrsctp_setsockopt SCTP_I_WANT_MAPPED_V4_ADDR"); + } + memset(&av, 0, sizeof(struct sctp_assoc_value)); + av.assoc_id = SCTP_ALL_ASSOC; + av.assoc_value = 47; + + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_CONTEXT, (const void*)&av, (socklen_t)sizeof(struct sctp_assoc_value)) < 0) { + perror("usrsctp_setsockopt SCTP_CONTEXT"); + } + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(int)) < 0) { + perror("usrsctp_setsockopt SCTP_RECVRCVINFO"); + } + if (argc > 2) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET6; + encaps.sue_port = htons(atoi(argv[2])); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("usrsctp_setsockopt SCTP_REMOTE_UDP_ENCAPS_PORT"); + } + } + memset(&event, 0, sizeof(event)); + event.se_assoc_id = SCTP_FUTURE_ASSOC; + event.se_on = 1; + for (i = 0; i < (unsigned int)(sizeof(event_types)/sizeof(uint16_t)); i++) { + event.se_type = event_types[i]; + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)) < 0) { + perror("usrsctp_setsockopt SCTP_EVENT"); + } + } + + usrsctp_set_upcall(sock, handle_upcall, NULL); + + memset((void *)&addr, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(PORT); + addr.sin6_addr = in6addr_any; + if (usrsctp_bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) { + perror("usrsctp_bind"); + } + if (usrsctp_listen(sock, 1) < 0) { + perror("usrsctp_listen"); + } + while (1) { +#ifdef _WIN32 + Sleep(1*1000); +#else + sleep(1); +#endif + } + usrsctp_close(sock); + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + return (0); +} diff --git a/programs/http_client_upcall.c b/programs/http_client_upcall.c new file mode 100644 index 000000000..c091ad623 --- /dev/null +++ b/programs/http_client_upcall.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2016 Felix Weinrank + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Usage: http_client_upcall remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri] + */ + +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#ifndef _WIN32 +#include +#include +#include +#else +#include +#endif +#include + +int done = 0; +int writePending = 1; + +static const char *request_prefix = "GET"; +static const char *request_postfix = "HTTP/1.0\r\nUser-agent: libusrsctp\r\nConnection: close\r\n\r\n"; +char request[512]; + +#ifdef _WIN32 +typedef char* caddr_t; +#endif + +#define BUFFERSIZE (1<<16) + + +static void handle_upcall(struct socket *sock, void *arg, int flgs) +{ + int events = usrsctp_get_events(sock); + int bytesSent = 0; + char *buf; + + if ((events & SCTP_EVENT_WRITE) && writePending) { + writePending = 0; + printf("\nHTTP request:\n%s\n", request); + printf("\nHTTP response:\n"); + + /* send GET request */ + bytesSent = usrsctp_sendv(sock, request, strlen(request), NULL, 0, NULL, 0, SCTP_SENDV_NOINFO, 0); + if (bytesSent < 0) { + perror("usrsctp_sendv"); + usrsctp_close(sock); + } else { + printf("%d bytes sent\n", bytesSent); + } + } + + if ((events & SCTP_EVENT_READ) && !done) { + struct sctp_recvv_rn rn; + ssize_t n; + struct sockaddr_in addr; + buf = malloc(BUFFERSIZE); + int flags = 0; + socklen_t len = (socklen_t)sizeof(struct sockaddr_in); + unsigned int infotype = 0; + socklen_t infolen = sizeof(struct sctp_recvv_rn); + memset(&rn, 0, sizeof(struct sctp_recvv_rn)); + n = usrsctp_recvv(sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn, + &infolen, &infotype, &flags); + if (n > 0) + write(1, buf, n); + done = 1; + usrsctp_close(sock); + free(buf); + return; + } +} + +void +debug_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +int +main(int argc, char *argv[]) +{ + struct socket *sock; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + struct sctp_udpencaps encaps; + int result; + + if (argc < 3) { + printf("Usage: http_client_upcall remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]\n"); + return(EXIT_FAILURE); + } + + result = 0; + if (argc > 4) { + usrsctp_init(atoi(argv[4]), NULL, debug_printf); + } else { + usrsctp_init(9899, NULL, debug_printf); + } + +#ifdef SCTP_DEBUG + usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); +#endif + + usrsctp_sysctl_set_sctp_blackhole(2); + + if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) { + perror("usrsctp_socket"); + result = 1; + goto out; + } + + usrsctp_set_non_blocking(sock, 1); + + if (argc > 3) { + memset((void *)&addr6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN6_LEN + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(atoi(argv[3])); + addr6.sin6_addr = in6addr_any; + if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + perror("bind"); + usrsctp_close(sock); + result = 2; + goto out; + } + } + + if (argc > 5) { + memset(&encaps, 0, sizeof(struct sctp_udpencaps)); + encaps.sue_address.ss_family = AF_INET6; + encaps.sue_port = htons(atoi(argv[5])); + if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void *)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) { + perror("setsockopt"); + usrsctp_close(sock); + result = 3; + goto out; + } + } + + if (argc > 6) { +#ifdef _WIN32 + _snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix); +#else + snprintf(request, sizeof(request), "%s %s %s", request_prefix, argv[6], request_postfix); +#endif + } else { +#ifdef _WIN32 + _snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix); +#else + snprintf(request, sizeof(request), "%s %s %s", request_prefix, "/", request_postfix); +#endif + } + + usrsctp_set_upcall(sock, handle_upcall, NULL); + + memset((void *)&addr4, 0, sizeof(struct sockaddr_in)); + memset((void *)&addr6, 0, sizeof(struct sockaddr_in6)); +#ifdef HAVE_SIN_LEN + addr4.sin_len = sizeof(struct sockaddr_in); +#endif +#ifdef HAVE_SIN6_LEN + addr6.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr4.sin_family = AF_INET; + addr6.sin6_family = AF_INET6; + addr4.sin_port = htons(atoi(argv[2])); + addr6.sin6_port = htons(atoi(argv[2])); + if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) { + if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + if (errno != EINPROGRESS) { + perror("usrsctp_connect"); + usrsctp_close(sock); + result = 4; + goto out; + } + } + } else if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) { + if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) { + if (errno != EINPROGRESS) { + perror("usrsctp_connect"); + usrsctp_close(sock); + result = 5; + goto out; + } + } + } else { + printf("Illegal destination address\n"); + usrsctp_close(sock); + result = 6; + goto out; + } + while (!done) { +#ifdef _WIN32 + Sleep(1*1000); +#else + sleep(1); +#endif + } +out: + while (usrsctp_finish() != 0) { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + return (result); +} diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c index 208da68f2..29ca9dcb0 100755 --- a/usrsctplib/netinet/sctp_input.c +++ b/usrsctplib/netinet/sctp_input.c @@ -5735,7 +5735,9 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt struct sctp_inpcb *inp = NULL, *inp_decr = NULL; struct sctp_tcb *stcb = NULL; struct sctp_nets *net = NULL; - +#if defined(__Userspace__) + struct socket *upcall_socket = NULL; +#endif SCTP_STAT_INCR(sctps_recvdatagrams); #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xE0, 1); @@ -5884,6 +5886,20 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt } } +#if defined(__Userspace__) + if (stcb && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + if (stcb->sctp_socket->so_head != NULL) { + upcall_socket = stcb->sctp_socket->so_head; + } else { + upcall_socket = stcb->sctp_socket; + } + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } +#endif if (IS_SCTP_CONTROL(ch)) { /* process the control portion of the SCTP packet */ /* sa_ignore NO_NULL_CHK */ @@ -5962,7 +5978,20 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt */ goto out; } - +#if defined(__Userspace__) + if (stcb && upcall_socket == NULL && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + if (stcb->sctp_socket->so_head != NULL) { + upcall_socket = stcb->sctp_socket->so_head; + } else { + upcall_socket = stcb->sctp_socket; + } + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } +#endif /* * DATA chunk processing */ @@ -6101,6 +6130,18 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt if (stcb != NULL) { SCTP_TCB_UNLOCK(stcb); } +#if defined(__Userspace__) + if (upcall_socket != NULL) { + if (upcall_socket->so_upcall != NULL) { + if (soreadable(upcall_socket) || sowriteable(upcall_socket) || upcall_socket->so_error) { + (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); + } + } + ACCEPT_LOCK(); + SOCK_LOCK(upcall_socket); + sorele(upcall_socket); + } +#endif if (inp_decr != NULL) { /* reduce ref-count */ SCTP_INP_WLOCK(inp_decr); diff --git a/usrsctplib/netinet/sctp_usrreq.c b/usrsctplib/netinet/sctp_usrreq.c index 032557146..6a4d7b50f 100755 --- a/usrsctplib/netinet/sctp_usrreq.c +++ b/usrsctplib/netinet/sctp_usrreq.c @@ -420,6 +420,11 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) #if defined(__FreeBSD__) struct ip *outer_ip; #endif + +#if defined(__Userspace__) + struct socket *upcall_socket = NULL; +#endif + struct ip *inner_ip; struct sctphdr *sh; struct icmp *icmp; @@ -528,7 +533,29 @@ sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip) #else inner_ip->ip_len, #endif - (uint32_t)ntohs(icmp->icmp_nextmtu)); + ntohs(icmp->icmp_nextmtu)); + +#if defined(__Userspace__) + if (stcb && upcall_socket == NULL && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + upcall_socket = stcb->sctp_socket; + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } + if (upcall_socket != NULL) { + if (upcall_socket->so_upcall != NULL) { + if (upcall_socket->so_error) { + (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); + } + } + ACCEPT_LOCK(); + SOCK_LOCK(upcall_socket); + sorele(upcall_socket); + } +#endif + } else { #if defined(__FreeBSD__) && __FreeBSD_version < 500000 /* diff --git a/usrsctplib/netinet/sctputil.c b/usrsctplib/netinet/sctputil.c index 2e404eb73..d131ac32a 100755 --- a/usrsctplib/netinet/sctputil.c +++ b/usrsctplib/netinet/sctputil.c @@ -1609,6 +1609,9 @@ sctp_timeout_handler(void *t) int did_output; int type; +#if defined(__Userspace__) + struct socket *upcall_socket = NULL; +#endif tmr = (struct sctp_timer *)t; inp = (struct sctp_inpcb *)tmr->ep; stcb = (struct sctp_tcb *)tmr->tcb; @@ -1744,6 +1747,16 @@ sctp_timeout_handler(void *t) } SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); +#if defined(__Userspace__) + if (stcb && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + upcall_socket = stcb->sctp_socket; + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } +#endif /* call the handler for the appropriate timer type */ switch (type) { case SCTP_TIMER_TYPE_ADDR_WQ: @@ -2045,6 +2058,18 @@ sctp_timeout_handler(void *t) } out_decr: +#if defined(__Userspace__) + if (upcall_socket != NULL) { + if (upcall_socket->so_upcall != NULL) { + if (upcall_socket->so_error) { + (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); + } + } + ACCEPT_LOCK(); + SOCK_LOCK(upcall_socket); + sorele(upcall_socket); + } +#endif if (inp) { SCTP_INP_DECR_REF(inp); } @@ -7753,6 +7778,9 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct struct sockaddr_in src, dst; uint8_t type, code; +#if defined(__Userspace__) + struct socket *upcall_socket = NULL; +#endif inner_ip = (struct ip *)vip; icmp = (struct icmp *)((caddr_t)inner_ip - (sizeof(struct icmp) - sizeof(struct ip))); @@ -7838,6 +7866,26 @@ sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ct sctp_notify(inp, stcb, net, type, code, ntohs(inner_ip->ip_len), (uint32_t)ntohs(icmp->icmp_nextmtu)); +#if defined(__Userspace__) + if (stcb && upcall_socket == NULL && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + upcall_socket = stcb->sctp_socket; + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } + if (upcall_socket != NULL) { + if (upcall_socket->so_upcall != NULL) { + if (upcall_socket->so_error) { + (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); + } + } + ACCEPT_LOCK(); + SOCK_LOCK(upcall_socket); + sorele(upcall_socket); + } +#endif } else { #if defined(__FreeBSD__) && __FreeBSD_version < 500000 /* @@ -7875,6 +7923,9 @@ sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx struct udphdr udp; struct sockaddr_in6 src, dst; uint8_t type, code; +#if defined(__Userspace__) + struct socket *upcall_socket = NULL; +#endif ip6cp = (struct ip6ctlparam *)d; /* @@ -8003,6 +8054,26 @@ sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx } sctp6_notify(inp, stcb, net, type, code, ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); +#if defined(__Userspace__) + if (stcb && upcall_socket == NULL && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + upcall_socket = stcb->sctp_socket; + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } + if (upcall_socket != NULL) { + if (upcall_socket->so_upcall != NULL) { + if (upcall_socket->so_error) { + (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); + } + } + ACCEPT_LOCK(); + SOCK_LOCK(upcall_socket); + sorele(upcall_socket); + } +#endif } else { #if defined(__FreeBSD__) && __FreeBSD_version < 500000 if (PRC_IS_REDIRECT(cmd) && (inp != NULL)) { diff --git a/usrsctplib/netinet6/sctp6_usrreq.c b/usrsctplib/netinet6/sctp6_usrreq.c index 897b4da5a..0ae9bdf5c 100644 --- a/usrsctplib/netinet6/sctp6_usrreq.c +++ b/usrsctplib/netinet6/sctp6_usrreq.c @@ -434,6 +434,9 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) struct sctphdr sh; struct sockaddr_in6 src, dst; +#if defined(__Userspace__) + struct socket *upcall_socket = NULL; +#endif #ifdef HAVE_SA_LEN if (pktdst->sa_family != AF_INET6 || pktdst->sa_len != sizeof(struct sockaddr_in6)) { @@ -567,6 +570,26 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) ip6cp->ip6c_icmp6->icmp6_type, ip6cp->ip6c_icmp6->icmp6_code, ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); +#if defined(__Userspace__) + if (stcb && upcall_socket == NULL && !(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + if (stcb->sctp_socket != NULL) { + upcall_socket = stcb->sctp_socket; + SOCK_LOCK(upcall_socket); + soref(upcall_socket); + SOCK_UNLOCK(upcall_socket); + } + } + if (upcall_socket != NULL) { + if (upcall_socket->so_upcall != NULL) { + if (upcall_socket->so_error) { + (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT); + } + } + ACCEPT_LOCK(); + SOCK_LOCK(upcall_socket); + sorele(upcall_socket); + } +#endif } else { #if defined(__FreeBSD__) && __FreeBSD_version < 500000 if (PRC_IS_REDIRECT(cmd) && (inp != NULL)) { diff --git a/usrsctplib/user_socket.c b/usrsctplib/user_socket.c index 7261c9a99..038194c06 100755 --- a/usrsctplib/user_socket.c +++ b/usrsctplib/user_socket.c @@ -3500,6 +3500,52 @@ usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bit return; } +int +usrsctp_get_events(struct socket *so) +{ + int events = 0; + + if (so == NULL) { + errno = EBADF; + return -1; + } + + if (soreadable(so)) { + events |= SCTP_EVENT_READ; + } + if (sowriteable(so)) { + events |= SCTP_EVENT_WRITE; + } + if (so->so_error) { + events |= SCTP_EVENT_ERROR; + } + return events; +} + +int usrsctp_get_error(struct socket *so) +{ + if (so->so_error) + return so->so_error; + return -1; +} + +int +usrsctp_set_upcall(struct socket *so, void (*upcall)(struct socket *, void *, int), void *arg) +{ + if (so == NULL) { + errno = EBADF; + return (-1); + } + + SOCK_LOCK(so); + so->so_upcall = upcall; + so->so_upcallarg = arg; + so->so_snd.sb_flags |= SB_UPCALL; + so->so_rcv.sb_flags |= SB_UPCALL; + SOCK_UNLOCK(so); + + return (0); +} #define USRSCTP_SYSCTL_SET_DEF(__field) \ void usrsctp_sysctl_set_ ## __field(uint32_t value) { \ diff --git a/usrsctplib/user_socketvar.h b/usrsctplib/user_socketvar.h index ffc8270ef..e00c4c7a2 100755 --- a/usrsctplib/user_socketvar.h +++ b/usrsctplib/user_socketvar.h @@ -364,6 +364,13 @@ extern userland_cond_t accept_cond; #define SQ_INCOMP 0x0800 /* unaccepted, incomplete connection */ #define SQ_COMP 0x1000 /* unaccepted, complete connection */ +/* + * Socket event flags + */ +#define SCTP_EVENT_READ 0x0001 /* socket is readable */ +#define SCTP_EVENT_WRITE 0x0002 /* socket is writeable */ +#define SCTP_EVENT_ERROR 0x0004 /* socket has an error state */ + /* * Externalized form of struct socket used by the sysctl(3) interface. */ @@ -719,6 +726,7 @@ void soisconnected(struct socket *so); struct socket * sonewconn(struct socket *head, int connstatus); void socantrcvmore(struct socket *so); void socantsendmore(struct socket *so); +void sofree(struct socket *so); diff --git a/usrsctplib/usrsctp.h b/usrsctplib/usrsctp.h index 16159f691..20e8c0069 100644 --- a/usrsctplib/usrsctp.h +++ b/usrsctplib/usrsctp.h @@ -141,6 +141,10 @@ union sctp_sockstore { #define SCTP_CURRENT_ASSOC 1 #define SCTP_ALL_ASSOC 2 +#define SCTP_EVENT_READ 0x0001 +#define SCTP_EVENT_WRITE 0x0002 +#define SCTP_EVENT_ERROR 0x0004 + /*** Structures and definitions to use the socket API ***/ #define SCTP_ALIGN_RESV_PAD 92 @@ -1008,6 +1012,15 @@ usrsctp_deregister_address(void *); int usrsctp_set_ulpinfo(struct socket *, void *); +int +usrsctp_set_upcall(struct socket *so, + void (*upcall)(struct socket *, void *, int), + void *arg); + +int +usrsctp_get_events(struct socket *so); + + #define SCTP_DUMP_OUTBOUND 1 #define SCTP_DUMP_INBOUND 0