aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIrene Ruengeler <ruengeler@wireshark.org>2017-12-11 14:08:32 +0100
committerIrene Ruengeler <ruengeler@wireshark.org>2017-12-11 14:08:32 +0100
commit6bafb12aa5c6cd7019bf0dde5a7af490cd336a8a (patch)
treea354da78264da762ec193af508b29ca635b7d7c2
parenta0c3a35adeb91541bc545ec0d04735e844cbec65 (diff)
downloadusrsctp-6bafb12aa5c6cd7019bf0dde5a7af490cd336a8a.tar.gz
New upcall API
-rw-r--r--programs/CMakeLists.txt6
-rw-r--r--programs/chargen_server_upcall.c239
-rw-r--r--programs/client_upcall.c333
-rw-r--r--programs/daytime_server_upcall.c156
-rw-r--r--programs/discard_server_upcall.c242
-rw-r--r--programs/echo_server.c2
-rw-r--r--programs/echo_server_upcall.c258
-rw-r--r--programs/http_client_upcall.c252
-rwxr-xr-xusrsctplib/netinet/sctp_callout.c4
-rwxr-xr-xusrsctplib/netinet/sctp_callout.h1
-rwxr-xr-xusrsctplib/netinet/sctp_input.c45
-rwxr-xr-xusrsctplib/netinet/sctp_usrreq.c29
-rwxr-xr-xusrsctplib/netinet/sctputil.c73
-rw-r--r--usrsctplib/netinet6/sctp6_usrreq.c23
-rwxr-xr-xusrsctplib/user_socket.c51
-rwxr-xr-xusrsctplib/user_socketvar.h8
-rw-r--r--usrsctplib/usrsctp.h13
17 files changed, 1728 insertions, 7 deletions
diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt
index ab4c7fda..e84dcaf9 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 00000000..bb654111
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <usrsctp.h>
+
+#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 00000000..2785cd04
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#include <io.h>
+#endif
+#include <usrsctp.h>
+#include <fcntl.h>
+
+#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 00000000..f2d786b4
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <time.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <usrsctp.h>
+
+#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 00000000..c0c5b8f7
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <usrsctp.h>
+
+#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 64f12c56..313eda63 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 00000000..1a39a019
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <usrsctp.h>
+
+#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 00000000..c091ad62
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#include <io.h>
+#endif
+#include <usrsctp.h>
+
+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_callout.c b/usrsctplib/netinet/sctp_callout.c
index 30bfa0d5..2e8c630a 100755
--- a/usrsctplib/netinet/sctp_callout.c
+++ b/usrsctplib/netinet/sctp_callout.c
@@ -144,8 +144,8 @@ sctp_os_timer_stop(sctp_os_timer_t *c)
return (1);
}
-static void
-sctp_handle_tick(int delta)
+void
+sctp_handle_tick(unsigned int delta)
{
sctp_os_timer_t *c;
void (*c_func)(void *);
diff --git a/usrsctplib/netinet/sctp_callout.h b/usrsctplib/netinet/sctp_callout.h
index 765f966b..a4fe52f9 100755
--- a/usrsctplib/netinet/sctp_callout.h
+++ b/usrsctplib/netinet/sctp_callout.h
@@ -90,6 +90,7 @@ typedef struct sctp_callout sctp_os_timer_t;
void sctp_os_timer_init(sctp_os_timer_t *tmr);
void sctp_os_timer_start(sctp_os_timer_t *, int, void (*)(void *), void *);
int sctp_os_timer_stop(sctp_os_timer_t *);
+void sctp_handle_tick(unsigned int);
#define SCTP_OS_TIMER_INIT sctp_os_timer_init
#define SCTP_OS_TIMER_START sctp_os_timer_start
diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c
index 208da68f..29ca9dcb 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 @@ trigger_send:
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 03255714..6a4d7b50 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 2e404eb7..9665f12f 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 @@ get_out:
}
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)));
@@ -7837,7 +7865,27 @@ 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));
+ 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 897b4da5..0ae9bdf5 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 7261c9a9..4cd6e5eb 100755
--- a/usrsctplib/user_socket.c
+++ b/usrsctplib/user_socket.c
@@ -3500,6 +3500,57 @@ usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bit
return;
}
+void usrsctp_handle_timers(unsigned int delta)
+{
+ sctp_handle_tick(MSEC_TO_TICKS(delta));
+}
+
+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 ffc8270e..e00c4c7a 100755
--- a/usrsctplib/user_socketvar.h
+++ b/usrsctplib/user_socketvar.h
@@ -365,6 +365,13 @@ extern userland_cond_t accept_cond;
#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.
*/
struct xsocket {
@@ -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 16159f69..20e8c006 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