├── .gitignore ├── CMakeDetermineGoCompiler.cmake ├── CMakeGoCompiler.cmake.in ├── CMakeGoInformation.cmake ├── CMakeLists.txt ├── CMakeTestGoCompiler.cmake ├── LICENSE.txt ├── README.md ├── RFCs ├── rfc3758.pdf ├── rfc4895.pdf ├── rfc4960.pdf └── rfc5061.pdf ├── include └── myutil.h ├── multi_echo ├── c │ ├── sctp │ │ ├── CMakeLists.txt │ │ ├── client │ │ │ ├── multiEchoSCTPClient.c │ │ │ └── multiEchoSCTPClient.h │ │ └── server │ │ │ ├── multiEchoSCTPServer.c │ │ │ └── multiEchoSCTPServer.h │ └── tcp │ │ ├── CMakeLists.txt │ │ ├── client │ │ ├── multiEchoTCPClient.c │ │ └── multiEchoTCPClient.h │ │ └── server │ │ ├── multiEchoTCPServer.c │ │ └── multiEchoTCPServer.h └── go │ ├── sctp │ ├── CMakeLists.txt │ ├── client │ │ └── multiEchoSCTPClient.go │ └── server │ │ └── multiEchoSCTPServer.go │ └── tcp │ ├── CMakeLists.txt │ ├── client │ └── multiEchoTCPClient.go │ └── server │ └── multiEchoTCPServer.go ├── simple ├── c │ ├── sctp │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── client_sendmsg │ │ │ └── simpleSCTPClient_sendmsg.c │ │ ├── client_sendv │ │ │ └── simpleSCTPClient_sctp_sendv.c │ │ ├── server_recvmsg │ │ │ └── simpleSCTPServer_recvmsg.c │ │ └── server_recvv │ │ │ └── simpleSCTPServer_sctp_revv.c │ └── tcp │ │ ├── CMakeLists.txt │ │ ├── client │ │ ├── simpleEchoTCPClient.c │ │ └── simpleEchoTCPClient.h │ │ └── server │ │ ├── simpleEchoTCPServer.c │ │ └── simpleEchoTCPServer.h └── go │ └── sctp │ ├── CMakeLists.txt │ ├── client │ └── simpleSCTPClient.go │ └── server │ └── simpleSCTPServer.go └── src └── myutil.c /.gitignore: -------------------------------------------------------------------------------- 1 | echo/c/tcp/build 2 | 3 | # Created by .ignore support plugin (hsz.mobi) 4 | ### Vim template 5 | [._]*.s[a-w][a-z] 6 | [._]s[a-w][a-z] 7 | *.un~ 8 | Session.vim 9 | .netrwhist 10 | *~ 11 | 12 | 13 | ### JetBrains template 14 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 15 | 16 | *.iml 17 | 18 | ## Directory-based project format: 19 | .idea/ 20 | # if you remove the above rule, at least ignore the following: 21 | 22 | # User-specific stuff: 23 | # .idea/workspace.xml 24 | # .idea/tasks.xml 25 | # .idea/dictionaries 26 | 27 | # Sensitive or high-churn files: 28 | # .idea/dataSources.ids 29 | # .idea/dataSources.xml 30 | # .idea/sqlDataSources.xml 31 | # .idea/dynamic.xml 32 | # .idea/uiDesigner.xml 33 | 34 | # Gradle: 35 | # .idea/gradle.xml 36 | # .idea/libraries 37 | 38 | # Mongo Explorer plugin: 39 | # .idea/mongoSettings.xml 40 | 41 | ## File-based project format: 42 | *.ipr 43 | *.iws 44 | 45 | ## Plugin-specific files: 46 | 47 | # IntelliJ 48 | /out/ 49 | 50 | # mpeltonen/sbt-idea plugin 51 | .idea_modules/ 52 | 53 | # JIRA plugin 54 | atlassian-ide-plugin.xml 55 | 56 | # Crashlytics plugin (for Android Studio and IntelliJ) 57 | com_crashlytics_export_strings.xml 58 | crashlytics.properties 59 | crashlytics-build.properties 60 | 61 | 62 | ### SublimeText template 63 | # cache files for sublime text 64 | *.tmlanguage.cache 65 | *.tmPreferences.cache 66 | *.stTheme.cache 67 | 68 | # workspace files are user-specific 69 | *.sublime-workspace 70 | 71 | # project files should be checked into the repository, unless a significant 72 | # proportion of contributors will probably not be using SublimeText 73 | # *.sublime-project 74 | 75 | # sftp configuration file 76 | sftp-config.json 77 | 78 | 79 | ### C template 80 | # Object files 81 | tcp/build/server/CMakeFiles/echoServer.dir/echoServer.c.o 82 | *.ko 83 | *.obj 84 | *.elf 85 | 86 | # Precompiled Headers 87 | *.gch 88 | *.pch 89 | 90 | # Libraries 91 | *.lib 92 | *.a 93 | *.la 94 | *.lo 95 | 96 | # Shared objects (inc. Windows DLLs) 97 | *.dll 98 | *.so 99 | *.so.* 100 | *.dylib 101 | 102 | # Executables 103 | *.exe 104 | *.out 105 | *.app 106 | *.i*86 107 | *.x86_64 108 | *.hex 109 | 110 | # Debug files 111 | *.dSYM/ 112 | 113 | 114 | ### C++ template 115 | # Compiled Object files 116 | *.slo 117 | *.lo 118 | *.o 119 | *.obj 120 | 121 | # Precompiled Headers 122 | *.gch 123 | *.pch 124 | 125 | # Compiled Dynamic libraries 126 | *.so 127 | *.dylib 128 | *.dll 129 | 130 | # Fortran module files 131 | *.mod 132 | 133 | # Compiled Static libraries 134 | *.lai 135 | *.la 136 | *.a 137 | *.lib 138 | 139 | # Executables 140 | *.exe 141 | *.out 142 | *.app 143 | 144 | 145 | build 146 | ### JetBrains template 147 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 148 | 149 | *.iml 150 | 151 | ## Directory-based project format: 152 | .idea/ 153 | # if you remove the above rule, at least ignore the following: 154 | 155 | # User-specific stuff: 156 | # .idea/workspace.xml 157 | # .idea/tasks.xml 158 | # .idea/dictionaries 159 | 160 | # Sensitive or high-churn files: 161 | # .idea/dataSources.ids 162 | # .idea/dataSources.xml 163 | # .idea/sqlDataSources.xml 164 | # .idea/dynamic.xml 165 | # .idea/uiDesigner.xml 166 | 167 | # Gradle: 168 | # .idea/gradle.xml 169 | # .idea/libraries 170 | 171 | # Mongo Explorer plugin: 172 | # .idea/mongoSettings.xml 173 | 174 | ## File-based project format: 175 | *.ipr 176 | *.iws 177 | 178 | ## Plugin-specific files: 179 | 180 | # IntelliJ 181 | /out/ 182 | 183 | # mpeltonen/sbt-idea plugin 184 | .idea_modules/ 185 | 186 | # JIRA plugin 187 | atlassian-ide-plugin.xml 188 | 189 | # Crashlytics plugin (for Android Studio and IntelliJ) 190 | com_crashlytics_export_strings.xml 191 | crashlytics.properties 192 | crashlytics-build.properties 193 | 194 | 195 | -------------------------------------------------------------------------------- /CMakeDetermineGoCompiler.cmake: -------------------------------------------------------------------------------- 1 | if(NOT CMAKE_Go_COMPILER) 2 | set(Go_BIN_PATH 3 | $ENV{GOPATH} 4 | $ENV{GOROOT} 5 | $ENV{GOROOT}/../bin 6 | /usr/bin 7 | /usr/local/bin 8 | ) 9 | find_program(CMAKE_Go_COMPILER 10 | NAMES go 11 | PATHS ${Go_BIN_PATH} 12 | ) 13 | endif() 14 | 15 | mark_as_advanced(CMAKE_Go_COMPILER) 16 | 17 | configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeGoCompiler.cmake.in ${CMAKE_PLATFORM_INFO_DIR}/CMakeGoCompiler.cmake @ONLY) 18 | 19 | set(CMAKE_Go_COMPILER_ENV_VAR "GOCOMPILER") 20 | -------------------------------------------------------------------------------- /CMakeGoCompiler.cmake.in: -------------------------------------------------------------------------------- 1 | set(CMAKE_Go_COMPILER "@CMAKE_Go_COMPILER@") 2 | set(CMAKE_Go_COMPILER_LOADED 1) 3 | 4 | set(CMAKE_Go_SOURCE_FILE_EXTENSIONS go) 5 | set(CMAKE_Go_LINKER_PREFERENCE 40) 6 | set(CMAKE_Go_OUTPUT_EXTENSION .6) 7 | set(CMAKE_Go_OUTPUT_EXTENSION_REPLACE 1) 8 | -------------------------------------------------------------------------------- /CMakeGoInformation.cmake: -------------------------------------------------------------------------------- 1 | if(CMAKE_USER_MAKE_RULES_OVERRIDE) 2 | # Save the full path of the file so try_compile can use it. 3 | include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override) 4 | set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}") 5 | endif() 6 | 7 | if(CMAKE_USER_MAKE_RULES_OVERRIDE_Go) 8 | # Save the full path of the file so try_compile can use it. 9 | include(${CMAKE_USER_MAKE_RULES_OVERRIDE_Go} RESULT_VARIABLE _override) 10 | set(CMAKE_USER_MAKE_RULES_OVERRIDE_Go "${_override}") 11 | endif() 12 | 13 | if(NOT CMAKE_Go_COMPILE_OBJECT) 14 | set(CMAKE_Go_COMPILE_OBJECT "go tool compile -l -N -o ") 15 | endif() 16 | if(NOT CMAKE_Go_LINK_EXECUTABLE) 17 | set(CMAKE_Go_LINK_EXECUTABLE "go tool link -o ") 18 | endif() 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/) 4 | 5 | project(root) 6 | set(HEADER_FILES ${root_SOURCE_DIR}/include/) 7 | 8 | add_library(myutillib src/myutil.c ${HEADER_FILES}) 9 | 10 | add_subdirectory(multi_echo/c/tcp) 11 | add_subdirectory(multi_echo/c/sctp) 12 | add_subdirectory(multi_echo/go/tcp) 13 | add_subdirectory(multi_echo/go/sctp) 14 | 15 | add_subdirectory(simple/c/tcp) 16 | add_subdirectory(simple/c/sctp) 17 | add_subdirectory(simple/go/sctp) -------------------------------------------------------------------------------- /CMakeTestGoCompiler.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_Go_COMPILER_WORKS 1 CACHE INTERNAL "") -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Olivier Van Acker 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Repository for SCTP example programs and their UDP and/or TCP equivalent 2 | 3 | ## OS Support 4 | 5 | ### FreeBSD 6 | The reference implementation of SCTP is on FreeBSD, so all programs are guarenteed to work on this OS. 7 | 8 | ### OS X 9 | The reference implementation gets ported frequently to the latest version of Mac OS X: 10 | [install instructions](https://nplab.fh-muenster.de/wiki/pages/27J6w9D2/SCTP_on_Yosemite.html). 11 | All programs should also work on this OS. 12 | 13 | Once everything is installed the driver kan be loaded with the follwoing command: 14 | 15 | sudo kextload /System/Library/Extensions/SCTP.kext 16 | 17 | 18 | ### Linux 19 | No guaranteed support. [SCTP Linux driver developement](https://github.com/borkmann/lksctp-tools) 20 | 21 | ### Microsoft Windows 22 | No guaranteed support. [SCTP Windows driver development](http://www.bluestop.org/SctpDrv/) 23 | 24 | ## Example programs 25 | Every category also has a TCP implementation for comparison. 26 | 27 | ### Simple Echo: Client - Server 28 | 1. Clients send a single message 29 | 2. Server echos message back 30 | 3. Client prints message 31 | 4. Client closes 32 | 33 | ### Multi Echo: Client - Server 34 | Multi threaded client, keeps sending messages to server 35 | 36 | ### File Upload: Client - Server 37 | Uploading a PNG picture file. 38 | 39 | ### Multi File Upload: Client - Server 40 | Uploading multiple files over multiple channels. 41 | 42 | ### Binary protocol: Client - Server 43 | Simple binary protocol 44 | 45 | ### Streaming audio 46 | Stream audio from single client to multiple clients via server. 47 | -------------------------------------------------------------------------------- /RFCs/rfc3758.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberroadie/sctp-examples/20de997cbd5530369156773a1f8c926c5e14d290/RFCs/rfc3758.pdf -------------------------------------------------------------------------------- /RFCs/rfc4895.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberroadie/sctp-examples/20de997cbd5530369156773a1f8c926c5e14d290/RFCs/rfc4895.pdf -------------------------------------------------------------------------------- /RFCs/rfc4960.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberroadie/sctp-examples/20de997cbd5530369156773a1f8c926c5e14d290/RFCs/rfc4960.pdf -------------------------------------------------------------------------------- /RFCs/rfc5061.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberroadie/sctp-examples/20de997cbd5530369156773a1f8c926c5e14d290/RFCs/rfc5061.pdf -------------------------------------------------------------------------------- /include/myutil.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Olivier Van Acker on 07/08/15. 3 | // 4 | 5 | #ifndef SCTP_EXAMPLES_UTIL_H 6 | #define SCTP_EXAMPLES_UTIL_H 7 | 8 | #include 9 | 10 | #define RECVBUFSIZE 100 11 | 12 | void createAddress(char *, char *, struct sockaddr_in *, char *); 13 | //void createAddress(char *hname, char *sname, struct sockaddr_in *sap, char *protocol); 14 | 15 | void error( int status, int err, char *fmt, ... ); 16 | 17 | void createInitMsg(struct sctp_initmsg *initmsg, 18 | u_int16_t num_ostreams, 19 | u_int16_t max_instreams, 20 | u_int16_t max_attempts, 21 | u_int16_t max_init_timeo); 22 | 23 | void createSndRcvInfo(struct sctp_sndrcvinfo *sinfo , 24 | uint32_t ppid, 25 | uint16_t flags, 26 | uint16_t stream_no, 27 | uint32_t timetolive, 28 | uint32_t context); 29 | 30 | void createMessageHdrSndRcv(struct msghdr *outmsghdr, 31 | struct sctp_initmsg *initmsg, 32 | struct sctp_sndrcvinfo *sinfo, 33 | struct sockaddr *to, 34 | socklen_t tolen, 35 | const void *msg, 36 | size_t len); 37 | 38 | void createMessageHdrRcv(struct msghdr *msghdr, 39 | void *message, 40 | size_t mlen); 41 | 42 | #endif //SCTP_EXAMPLES_UTIL_H 43 | -------------------------------------------------------------------------------- /multi_echo/c/sctp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(sctp-examples) 3 | 4 | set(CMAKE_C_FLAGS "-std=c99 -Wall") 5 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 6 | 7 | add_executable(multiEchoSCTPClientC client/multiEchoSCTPClient.c) 8 | add_executable(multiEchoSCTPServerC server/multiEchoSCTPServer.c) 9 | 10 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 11 | target_link_libraries(multiEchoSCTPServerC /usr/lib/libsctp.dylib) 12 | target_link_libraries(multiEchoSCTPClientC /usr/lib/libsctp.dylib) 13 | endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 14 | -------------------------------------------------------------------------------- /multi_echo/c/sctp/client/multiEchoSCTPClient.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include /* optarg */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "multiEchoSCTPClient.h" 15 | 16 | #define PPID 424242 17 | #define RECVBUFSIZE 2048 18 | 19 | typedef struct messageSender_data { 20 | char *host; 21 | int port; 22 | char *message; 23 | long count; 24 | int thread_id; 25 | } messageSenderData_t; 26 | 27 | struct settings settings; 28 | 29 | void *messageSender(void *arg) { 30 | 31 | messageSenderData_t *data = (messageSenderData_t *) arg; 32 | char *message = strdup(data->message); 33 | 34 | int count = data->count; 35 | int sd; 36 | 37 | sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 38 | 39 | if(sd == -1) { 40 | perror("failure opening socket"); 41 | exit(EXIT_FAILURE); 42 | } 43 | 44 | struct sctp_initmsg initmsg = {0}; 45 | initmsg.sinit_num_ostreams = 100; 46 | int s = setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); 47 | if(s == -1) { 48 | perror("error setting socket options"); 49 | exit(EXIT_FAILURE); 50 | } 51 | //const int on = 0; 52 | //setsockopt(sd, IPPROTO_SCTP, SCTP_LISTEN_FIX, &on, sizeof(int)); 53 | 54 | struct sockaddr_in address; 55 | bzero((void*)&address, sizeof(address)); 56 | address.sin_family = AF_INET; 57 | address.sin_port = htons(data->port); 58 | address.sin_addr.s_addr = inet_addr(data->host); 59 | address.sin_len = (socklen_t) sizeof(struct sockaddr_in); 60 | 61 | // Structure containing data 62 | struct iovec iov; 63 | bzero(&iov, sizeof(iov)); 64 | iov.iov_base = message; 65 | iov.iov_len = strlen(message); 66 | 67 | struct sctp_sndinfo sinfo; 68 | bzero(&sinfo, sizeof(struct sctp_sndinfo)); 69 | 70 | // Send information structure 71 | sinfo.snd_sid = 3; 72 | sinfo.snd_ppid = htonl(424242); 73 | //sinfo.snd_flags = SCTP_UNORDERED; 74 | 75 | // receiving variables 76 | struct iovec echoiov[1]; 77 | char buf[RECVBUFSIZE]; 78 | echoiov->iov_base = buf; 79 | echoiov->iov_len = RECVBUFSIZE; 80 | 81 | struct sockaddr_in from; 82 | socklen_t *fromlen = NULL, infolen; 83 | int flags = 0; 84 | unsigned int infotype = 0; 85 | struct sctp_rcvinfo rinfo; 86 | bzero(&rinfo, sizeof(struct sctp_rcvinfo)); 87 | infolen = sizeof(rinfo); 88 | 89 | struct sctp_initmsg initMsg; 90 | bzero((void *)&initMsg, sizeof(initMsg)); 91 | initMsg.sinit_num_ostreams = 100; 92 | initMsg.sinit_max_instreams = 0; 93 | initMsg.sinit_max_attempts = 0; 94 | initMsg.sinit_max_init_timeo = 0; 95 | 96 | setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)); 97 | 98 | for(int i = 0; i < count; i++) { 99 | 100 | printf("sending message: %s\n", message); 101 | char str[INET_ADDRSTRLEN]; 102 | inet_ntop(AF_INET, &address.sin_addr, str, sizeof(str)); 103 | printf("on address %s\n", str); 104 | 105 | int n = sctp_sendv(sd, 106 | &iov, 107 | 1, 108 | (struct sockaddr *) &address, 109 | 1, 110 | (void *) &sinfo, 111 | sizeof(struct sctp_sndinfo), 112 | SCTP_SENDV_SNDINFO, 113 | 0); 114 | 115 | if(n == -1) { 116 | perror("failure sending message"); 117 | exit(EXIT_FAILURE); 118 | } 119 | 120 | int length = sctp_recvv(sd, 121 | echoiov, 122 | 1, 123 | (struct sockaddr *) &from, 124 | fromlen, 125 | &rinfo, 126 | &infolen, 127 | &infotype, 128 | &flags); 129 | 130 | if(length == -1) { 131 | perror("failure receiving message"); 132 | exit(EXIT_FAILURE); 133 | } else { 134 | printf("received: %s\n", buf); 135 | } 136 | } 137 | return 0; 138 | } 139 | 140 | static void settings_init(void) { 141 | settings.host = "127.0.0.1"; 142 | settings.port = 4242; 143 | settings.message = "hello"; 144 | settings.count = 1; 145 | settings.no_of_threads = 1; 146 | settings.bufsize = 4096; 147 | settings.verbose= false; 148 | } 149 | 150 | void echoClient(char *host, int port, char *message, long count, int number_of_threads) { 151 | 152 | int rc; 153 | messageSenderData_t data[number_of_threads]; 154 | pthread_t pth[number_of_threads]; 155 | 156 | for(int i = 0; i < number_of_threads; i++) { 157 | //data = (messageSenderData_t*)malloc(sizeof(messageSenderData_)); 158 | data[i].host = strdup(host); 159 | data[i].port = port; 160 | data[i].message = strdup(message); 161 | data[i].count = count; 162 | data[i].thread_id = i; 163 | 164 | if((rc = pthread_create(&pth[i], NULL, messageSender, &data[i]))) { 165 | perror("failure creating thread"); 166 | continue; 167 | } 168 | } 169 | /* wait for every htread to finish */ 170 | for(int i = 0; i < number_of_threads; i++) { 171 | pthread_join(pth[i], NULL); 172 | } 173 | } 174 | 175 | static void usage(void) { 176 | printf("-i server to connect to (default: localhost)\n" 177 | "-p port number to connect to (default: 4242)\n" 178 | "-m message to send (default: hello)\n" 179 | "-c (default: 1)\n" 180 | "-n (default: 1)\n" 181 | ); 182 | return; 183 | } 184 | 185 | int main(int argc, char **argv) { 186 | 187 | int c; 188 | 189 | settings_init(); 190 | 191 | while (-1 != (c = getopt(argc, argv, 192 | "h:" 193 | "i:" 194 | "p:" 195 | "m:" 196 | "c:" 197 | "n:" 198 | "b:" 199 | "s" 200 | "v" 201 | ))) { 202 | switch (c) { 203 | case 'h': 204 | usage(); 205 | exit(EXIT_SUCCESS); 206 | case 'i': 207 | settings.host = optarg; 208 | break; 209 | case 'p': 210 | settings.port = atoi(optarg); 211 | break; 212 | case 'm': 213 | settings.message = optarg; 214 | break; 215 | case 'c': 216 | settings.count = atol(optarg); 217 | break; 218 | case 'n': 219 | settings.no_of_threads= atoi(optarg); 220 | break; 221 | case 'b': 222 | settings.bufsize = atoi(optarg); 223 | break; 224 | case 's': 225 | settings.sctp = true; 226 | break; 227 | case 'v': 228 | settings.verbose = true; 229 | break; 230 | default: 231 | fprintf(stderr, "Illegal argument \"%c\"\n", c); 232 | exit(EXIT_FAILURE); 233 | } 234 | } 235 | echoClient(settings.host, settings.port, settings.message, settings.count, settings.no_of_threads); 236 | } 237 | 238 | -------------------------------------------------------------------------------- /multi_echo/c/sctp/client/multiEchoSCTPClient.h: -------------------------------------------------------------------------------- 1 | #ifndef ECHO_CLIENT_H 2 | #define ECHO_CLIENT_H 3 | 4 | struct settings { 5 | int port; 6 | char *host; 7 | char *message; /* message to send to server */ 8 | long count; /* number of messages to send */ 9 | int no_of_threads; 10 | int bufsize; 11 | bool verbose; 12 | bool sctp; 13 | }; 14 | 15 | struct audit { 16 | long success; 17 | long failure; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /multi_echo/c/sctp/server/multiEchoSCTPServer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "multiEchoSCTPServer.h" 11 | 12 | #define RECVBUFSIZE 2048 13 | #define SCTP_CONTROL_VEC_SIZE_RCV 16384 // lib/libc/net/sctp_sys_calls.c 14 | 15 | struct settings settings; 16 | 17 | static void usage(void) { 18 | printf("-i server to connect to (default: 0.0.0.0)\n" 19 | "-p port number to connect on (default: 4242)\n" 20 | "-m message to send (default: recv)\n" 21 | ); 22 | return; 23 | } 24 | 25 | int echoServer(char *host, int port, char *message) { 26 | 27 | int sd; 28 | 29 | sd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 30 | 31 | if(sd == -1) { 32 | perror("failure opening socket"); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | struct sockaddr_in serverAddress; 37 | bzero((void *)&serverAddress, sizeof(serverAddress)); 38 | serverAddress.sin_family = AF_INET; 39 | serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); 40 | serverAddress.sin_port = htons(port); 41 | 42 | if(-1 == bind(sd, (struct sockaddr *)&serverAddress, sizeof(serverAddress))) { 43 | perror("bind error"); 44 | close(sd); 45 | exit(EXIT_FAILURE); 46 | } 47 | 48 | struct sctp_initmsg initMsg; 49 | bzero((void *)&initMsg, sizeof(initMsg)); 50 | initMsg.sinit_num_ostreams = 100; 51 | initMsg.sinit_max_instreams = 100; 52 | initMsg.sinit_max_attempts = 0; 53 | initMsg.sinit_max_init_timeo = 0; 54 | 55 | setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)); 56 | const int on = 1; 57 | setsockopt(sd, IPPROTO_SCTP, SCTP_LISTEN_FIX, &on, sizeof(int)); 58 | 59 | if(listen(sd, 1) < 0) { 60 | perror("failed to listen for connection"); 61 | exit(EXIT_FAILURE); 62 | } 63 | 64 | printf("listening on port %d\n", port); 65 | 66 | struct iovec iov[1]; 67 | char buf[RECVBUFSIZE]; 68 | iov->iov_base = buf; 69 | iov->iov_len = RECVBUFSIZE; 70 | 71 | 72 | if (setsockopt(sd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0) { 73 | perror("setsockopt SCTP_RECVRCVINFO"); 74 | exit(EXIT_FAILURE); 75 | } 76 | 77 | struct sctp_sndinfo sinfo; 78 | bzero(&sinfo, sizeof(struct sctp_sndinfo)); 79 | 80 | 81 | for(;;) { 82 | 83 | printf("listening for message\n"); 84 | struct sockaddr_in client_addr; 85 | bzero((void*)&client_addr, sizeof(client_addr)); 86 | socklen_t fromlen, infolen; 87 | int flags = 0; 88 | unsigned int infotype = 0; 89 | struct sctp_rcvinfo rinfo; 90 | bzero(&rinfo, sizeof(struct sctp_rcvinfo)); 91 | infolen = sizeof(rinfo); 92 | fromlen = sizeof(client_addr); 93 | int length = sctp_recvv(sd, 94 | iov, 95 | 1, 96 | (struct sockaddr *) &client_addr, 97 | &fromlen, 98 | &rinfo, 99 | &infolen, 100 | &infotype, 101 | &flags); 102 | 103 | if(length == -1) { 104 | perror("error receiving message: "); 105 | exit(EXIT_FAILURE); 106 | } 107 | 108 | buf[length] = '\0'; 109 | printf("message received: %s\n", buf); 110 | 111 | printf("[ Receive echo (%u bytes): stream = %hu, " 112 | "flags = %hx, ppid = %u ]\n", length, 113 | rinfo.rcv_sid, rinfo.rcv_flags, 114 | ntohl(rinfo.rcv_ppid)); 115 | 116 | 117 | 118 | sinfo.snd_sid = rinfo.rcv_sid; 119 | sinfo.snd_flags = SCTP_UNORDERED; 120 | sinfo.snd_ppid = rinfo.rcv_ppid; 121 | sinfo.snd_assoc_id = rinfo.rcv_assoc_id; 122 | 123 | printf("sending message back: %s\n", buf); 124 | 125 | char str[INET_ADDRSTRLEN]; 126 | inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)); 127 | printf("On address %s\n", str); 128 | // 129 | // sctp_sendv(sd, 130 | // iov, 131 | // 1, 132 | // (struct sockaddr *) &from, 133 | // 1, 134 | // (void *) &sinfo, 135 | // sizeof(struct sctp_sndinfo), 136 | // SCTP_SENDV_SNDINFO, 137 | // 0); 138 | // 139 | int n = sctp_sendv(sd, 140 | iov, 141 | 1, 142 | (struct sockaddr *) &client_addr, 143 | 1, 144 | (void *) &sinfo, 145 | sizeof(struct sctp_sndinfo), 146 | SCTP_SENDV_SNDINFO, 147 | 0); 148 | if(n == -1) { 149 | perror("error receiving message: "); 150 | exit(EXIT_FAILURE); 151 | } 152 | 153 | printf("message sent\n"); 154 | 155 | } 156 | 157 | return EXIT_SUCCESS; 158 | } 159 | 160 | static void settingsInit(void) { 161 | settings.host = "0.0.0.0"; 162 | settings.port = 4242; 163 | settings.message = "recv"; 164 | settings.verbose= false; 165 | } 166 | 167 | int main(int argc, char **argv) { 168 | 169 | int c; 170 | 171 | settingsInit(); 172 | 173 | while(-1 != (c = getopt(argc, argv, 174 | "h:" 175 | "i:" 176 | "p:" 177 | "m:" 178 | "c:" 179 | "b:" 180 | "v" 181 | ))) { 182 | switch (c) { 183 | case 'h': 184 | usage(); 185 | exit(EXIT_SUCCESS); 186 | case 'i': 187 | settings.host = optarg; 188 | break; 189 | case 'p': 190 | settings.port = atoi(optarg); 191 | break; 192 | case 'm': 193 | settings.message = optarg; 194 | break; 195 | case 'v': 196 | settings.verbose = true; 197 | break; 198 | default: 199 | fprintf(stderr, "Illegal argument \"%c\"\n", c); 200 | exit(EXIT_FAILURE); 201 | } 202 | } 203 | echoServer(settings.host, settings.port, settings.message); 204 | } 205 | -------------------------------------------------------------------------------- /multi_echo/c/sctp/server/multiEchoSCTPServer.h: -------------------------------------------------------------------------------- 1 | #ifndef ECHO_SERVER_H 2 | #define ECHO_SERVER_H 3 | 4 | struct settings { 5 | int port; 6 | char *host; 7 | char *message; /* answer to send to client */ 8 | bool verbose; 9 | bool sctp; 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /multi_echo/c/tcp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(sctp-examples) 3 | 4 | include_directories(SYSTEM "/usr/include") 5 | set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") 6 | 7 | set(CMAKE_C_FLAGS "-std=c99 -Wall") 8 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 9 | 10 | add_executable(multiEchoTCPClientC client/multiEchoTCPClient.c) 11 | add_executable(multiEchoTCPServerC server/multiEchoTCPServer.c) 12 | 13 | -------------------------------------------------------------------------------- /multi_echo/c/tcp/client/multiEchoTCPClient.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include /* optarg */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include /* TCP_NODELAY lives here */ 10 | #include 11 | #include 12 | #include "multiEchoTCPClient.h" 13 | 14 | struct settings settings; 15 | 16 | typedef struct messageSender_data { 17 | char *host; 18 | int port; 19 | char *message; 20 | long count; 21 | int thread_id; 22 | } messageSenderData_t; 23 | 24 | void *messageSender(void *arg) { 25 | 26 | messageSenderData_t *data = (messageSenderData_t *) arg; 27 | 28 | struct sockaddr_in serverAddress; 29 | struct audit audit; 30 | audit.success = 0; 31 | audit.failure = 0; 32 | 33 | /* keep data local to thread */ 34 | char *message = strdup(data->message); 35 | int count = data->count; 36 | 37 | bzero((void *)&serverAddress, sizeof(serverAddress)); 38 | serverAddress.sin_family = AF_INET; 39 | serverAddress.sin_port = htons(data->port); 40 | serverAddress.sin_addr.s_addr = inet_addr(data->host); 41 | 42 | int sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 43 | 44 | if(-1 == connect(sd, 45 | (struct sockaddr *) &serverAddress, 46 | sizeof(serverAddress))) { 47 | perror("connection failure"); 48 | close(sd); 49 | pthread_exit(NULL); 50 | } 51 | 52 | int flag = 1; 53 | setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)); 54 | 55 | size_t length; 56 | uint32_t nlength, nid, ack_id, ack_nid; 57 | ssize_t numbytes; 58 | 59 | printf("thread %d start sending %d messages\n", data->thread_id, count); 60 | 61 | for(uint32_t id = 0; id < count; id++) { 62 | 63 | if(settings.verbose) printf("sending message %d\n", id); 64 | 65 | // send size of message 66 | length = strlen(message); 67 | nlength = htonl(length); 68 | 69 | if((numbytes = send(sd, &nlength, 4, 0)) == -1) { 70 | perror("send message size failure"); 71 | audit.failure++; 72 | break; 73 | } 74 | 75 | // send message id 76 | nid = htonl(id); 77 | if((numbytes = send(sd, &nid, 4, 0)) == -1) { 78 | perror("send message id failure"); 79 | audit.failure++; 80 | break; 81 | } 82 | 83 | // send message 84 | if((numbytes = send(sd, message, length, 0)) == -1) { 85 | perror("send message failure"); 86 | audit.failure++; 87 | break; 88 | } 89 | 90 | /* get response (message id) */ 91 | if((numbytes = recv(sd, &ack_nid, 4, MSG_WAITALL)) == -1) { 92 | perror("recv id failure"); 93 | audit.failure++; 94 | break; 95 | } 96 | 97 | ack_id = ntohl(ack_nid); 98 | if(ack_id != id) { 99 | printf("ack_id: %d != id: %d\n", ack_id, id); 100 | break; 101 | } 102 | 103 | audit.success++; 104 | } 105 | 106 | 107 | /* close the message stream by sending a zero length message */ 108 | length = 0; 109 | nlength = htonl(length); 110 | if((numbytes = send(sd, &nlength, 4, 0)) == -1) { 111 | perror("send message size failure"); 112 | close(sd); 113 | pthread_exit(NULL); 114 | } 115 | 116 | close(sd); 117 | 118 | printf("%lu messages send succesful by thread %d\n", audit.success, data->thread_id); 119 | printf("%lu messages failed\n", audit.failure); 120 | 121 | pthread_exit(NULL); 122 | } 123 | 124 | void echoClient(char *host, int port, char *message, long count, int number_of_threads) { 125 | 126 | int rc; 127 | messageSenderData_t data[number_of_threads]; 128 | pthread_t pth[number_of_threads]; 129 | 130 | for(int i = 0; i < number_of_threads; i++) { 131 | //data = (messageSenderData_t*)malloc(sizeof(messageSenderData_)); 132 | data[i].host = strdup(host); 133 | data[i].port = port; 134 | data[i].message = strdup(message); 135 | data[i].count = count; 136 | data[i].thread_id = i; 137 | 138 | if((rc = pthread_create(&pth[i], NULL, messageSender, &data[i]))) { 139 | perror("failure creating thread"); 140 | continue; 141 | } 142 | } 143 | /* wait for every htread to finish */ 144 | for(int i = 0; i < number_of_threads; i++) { 145 | pthread_join(pth[i], NULL); 146 | } 147 | } 148 | 149 | static void usage(void) { 150 | printf("-i server to connect to (default: localhost)\n" 151 | "-p port number to connect to (default: 4242)\n" 152 | "-m message to send (default: hello)\n" 153 | "-c (default: 1)\n" 154 | "-n (default: 1)\n" 155 | ); 156 | return; 157 | } 158 | 159 | static void settings_init(void) { 160 | settings.host = "127.0.0.1"; 161 | settings.port = 4242; 162 | settings.message = "hello"; 163 | settings.count = 1; 164 | settings.no_of_threads = 1; 165 | settings.bufsize = 4096; 166 | settings.verbose= false; 167 | } 168 | 169 | int main(int argc, char **argv) { 170 | 171 | int c; 172 | 173 | settings_init(); 174 | 175 | while (-1 != (c = getopt(argc, argv, 176 | "h" 177 | "i:" 178 | "p:" 179 | "m:" 180 | "c:" 181 | "n:" 182 | "b:" 183 | "s" 184 | "v" 185 | ))) { 186 | switch (c) { 187 | case 'h': 188 | usage(); 189 | exit(EXIT_SUCCESS); 190 | case 'i': 191 | settings.host = optarg; 192 | break; 193 | case 'p': 194 | settings.port = atoi(optarg); 195 | break; 196 | case 'm': 197 | settings.message = optarg; 198 | break; 199 | case 'c': 200 | settings.count = atol(optarg); 201 | break; 202 | case 'n': 203 | settings.no_of_threads= atoi(optarg); 204 | break; 205 | case 'b': 206 | settings.bufsize = atoi(optarg); 207 | break; 208 | case 'v': 209 | settings.verbose = true; 210 | break; 211 | default: 212 | fprintf(stderr, "Illegal argument \"%c\"\n", c); 213 | exit(EXIT_FAILURE); 214 | } 215 | } 216 | echoClient(settings.host, settings.port, settings.message, settings.count, settings.no_of_threads); 217 | } 218 | 219 | 220 | -------------------------------------------------------------------------------- /multi_echo/c/tcp/client/multiEchoTCPClient.h: -------------------------------------------------------------------------------- 1 | #ifndef ECHO_CLIENT_H 2 | #define ECHO_CLIENT_H 3 | 4 | struct settings { 5 | int port; 6 | char *host; 7 | char *message; /* message to send to server */ 8 | long count; /* number of messages to send */ 9 | int no_of_threads; 10 | int bufsize; 11 | bool verbose; 12 | }; 13 | 14 | struct audit { 15 | long success; 16 | long failure; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /multi_echo/c/tcp/server/multiEchoTCPServer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include /* optarg */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "multiEchoTCPServer.h" 12 | 13 | struct settings settings; 14 | 15 | typedef struct handleClientData { 16 | int acceptedSocket; 17 | struct sockaddr_in client_address; 18 | char *message; 19 | } handleClientData_t; 20 | 21 | void *handleClient(void *arg) { 22 | 23 | long numMessages = 0; 24 | handleClientData_t *data = (handleClientData_t *) arg; 25 | 26 | char addr[INET_ADDRSTRLEN]; 27 | inet_ntop(AF_INET, &(data->client_address.sin_addr), addr, INET_ADDRSTRLEN); 28 | printf("Connection accepted from: %s \n", addr); 29 | 30 | int numbytes = 0; 31 | uint32_t length, nlength, id, nid; 32 | 33 | for(;;) { 34 | /* get message length */ 35 | if((numbytes = recv(data->acceptedSocket, &nlength, 4, MSG_WAITALL)) == -1) { 36 | perror("recv message size failure"); 37 | close(data->acceptedSocket); 38 | pthread_exit(NULL); 39 | } 40 | 41 | /* check if last message is sent */ 42 | if(ntohl(nlength) == 0) break; 43 | 44 | /* get message id */ 45 | if((numbytes = recv(data->acceptedSocket, &nid, 4, MSG_WAITALL)) == -1) { 46 | perror("recv message size failure"); 47 | close(data->acceptedSocket); 48 | pthread_exit(NULL); 49 | } 50 | 51 | id = ntohl(nid); 52 | if(settings.verbose) printf("message %d received\n", id); 53 | 54 | /* get message */ 55 | char *msg; 56 | length = ntohl(nlength); 57 | msg = malloc(length); 58 | if((numbytes = recv(data->acceptedSocket, msg, length, MSG_WAITALL)) == -1) { 59 | printf("%lu messages received\n", numMessages); 60 | perror("recv message failure"); 61 | close(data->acceptedSocket); 62 | pthread_exit(NULL); 63 | 64 | } 65 | msg[length] = 0; 66 | numMessages++; 67 | 68 | /* send message id back as acknowledgement */ 69 | if((numbytes = send(data->acceptedSocket, &nid, 4, 0)) == -1) { 70 | perror("send failure"); 71 | close(data->acceptedSocket); 72 | pthread_exit(NULL); 73 | } 74 | } 75 | printf("%lu messages received\n", numMessages); 76 | close(data->acceptedSocket); 77 | 78 | pthread_exit(NULL); 79 | } 80 | 81 | int echoServer(char *host, int port, char *message) { 82 | 83 | int rc; 84 | struct sockaddr_in serverAddress, client_address; 85 | 86 | int sd; 87 | if(settings.sctp) { 88 | sd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); 89 | } else { 90 | sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 91 | } 92 | 93 | if(sd == -1) { 94 | perror("failure creating socket"); 95 | exit(EXIT_FAILURE); 96 | } 97 | 98 | bzero((void *)&serverAddress, sizeof(serverAddress)); 99 | serverAddress.sin_family = AF_INET; 100 | serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); 101 | serverAddress.sin_port = htons(port); 102 | 103 | if(-1 == bind(sd, 104 | (struct sockaddr *)&serverAddress, 105 | sizeof(serverAddress))) { 106 | perror("bind error"); 107 | close(sd); 108 | exit(EXIT_FAILURE); 109 | } 110 | 111 | if(-1 == listen(sd, 5)) { 112 | perror("listen error"); 113 | close(sd); 114 | exit(EXIT_FAILURE); 115 | } 116 | 117 | socklen_t len = sizeof(client_address); 118 | 119 | handleClientData_t *data; 120 | 121 | for(;;) { 122 | data = (handleClientData_t*)malloc(sizeof(handleClientData_t)); 123 | data->message = strdup(message); 124 | data->acceptedSocket = accept(sd, 125 | (struct sockaddr *) &data->client_address, 126 | &len); 127 | 128 | if(data->acceptedSocket == -1) { 129 | perror("failure accepting socket"); 130 | close(data->acceptedSocket); 131 | continue; 132 | } 133 | 134 | pthread_t pth; 135 | 136 | if((rc = pthread_create(&pth, NULL, handleClient, data))) { 137 | perror("failure creating thread"); 138 | close(data->acceptedSocket); 139 | continue; 140 | } 141 | } 142 | } 143 | 144 | static void usage(void) { 145 | printf("-i server to connect to (default: 0.0.0.0)\n" 146 | "-p port number to connect on (default: 4243)\n" 147 | "-m message to send (default: recv)\n" 148 | "-v verbose\n" 149 | "-s use sctp\n" 150 | ); 151 | return; 152 | } 153 | 154 | static void settingsInit(void) { 155 | settings.host = "0.0.0.0"; 156 | settings.port = 4242; 157 | settings.message = "recv"; 158 | settings.verbose= false; 159 | settings.sctp = false; 160 | } 161 | 162 | int main(int argc, char **argv) { 163 | 164 | int c; 165 | 166 | settingsInit(); 167 | 168 | while (-1 != (c = getopt(argc, argv, 169 | "h:" 170 | "i:" 171 | "p:" 172 | "m:" 173 | "c:" 174 | "b:" 175 | "s" 176 | "v" 177 | ))) { 178 | switch (c) { 179 | case 'h': 180 | usage(); 181 | exit(EXIT_SUCCESS); 182 | case 'i': 183 | settings.host = optarg; 184 | break; 185 | case 'p': 186 | settings.port = atoi(optarg); 187 | break; 188 | case 'm': 189 | settings.message = optarg; 190 | break; 191 | case 'v': 192 | settings.verbose = true; 193 | break; 194 | case 's': 195 | settings.sctp = true; 196 | break; 197 | default: 198 | fprintf(stderr, "Illegal argument \"%c\"\n", c); 199 | exit(EXIT_FAILURE); 200 | } 201 | } 202 | echoServer(settings.host, settings.port, settings.message); 203 | } 204 | -------------------------------------------------------------------------------- /multi_echo/c/tcp/server/multiEchoTCPServer.h: -------------------------------------------------------------------------------- 1 | #ifndef ECHO_SERVER_H 2 | #define ECHO_SERVER_H 3 | 4 | struct settings { 5 | int port; 6 | char *host; 7 | char *message; /* answer to send to client */ 8 | bool verbose; 9 | bool sctp; 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /multi_echo/go/sctp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(scpt-examples Go) 3 | 4 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 5 | 6 | add_executable(multiEchoSCTPCLient client/multiEchoSCTPClient.go) 7 | add_executable(multiEchoSCTPServer server/multiEchoSCTPServer.go) -------------------------------------------------------------------------------- /multi_echo/go/sctp/client/multiEchoSCTPClient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "net" 7 | "os" 8 | "time" 9 | ) 10 | 11 | type Settings struct { 12 | Address *string 13 | Message *string 14 | Count *int 15 | Instances *int 16 | Verbose *bool 17 | } 18 | 19 | var ( 20 | settings = Settings{ 21 | Address: flag.String("a", "localhost:4242", "address to sent messages to"), 22 | Message: flag.String("m", "haai", "message to send"), 23 | Count: flag.Int("c", 1, "number of messages"), 24 | Instances: flag.Int("n", 1, "number of threads"), 25 | Verbose: flag.Bool("v", false, "extra logging"), 26 | } 27 | ) 28 | 29 | func main() { 30 | flag.Parse() 31 | 32 | addr, err := net.ResolveSCTPAddr("sctp", *settings.Address) 33 | if err != nil { 34 | println(err) 35 | os.Exit(-1) 36 | } 37 | 38 | msg := make([]byte, 2048) 39 | conn, err := net.DialSCTP("sctp", nil, addr) 40 | 41 | if err != nil { 42 | println("Error listening " + err.Error()) 43 | os.Exit(-1) 44 | } 45 | defer conn.Close() 46 | 47 | log.Printf("Dialing to %s", *settings.Address) 48 | 49 | var message = *settings.Message 50 | bmessage := []byte(message) 51 | 52 | for { 53 | // for i := 0; i < 10; i++ { 54 | log.Printf("Sending message '%s'", message) 55 | _, err := conn.WriteTo(bmessage, addr) 56 | if err != nil { 57 | log.Printf("WriteTo error: %v", err) 58 | break 59 | } 60 | _, _, err = conn.ReadFrom(msg) 61 | if err != nil { 62 | println("ReadFrom error") 63 | print(err) 64 | break 65 | } 66 | println("Received: " + string(msg)) 67 | time.Sleep(1 * 1e9) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /multi_echo/go/sctp/server/multiEchoSCTPServer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "net" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | type Settings struct { 12 | Address *string 13 | Message *string 14 | Verbose *bool 15 | Sctp *bool 16 | } 17 | 18 | var ( 19 | settings = Settings{ 20 | Address: flag.String("a", "localhost:4242", "address to listen on"), 21 | Message: flag.String("m", "recv", "message to send"), 22 | Sctp: flag.Bool("s", false, "Use SCTP"), 23 | Verbose: flag.Bool("v", false, "extra logging"), 24 | } 25 | ) 26 | 27 | func echoServer(Address *string, Message *string) { 28 | addr, _ := net.ResolveSCTPAddr("sctp", *settings.Address) 29 | conn, err := net.ListenSCTP("sctp", addr) 30 | 31 | if err != nil { 32 | log.Printf("Error listening: %v", err) 33 | os.Exit(-1) 34 | } 35 | defer conn.Close() 36 | 37 | for { 38 | msg := make([]byte, 2048) 39 | log.Printf("Listening on %s", *settings.Address) 40 | aid, addr, sid, err := conn.ReadFromSCTP(msg) 41 | if err != nil { 42 | log.Printf("Error: %v ", err) 43 | break 44 | } 45 | println("********") 46 | println("Message: " + string(msg)) 47 | println("Stream id: " + strconv.Itoa(int(sid))) 48 | println("Association id: " + strconv.Itoa(int(aid))) 49 | println("********") 50 | conn.WriteTo(msg, addr) 51 | } 52 | 53 | } 54 | 55 | func main() { 56 | flag.Parse() 57 | echoServer(settings.Address, settings.Message) 58 | } 59 | -------------------------------------------------------------------------------- /multi_echo/go/tcp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(scpt-examples Go) 3 | 4 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 5 | 6 | add_executable(multiEchoTCPClientGo client/multiEchoTCPClient.go) 7 | add_executable(multiEchoTCPServerGo server/multiEchoTCPServer.go) 8 | -------------------------------------------------------------------------------- /multi_echo/go/tcp/client/multiEchoTCPClient.go: -------------------------------------------------------------------------------- 1 | // EchoClient.go 2 | package main 3 | 4 | import ( 5 | "encoding/binary" 6 | "flag" 7 | "fmt" 8 | "io" 9 | "log" 10 | "net" 11 | ) 12 | 13 | type Settings struct { 14 | Address *string 15 | Message *string 16 | Count *int 17 | Instances *int 18 | Verbose *bool 19 | } 20 | 21 | var ( 22 | settings = Settings{ 23 | Address: flag.String("a", "127.0.0.1:4242", "address to listen on"), 24 | Message: flag.String("m", "recv", "message to send"), 25 | Count: flag.Int("c", 1, "number of messages"), 26 | Instances: flag.Int("n", 1, "number of threads"), 27 | Verbose: flag.Bool("v", true, "extra logging"), 28 | } 29 | ) 30 | 31 | func messageSender(address *string, message *string, count int, done chan bool) { 32 | 33 | var conn net.Conn 34 | conn, err := net.Dial("tcp", *address) 35 | if *settings.Verbose { 36 | fmt.Printf("Connecting to %s\n", *address) 37 | } 38 | if err != nil { 39 | log.Printf("error connecting: %s", err) 40 | return 41 | } 42 | defer conn.Close() 43 | 44 | if err := conn.(*net.TCPConn).SetNoDelay(true); err != nil { 45 | log.Printf("error setting socket option: %s", err) 46 | return 47 | } 48 | 49 | idBytes := make([]byte, 4) 50 | idReceived, idBytesReceived := uint32(0), make([]byte, 4) 51 | size, sizeBytes := uint32(len(*message)), make([]byte, 4) 52 | binary.BigEndian.PutUint32(sizeBytes, uint32(size)) 53 | 54 | for i := 0; i < count; i++ { 55 | // Write data length 56 | if _, err := conn.Write(sizeBytes); err != nil { 57 | log.Printf("error writing id: %s", err) 58 | return 59 | } 60 | 61 | // Write id 62 | binary.BigEndian.PutUint32(idBytes, uint32(i)) 63 | if _, err := conn.Write(idBytes); err != nil { 64 | log.Printf("error writing id: %s", err) 65 | return 66 | } 67 | 68 | if _, err := conn.Write([]byte(*message)); err != nil { 69 | log.Printf("error writing id: %s", err) 70 | return 71 | } 72 | 73 | // Get message id 74 | if n, err := io.ReadFull(conn, idBytesReceived); n == 0 && err == io.EOF { 75 | break 76 | } else if err != nil { 77 | log.Printf("read id: %s (after %d bytes)", err, n) 78 | break 79 | } 80 | if *settings.Verbose { 81 | idReceived = binary.BigEndian.Uint32(idBytesReceived) 82 | log.Printf("id received: %d", idReceived) 83 | } 84 | } 85 | done <- true 86 | return 87 | } 88 | 89 | func echoClient(address *string, message *string, count *int, instances *int) { 90 | done := make(chan bool) 91 | for i := 0; i < *instances; i++ { 92 | go messageSender(address, message, *count, done) 93 | } 94 | finished := 0 95 | for { 96 | if finished == *instances { 97 | return 98 | } 99 | <-done 100 | finished++ 101 | } 102 | } 103 | 104 | func main() { 105 | flag.Parse() 106 | log.Printf("Connecting to %s and starting %d goroutines, sending %d messages", 107 | *settings.Address, 108 | *settings.Instances, 109 | *settings.Count) 110 | echoClient(settings.Address, settings.Message, settings.Count, settings.Instances) 111 | } 112 | -------------------------------------------------------------------------------- /multi_echo/go/tcp/server/multiEchoTCPServer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * User: cyberroadie 3 | * Date: 12/11/2011 4 | */ 5 | package main 6 | 7 | import ( 8 | "encoding/binary" 9 | "flag" 10 | "io" 11 | "log" 12 | "net" 13 | "os" 14 | ) 15 | 16 | type Settings struct { 17 | Address *string 18 | Message *string 19 | Verbose *bool 20 | Sctp *bool 21 | } 22 | 23 | var ( 24 | settings = Settings{ 25 | Address: flag.String("a", "127.0.0.1:4242", "address to listen on"), 26 | Message: flag.String("m", "recv", "message to send"), 27 | Sctp: flag.Bool("s", false, "Use SCTP"), 28 | Verbose: flag.Bool("v", true, "extra logging"), 29 | } 30 | ) 31 | 32 | func handleClient(conn net.Conn, message *string) { 33 | 34 | size, sizeBytes := uint32(0), make([]byte, 4) 35 | id, idBytes := uint32(0), make([]byte, 4) 36 | 37 | for { 38 | // Get message length 39 | if n, err := io.ReadFull(conn, sizeBytes); n == 0 && err == io.EOF { 40 | break 41 | } else if err != nil { 42 | log.Printf("read size: %s (after %d bytes)", err, n) 43 | break 44 | } 45 | // Get message id 46 | if n, err := io.ReadFull(conn, idBytes); n == 0 && err == io.EOF { 47 | break 48 | } else if err != nil { 49 | log.Printf("read id: %s (after %d bytes)", err, n) 50 | break 51 | } 52 | 53 | size = binary.BigEndian.Uint32(sizeBytes) 54 | data := make([]byte, size) 55 | if _, err := io.ReadFull(conn, data); err != nil { 56 | log.Printf("read data: %s", err) 57 | break 58 | } 59 | 60 | // Send message id back as ACK 61 | id = binary.BigEndian.Uint32(idBytes) 62 | //log.Printf("write data: %d", id) 63 | if _, err := conn.Write(idBytes); err != nil { 64 | log.Printf("write data: %d", id) 65 | log.Printf("write data: %s", err) 66 | break 67 | } 68 | } 69 | } 70 | 71 | func echoServer(Address *string, Message *string) { 72 | var netlisten net.Listener 73 | var err error 74 | 75 | if *settings.Sctp == true { 76 | log.Printf("Using SCTP") 77 | netlisten, err = net.Listen("sctp", *settings.Address) 78 | } else { 79 | log.Printf("Using TCP") 80 | netlisten, err = net.Listen("tcp", *settings.Address) 81 | } 82 | 83 | if err != nil { 84 | log.Printf("Error listening: %s", err) 85 | os.Exit(-1) 86 | } 87 | defer netlisten.Close() 88 | 89 | for { 90 | c, err := netlisten.Accept() 91 | if err != nil { 92 | log.Printf("Error accepting: %s", err) 93 | continue 94 | } 95 | go handleClient(c, Message) 96 | } 97 | } 98 | 99 | func main() { 100 | flag.Parse() 101 | echoServer(settings.Address, settings.Message) 102 | } 103 | -------------------------------------------------------------------------------- /simple/c/sctp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(sctp-examples) 3 | 4 | include_directories(SYSTEM "/usr/include") 5 | include_directories(${HEADER_FILES}) 6 | set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") 7 | 8 | set(CMAKE_C_FLAGS "-std=c99 -Wall") 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | 11 | # As described in https://tools.ietf.org/html/rfc6458#section-3 (One to many style) 12 | add_executable(simpleSCTPClient_sendmsg client_sendmsg/simpleSCTPClient_sendmsg.c ${HEADER_FILES}) 13 | target_link_libraries(simpleSCTPClient_sendmsg myutillib) 14 | add_executable(simpleSCTPServer_recvmsg server_recvmsg/simpleSCTPServer_recvmsg.c ${HEADER_FILES}) 15 | target_link_libraries(simpleSCTPServer_recvmsg myutillib) 16 | 17 | # As described in https://tools.ietf.org/html/rfc6458#section-9.12 18 | add_executable(simpleSCTPClient_sctp_sendv client_sendv/simpleSCTPClient_sctp_sendv.c) 19 | # As described in https://tools.ietf.org/html/rfc6458#section-9.13 20 | add_executable(simpleSCTPServer_sctp_revv server_recvv/simpleSCTPServer_sctp_revv.c) 21 | 22 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 23 | target_link_libraries(simpleSCTPClient_sendmsg /usr/lib/libsctp.dylib) 24 | target_link_libraries(simpleSCTPServer_recvmsg /usr/lib/libsctp.dylib) 25 | target_link_libraries(simpleSCTPClient_sctp_sendv /usr/lib/libsctp.dylib) 26 | target_link_libraries(simpleSCTPServer_sctp_revv /usr/lib/libsctp.dylib) 27 | endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") -------------------------------------------------------------------------------- /simple/c/sctp/README.md: -------------------------------------------------------------------------------- 1 | There are two method to send and receive data over SCPT, both methods have 2 | an example implementations. 3 | 4 | ===sendmsg and recvmsg 5 | 6 | According to RFC Section 3.1 the follwoing socket call 7 | sequence can be used for sending and receiving messages: 8 | 9 | A typical server in this style uses the following socket calls in 10 | sequence to prepare an endpoint for servicing requests: 11 | 12 | o socket() 13 | 14 | o bind() 15 | 16 | o listen() 17 | 18 | o recvmsg() 19 | 20 | o sendmsg() 21 | 22 | o close() 23 | 24 | A typical client uses the following calls in sequence to set up an 25 | association with a server to request services: 26 | 27 | o socket() 28 | 29 | o sendmsg() 30 | 31 | o recvmsg() 32 | 33 | o close() 34 | 35 | Sendmsg and recmsg ae standard POSIX method calls. 36 | 37 | 38 | === sctp_sendv and sctp_recv 39 | 40 | The other method, described in RFC6458 section 9.12 and 9.13 are: 41 | 42 | ssize_t sctp_sendv( 43 | int sd, 44 | const struct iovec *iov, 45 | int iovcnt, 46 | struct sockaddr *addrs, 47 | int addrcnt, 48 | void *info, 49 | socklen_t infolen, 50 | unsigned int infotype, 51 | int flags); 52 | 53 | ssize_t sctp_recvv( 54 | int sd, 55 | const struct iovec *iov, 56 | int iovlen, 57 | struct sockaddr *from, 58 | socklen_t *fromlen, 59 | void *info, 60 | socklen_t *infolen, 61 | unsigned int *infotype, 62 | int *flags); 63 | 64 | 65 | -------------------------------------------------------------------------------- /simple/c/sctp/client_sendmsg/simpleSCTPClient_sendmsg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "myutil.h" 6 | 7 | int main() { 8 | int sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 9 | if(sd == -1) { 10 | perror("failure opening socket"); 11 | exit(EXIT_FAILURE); 12 | } 13 | 14 | struct sctp_initmsg initmsg; 15 | createInitMsg(&initmsg, 10, 10, 0, 0); 16 | 17 | int s = setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); 18 | if(s == -1) { 19 | perror("error setting socket options"); 20 | close(sd); 21 | exit(EXIT_FAILURE); 22 | } 23 | 24 | struct sockaddr_in peer; 25 | createAddress("127.0.0.1", "4242", &peer, "sctp"); 26 | 27 | struct sctp_sndrcvinfo sinfo; 28 | createSndRcvInfo(&sinfo, 1, 0, 0, 0, 0); 29 | 30 | char *message = "hello"; 31 | 32 | struct msghdr msghdr; 33 | createMessageHdrSndRcv(&msghdr, 34 | &initmsg, 35 | &sinfo, 36 | (struct sockaddr *) &peer, 37 | sizeof(peer), 38 | (void *) message, 39 | sizeof(message) 40 | ); 41 | 42 | ssize_t n = sendmsg(sd, &msghdr, 0); 43 | if(n < 0) { 44 | perror("error sending message"); 45 | close(sd); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | close(sd); 50 | exit(EXIT_SUCCESS); 51 | } 52 | -------------------------------------------------------------------------------- /simple/c/sctp/client_sendv/simpleSCTPClient_sctp_sendv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define RECVBUFSIZE 2048 10 | 11 | 12 | int main() { 13 | char *message = "hello"; 14 | 15 | int sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 16 | if(sd == -1) { 17 | perror("failure opening socket"); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | struct sctp_initmsg initmsg = {0}; 22 | initmsg.sinit_num_ostreams = 1; 23 | int s = setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); 24 | if(s == -1) { 25 | perror("error setting socket options"); 26 | exit(EXIT_FAILURE); 27 | } 28 | 29 | struct sockaddr_in address; // TODO replace with helper function 30 | bzero((void*)&address, sizeof(address)); 31 | address.sin_family = AF_INET; 32 | address.sin_port = htons(4242); 33 | char *host = "127.0.0.1"; 34 | address.sin_addr.s_addr = inet_addr(host); 35 | address.sin_len = (socklen_t) sizeof(struct sockaddr_in); 36 | 37 | // Structure containing data 38 | struct iovec iov; 39 | bzero(&iov, sizeof(iov)); 40 | iov.iov_base = message; 41 | iov.iov_len = strlen(message); 42 | 43 | struct sctp_sndinfo sinfo; 44 | bzero(&sinfo, sizeof(struct sctp_sndinfo)); 45 | 46 | // Send information structure 47 | sinfo.snd_sid = 1; 48 | sinfo.snd_ppid = htonl(424242); 49 | //sinfo.snd_flags = SCTP_UNORDERED; 50 | 51 | // receiving variables 52 | struct iovec echoiov[1]; 53 | char buf[RECVBUFSIZE]; 54 | echoiov->iov_base = buf; 55 | echoiov->iov_len = RECVBUFSIZE; 56 | 57 | struct sockaddr_in from; 58 | socklen_t *fromlen = NULL, infolen; 59 | int flags = 0; 60 | unsigned int infotype = 0; 61 | struct sctp_rcvinfo rinfo; 62 | bzero(&rinfo, sizeof(struct sctp_rcvinfo)); 63 | infolen = sizeof(rinfo); 64 | 65 | struct sctp_initmsg initMsg; // TODO Replace with helper function 66 | bzero((void *)&initMsg, sizeof(initMsg)); 67 | initMsg.sinit_num_ostreams = 100; 68 | initMsg.sinit_max_instreams = 0; 69 | initMsg.sinit_max_attempts = 0; 70 | initMsg.sinit_max_init_timeo = 0; 71 | 72 | setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)); 73 | 74 | 75 | int n = sctp_sendv(sd, 76 | &iov, 77 | 1, 78 | (struct sockaddr *) &address, 79 | 1, 80 | (void *) &sinfo, 81 | sizeof(struct sctp_sndinfo), 82 | SCTP_SENDV_SNDINFO, 83 | 0); 84 | 85 | if(n == -1) { 86 | perror("failure sending message"); 87 | exit(EXIT_FAILURE); 88 | } 89 | 90 | return EXIT_SUCCESS; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /simple/c/sctp/server_recvmsg/simpleSCTPServer_recvmsg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "myutil.h" 8 | 9 | int main() { 10 | 11 | int sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 12 | if(sd == -1) { 13 | perror("failure opening socket"); 14 | exit(EXIT_FAILURE); 15 | } 16 | 17 | // listen on 0.0.0.0:4242, any NIC and port 4242 18 | struct sockaddr_in serverAddress; 19 | createAddress(INADDR_ANY, "4242", &serverAddress, "sctp"); 20 | 21 | int rb = bind(sd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)); 22 | if(rb == -1) { 23 | perror("failed to bind"); 24 | close(sd); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | int lr = listen(sd, 5); 29 | if(lr == -1) { 30 | perror("listen failed"); 31 | close(sd); 32 | exit(EXIT_FAILURE); 33 | } 34 | 35 | struct sctp_initmsg initmsg; 36 | createInitMsg(&initmsg, 10, 10, 0, 0); 37 | 38 | int s = setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); 39 | if(s == -1) { 40 | perror("error setting socket options"); 41 | close(sd); 42 | exit(EXIT_FAILURE); 43 | } 44 | 45 | // indicate we want information returned 46 | int on = 1; 47 | if (setsockopt(sd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0) { 48 | perror("setsockopt SCTP_RECVRCVINFO"); 49 | exit(EXIT_FAILURE); 50 | } 51 | 52 | int rl = listen(sd, 1); 53 | if(rl < -1) { 54 | perror("listen failed"); 55 | close(sd); 56 | exit(EXIT_FAILURE); 57 | } 58 | 59 | char message[RECVBUFSIZE]; 60 | 61 | struct msghdr msghdr; 62 | createMessageHdrRcv(&msghdr, 63 | (void *) &message, 64 | RECVBUFSIZE 65 | ); 66 | 67 | for(;;) { 68 | bzero(message, sizeof(message)); 69 | size_t length = recvmsg(sd, &msghdr, 0); 70 | if(length < 0) { 71 | perror("error receiving message"); 72 | close(sd); 73 | exit(EXIT_FAILURE); 74 | } 75 | 76 | struct cmsghdr *cmsg; 77 | struct sctp_rcvinfo *rinfo; 78 | 79 | if(msghdr.msg_controllen > 0) { 80 | cmsg = CMSG_FIRSTHDR(&msghdr); 81 | if (cmsg->cmsg_type == SCTP_RCVINFO) { 82 | rinfo = (struct sctp_rcvinfo *) CMSG_DATA(cmsg); 83 | printf("[ Receive echo (%u bytes): stream = %hu, " 84 | "flags = %hx, ppid = %u ]\n", length, 85 | rinfo->rcv_sid, rinfo->rcv_flags, 86 | rinfo->rcv_ppid); 87 | } 88 | } 89 | 90 | message[length] = '\0'; 91 | printf("message received: %s\n", message); 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /simple/c/sctp/server_recvv/simpleSCTPServer_sctp_revv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RECVBUFSIZE 10 11 | 12 | int main() { 13 | 14 | int sd; 15 | 16 | sd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 17 | 18 | if(sd == -1) { 19 | perror("failure opening socket"); 20 | exit(EXIT_FAILURE); 21 | } 22 | 23 | struct sockaddr_in serverAddress; 24 | bzero((void *)&serverAddress, sizeof(serverAddress)); 25 | serverAddress.sin_family = AF_INET; 26 | serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); 27 | serverAddress.sin_port = htons(4242); 28 | 29 | int rb = bind(sd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)); 30 | if(rb == -1){ 31 | perror("bind error"); 32 | close(sd); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | struct sctp_initmsg initMsg; 37 | bzero((void *)&initMsg, sizeof(initMsg)); 38 | initMsg.sinit_num_ostreams = 100; 39 | initMsg.sinit_max_instreams = 100; 40 | initMsg.sinit_max_attempts = 0; 41 | initMsg.sinit_max_init_timeo = 0; 42 | 43 | setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)); 44 | 45 | const int on = 1; 46 | setsockopt(sd, IPPROTO_SCTP, SCTP_LISTEN_FIX, &on, sizeof(int)); 47 | 48 | int rl = listen(sd, 1); 49 | if(rl < 0) { 50 | perror("failed to listen for connection"); 51 | close(sd); 52 | exit(EXIT_FAILURE); 53 | } 54 | 55 | struct iovec iov[1]; 56 | char buf[RECVBUFSIZE]; 57 | iov->iov_base = buf; 58 | iov->iov_len = RECVBUFSIZE; 59 | 60 | if (setsockopt(sd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0) { 61 | perror("setsockopt SCTP_RECVRCVINFO"); 62 | exit(EXIT_FAILURE); 63 | } 64 | 65 | struct sctp_sndinfo sinfo; 66 | bzero(&sinfo, sizeof(struct sctp_sndinfo)); 67 | 68 | 69 | for(;;) { 70 | struct sockaddr_in client_addr; 71 | bzero((void*)&client_addr, sizeof(client_addr)); 72 | socklen_t fromlen, infolen; 73 | int flags = 0; 74 | unsigned int infotype = 0; 75 | struct sctp_rcvinfo rinfo; 76 | bzero(&rinfo, sizeof(struct sctp_rcvinfo)); 77 | infolen = sizeof(rinfo); 78 | fromlen = sizeof(client_addr); 79 | 80 | int length = sctp_recvv(sd, 81 | iov, 82 | 1, 83 | (struct sockaddr *) &client_addr, 84 | &fromlen, 85 | &rinfo, 86 | &infolen, 87 | &infotype, 88 | &flags); 89 | 90 | if(length == -1) { 91 | perror("error receiving message: "); 92 | exit(EXIT_FAILURE); 93 | } 94 | 95 | buf[length] = '\0'; 96 | printf("message received: %s\n", buf); 97 | 98 | } 99 | 100 | return EXIT_SUCCESS; 101 | } 102 | -------------------------------------------------------------------------------- /simple/c/tcp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(simple-echo) 3 | 4 | include_directories(SYSTEM "/usr/include") 5 | include_directories(${HEADER_FILES}) 6 | 7 | set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") 8 | 9 | set(CMAKE_C_FLAGS "-std=c99 -Wall") 10 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 11 | 12 | add_executable(simpleEchoTCPClientC client/simpleEchoTCPClient.c) 13 | add_executable(simpleEchoTCPServerC server/simpleEchoTCPServer.c ${HEADER_FILES}) 14 | 15 | target_link_libraries(simpleEchoTCPServerC myutillib) 16 | 17 | -------------------------------------------------------------------------------- /simple/c/tcp/client/simpleEchoTCPClient.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "simpleEchoTCPClient.h" 9 | 10 | 11 | int main() { 12 | 13 | // create socket 14 | int cd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 15 | if(cd == -1) { 16 | perror("failure creating socket"); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | char *host = "127.0.0.1"; 21 | 22 | // set server address 23 | struct sockaddr_in serverAddress; 24 | bzero((void *)&serverAddress, sizeof(serverAddress)); 25 | serverAddress.sin_family = AF_INET; 26 | serverAddress.sin_addr.s_addr = inet_addr(host); 27 | serverAddress.sin_port = htons(4242); 28 | 29 | // connect to server 30 | int co = connect(cd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)); 31 | 32 | if(co == -1) { 33 | perror("failure to connect"); 34 | close(cd); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | // int flag = 1; 39 | // setsockopt(cd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)); 40 | 41 | char *msg = "hello"; 42 | int length = strlen(msg); 43 | int n = send(cd, msg, length, 0); 44 | if(n < 0) { 45 | perror("error sending message"); 46 | close(cd); 47 | exit(EXIT_FAILURE); 48 | } 49 | 50 | char rmsg[7]; 51 | bzero(rmsg, sizeof(rmsg)); 52 | 53 | // receive message 54 | int m = read(cd, rmsg, sizeof(rmsg)); 55 | if(m < 0) { 56 | perror("error reading message"); 57 | close(cd); 58 | exit(EXIT_FAILURE); 59 | } 60 | 61 | printf("message received: %s", rmsg); 62 | close(cd); 63 | 64 | } -------------------------------------------------------------------------------- /simple/c/tcp/client/simpleEchoTCPClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Olivier Van Acker on 05/08/15. 3 | // 4 | 5 | #ifndef SCTP_EXAMPLES_SIMPLEECHOTCPCLIENT_H 6 | #define SCTP_EXAMPLES_SIMPLEECHOTCPCLIENT_H 7 | 8 | #endif //SCTP_EXAMPLES_SIMPLEECHOTCPCLIENT_H 9 | -------------------------------------------------------------------------------- /simple/c/tcp/server/simpleEchoTCPServer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "myutil.h" 7 | #include "simpleEchoTCPServer.h" 8 | 9 | #define MSG_SIZE 6 10 | 11 | int main() { 12 | 13 | // create socket 14 | int sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 15 | if(sd == -1) { 16 | perror("failed to create socket"); 17 | exit(EXIT_FAILURE); 18 | } 19 | 20 | // server address and port to listen on (0.0.0.0) (4242) 21 | struct sockaddr_in serverAddress; 22 | createAddress(INADDR_ANY, "4242", &serverAddress, "tcp"); 23 | 24 | // bind socket to address 25 | int rb = bind(sd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)); 26 | if(rb == -1) { 27 | perror("failed to bind"); 28 | close(sd); 29 | exit(EXIT_FAILURE); 30 | } 31 | 32 | // listen to socket 33 | int lr = listen(sd, 5); 34 | if(lr == -1) { 35 | perror("listen failed"); 36 | close(sd); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | char msg[MSG_SIZE]; 41 | char *rmsg = "thanks"; 42 | struct sockaddr_in clientAddress; 43 | socklen_t len = sizeof(clientAddress); 44 | 45 | for(;;) { 46 | // accept connections 47 | int cd = accept(sd, (struct sockaddr *)&clientAddress, &len); 48 | if(cd < 0) { 49 | perror("fail on accept"); 50 | exit(EXIT_FAILURE); 51 | } 52 | printf("connection accepted"); 53 | 54 | bzero(msg, MSG_SIZE); 55 | // read from client socket 56 | int n = read(cd, msg, MSG_SIZE); 57 | if(n < 0) { 58 | perror("error reading"); 59 | close(cd); 60 | continue; 61 | } 62 | 63 | printf("message received: %s", msg); 64 | 65 | // write return message 66 | int m = write(cd, rmsg, sizeof(rmsg)); 67 | if(m < 0) { 68 | perror("error writing"); 69 | } 70 | 71 | // close client socket 72 | close(cd); 73 | 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /simple/c/tcp/server/simpleEchoTCPServer.h: -------------------------------------------------------------------------------- 1 | #ifndef SCTP_EXAMPLES_SIMPLEECHOSERVER_H 2 | #define SCTP_EXAMPLES_SIMPLEECHOSERVER_H 3 | 4 | #endif //SCTP_EXAMPLES_SIMPLEECHOSERVER_H 5 | -------------------------------------------------------------------------------- /simple/go/sctp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(scpt-examples Go) 3 | 4 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 5 | 6 | add_executable(simpleSCTPClientGo client/simpleSCTPClient.go) 7 | add_executable(simpleSCTPServerGo server/simpleSCTPServer.go) 8 | -------------------------------------------------------------------------------- /simple/go/sctp/client/simpleSCTPClient.go: -------------------------------------------------------------------------------- 1 | package main 2 | import ( 3 | "log" 4 | "os" 5 | "net" 6 | ) 7 | 8 | func main() { 9 | 10 | saddr := "127.0.0.1:4242" 11 | addr, err := net.ResolveSCTPAddr("sctp", saddr) 12 | if err != nil { 13 | println(err) 14 | os.Exit(-1) 15 | } 16 | 17 | conn, err := net.DialSCTP("sctp", nil, addr) 18 | if err != nil { 19 | println("Error listening " + err.Error()) 20 | os.Exit(-1) 21 | } 22 | 23 | defer conn.Close() 24 | 25 | var message = "hello" 26 | bmessage := []byte(message) 27 | 28 | _, err = conn.WriteTo(bmessage, addr) 29 | if err != nil { 30 | log.Printf("WriteTo error: %v", err) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /simple/go/sctp/server/simpleSCTPServer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "os" 8 | ) 9 | 10 | 11 | func main() { 12 | 13 | saddr := "127.0.0.1:4242" 14 | c, err := net.ListenPacket("sctp", saddr) 15 | if err != nil { 16 | log.Printf("Error listening: %v", err) 17 | os.Exit(-1) 18 | } 19 | 20 | defer c.Close() 21 | 22 | for { 23 | msg := make([]byte, 100) 24 | length, _, err := c.ReadFrom(msg) 25 | log.Printf("[ Receive echo (%x bytes): stream = hu, " + 26 | "flags = hx, ppid = u ]\n", length, ) 27 | 28 | // printf("[ Receive echo (%u bytes): stream = %hu, " 29 | // "flags = %hx, ppid = %u ]\n", length, 30 | // rinfo->rcv_sid, rinfo->rcv_flags, 31 | // rinfo->rcv_ppid); 32 | // 33 | if err != nil { 34 | log.Printf("Error: %v ", err) 35 | break 36 | } 37 | fmt.Println("Message: " + string(msg)) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/myutil.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../include/myutil.h" 9 | 10 | #define SCTP_CONTROL_VEC_SIZE_RCV 16384 11 | 12 | 13 | char *program_name; 14 | 15 | void error( int status, int err, char *fmt, ... ) { 16 | fprintf( stderr, "%s: ", program_name ); 17 | if ( err ) 18 | fprintf( stderr, ": %s (%d)\n", strerror( err ), err ); 19 | if ( status ) 20 | exit( status ); 21 | } 22 | 23 | void createAddress(char *hname, char *sname, struct sockaddr_in *sap, char *protocol) { 24 | struct servent *sp; 25 | struct hostent *hp; 26 | char *endptr; 27 | short port; 28 | 29 | bzero( sap, sizeof( *sap ) ); 30 | sap->sin_family = AF_INET; 31 | if ( hname != NULL ) 32 | { 33 | if ( !inet_aton( hname, &sap->sin_addr ) ) 34 | { 35 | hp = gethostbyname( hname ); 36 | if ( hp == NULL ) 37 | error( 1, 0, "unknown host: %s\n", hname ); 38 | sap->sin_addr = *( struct in_addr * )hp->h_addr; 39 | } 40 | } 41 | else 42 | sap->sin_addr.s_addr = htonl( INADDR_ANY ); 43 | port = strtol( sname, &endptr, 0 ); 44 | if ( *endptr == '\0' ) 45 | sap->sin_port = htons( port ); 46 | else 47 | { 48 | sp = getservbyname( sname, protocol ); 49 | if ( sp == NULL ) 50 | error( 1, 0, "unknown service: %s\n", sname ); 51 | sap->sin_port = sp->s_port; 52 | } 53 | } 54 | 55 | void createInitMsg(struct sctp_initmsg *initmsg, 56 | u_int16_t num_ostreams, 57 | u_int16_t max_instreams, 58 | u_int16_t max_attempts, 59 | u_int16_t max_init_timeo) { 60 | 61 | bzero(initmsg, sizeof(*initmsg)); 62 | initmsg->sinit_num_ostreams = num_ostreams; 63 | initmsg->sinit_max_instreams = max_instreams; 64 | initmsg->sinit_max_attempts = max_attempts; 65 | initmsg->sinit_max_init_timeo = max_init_timeo; 66 | 67 | } 68 | 69 | void createSndRcvInfo(struct sctp_sndrcvinfo *sinfo, 70 | uint32_t ppid, 71 | uint16_t flags, 72 | uint16_t stream_no, 73 | uint32_t timetolive, 74 | uint32_t context) { 75 | 76 | bzero(sinfo, sizeof(*sinfo)); 77 | sinfo->sinfo_ppid = ppid; 78 | sinfo->sinfo_flags = flags; 79 | sinfo->sinfo_stream = stream_no; 80 | sinfo->sinfo_timetolive = timetolive; 81 | sinfo->sinfo_context = context; 82 | // TODO Research what they do and add 83 | // sinfo->sinfo_cumtsn 84 | // sinfo->sinfo_keynumber 85 | // sinfo->sinfo_keynumber_valid 86 | // sinfo->sinfo_ssn 87 | // sinfo->sinfo_tsn 88 | 89 | } 90 | 91 | void createMessageHdrSndRcv(struct msghdr *outmsghdr, 92 | struct sctp_initmsg *initmsg, 93 | struct sctp_sndrcvinfo *sinfo, 94 | struct sockaddr *to, 95 | socklen_t tolen, 96 | const void *msg, 97 | size_t len) { 98 | 99 | 100 | 101 | char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; 102 | struct cmsghdr *cmsg; 103 | 104 | // server address 105 | outmsghdr->msg_name = to; 106 | outmsghdr->msg_namelen = tolen; 107 | 108 | // message 109 | struct iovec iov; 110 | outmsghdr->msg_iov = &iov; 111 | outmsghdr->msg_iovlen = 1; 112 | iov.iov_base = (void *) msg; 113 | iov.iov_len = len; 114 | 115 | outmsghdr->msg_control = cmsgbuf; 116 | outmsghdr->msg_controllen = sizeof(cmsgbuf); 117 | outmsghdr->msg_flags = 0; 118 | 119 | cmsg = CMSG_FIRSTHDR(outmsghdr); 120 | cmsg->cmsg_level = IPPROTO_SCTP; 121 | cmsg->cmsg_type = SCTP_SNDRCV; 122 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 123 | 124 | outmsghdr->msg_controllen = cmsg->cmsg_len; 125 | memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); 126 | 127 | } 128 | 129 | void createMessageHdrRcv(struct msghdr *msg, 130 | void *message, 131 | size_t mlen) { 132 | 133 | char cbuf[SCTP_CONTROL_VEC_SIZE_RCV]; 134 | bzero(msg, sizeof(msg)); 135 | bzero(cbuf, sizeof(cbuf)); 136 | msg->msg_control = &cbuf; 137 | msg->msg_controllen = sizeof(cbuf); 138 | 139 | struct iovec iov[1]; 140 | iov->iov_base = message; 141 | iov->iov_len = RECVBUFSIZE; 142 | 143 | // Message header 144 | msg->msg_iov = iov; 145 | msg->msg_iovlen = 1; 146 | 147 | } 148 | --------------------------------------------------------------------------------