📄 sctp_test.c
字号:
/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999 Cisco * Copyright (c) 1999, 2000, 2001 Motorola * Copyright (c) 2001-2002 Nokia * Copyright (c) 2001 La Monte H.P. Yarroll * * This is a userspace test application for the SCTP kernel * implementation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ^^^^^^^^^^^^^^^^^^^^^^^^ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers <lksctp-developers@lists.sourceforge.net> * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Written or modified by: * Hui Huang <hui.huang@nokia.com> * Sridhar Samudrala <samudrala@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com> * Ryan Layer <rmlayer@us.ibm.com> */#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <time.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#include <sys/errno.h>#include <errno.h>#include <netinet/sctp.h>#include <string.h>#include <arpa/inet.h>#include <sys/wait.h>#include <sys/param.h>#include <fcntl.h>#include <netdb.h>#include <net/if.h>#include <sys/resource.h>#define REALLY_BIG 65536#define SERVER 0#define CLIENT 1#define MIXED 2#define NOT_DEFINED 666#define REPEAT 10#define BIG_REPEAT 1000000#define MAX_BIND_RETRYS 10#define BODYSIZE 10#define MSG_CNT 10 /* If this is changed the msg_sizes array needs to be modified accordingly. */#define DEFAULT_MAX_WINDOW 32768#define DEFAULT_MIN_WINDOW 1500#define DEBUG_NONE 0#define DEBUG_MIN 1#define DEBUG_MAX 2#define STREAM_PATTERN_SEQUENTIAL 0#define STREAM_PATTERN_RANDOM 1#define ORDER_PATTERN_UNORDERED 0#define ORDER_PATTERN_ORDERED 1#define ORDER_PATTERN_ALTERNATE 2#define ORDER_PATTERN_RANDOM 3#define ASSOC_PATTERN_SEQUENTIAL 0#define ASSOC_PATTERN_RANDOM 1#define NCASES 6#define MAX_POLL_SKS 256#define DEBUG_PRINT(level, print_this...) \{ \ if (debug_level >= level) { \ fprintf(stdout, print_this); \ fflush(stdout); \ } \} /* DEBUG_PRINT *//* Convenience structure to determine space needed for cmsg. */typedef union { struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcvinfo;} _sctp_cmsg_data_t;#ifdef __FreeBSD__typedef union { int raw; struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcv;} sctp_cmsg_data_t;#endif#define CMSG_SPACE_INITMSG (CMSG_SPACE(sizeof(struct sctp_initmsg)))#define CMSG_SPACE_SNDRCV (CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)))typedef struct { int rem_port; int order_state; int stream_state; int msg_cnt; int msg_sent; int cycle;} _assoc_state;typedef struct { int sk; int assoc_i; _assoc_state *assoc_state;} _poll_sks;char *local_host = NULL;int local_port = 0;char *remote_host = NULL;int remote_port = 0;/* struct sockaddr_in s_rem, s_loc; */struct sockaddr_storage s_rem, s_loc;int r_len, l_len;int test_case = 0;int size_arg = 0;int xflag = 0;int debug_level = DEBUG_MAX;int do_exit = 1;int stream_pattern = STREAM_PATTERN_SEQUENTIAL;int stream_state = 0;int order_pattern = ORDER_PATTERN_UNORDERED;int order_state = 0;int max_stream = 0;int seed = 0;int max_msgsize = DEFAULT_MAX_WINDOW;int assoc_pattern = ASSOC_PATTERN_SEQUENTIAL;int repeat_count = 0;int listeners = 0;int tosend = 0;_poll_sks poll_sks[MAX_POLL_SKS];int repeat = REPEAT;int msg_cnt = MSG_CNT;int drain = 0;unsigned char msg[] = "012345678901234567890123456789012345678901234567890";static int msg_sizes[NCASES][MSG_CNT] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1452, 2904, 4356, 1452, 2904, 4356, 1452, 2904, 4356, 1452}, {1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453}, {1, 1453, 32768, 1, 1453, 32768, 1, 1453, 32768, 1}, {1, 1000, 2000, 3000, 5000, 10000, 15000, 20000, 25000, 32768}, {32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768}, };static const char *sac_state_tbl[] = { "COMMUNICATION_UP", "COMMUNICATION_LOST", "RESTART", "SHUTDOWN_COMPLETE", "CANT_START_ASSOCICATION"};void usage(char *argv0){ fprintf(stderr, "\nusage:\n"); fprintf(stderr, " server:\n"); fprintf(stderr, " %8s -H local-addr -P local-port -l [-d level] [-x]\n" "\t [-L num-ports] [-S num-ports]\n" "\t [-a assoc-pattern]\n" "\t [-i interface]\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, " client:\n"); fprintf(stderr, " %8s -H local-addr -P local-port -h remote-addr\n" "\t -p remote-port -s [-c case ] [-d level]\n" "\t [-x repeat] [-o order-pattern] ream-pattern]\n" "\t [-M max-stream] [-r rand-seed]\n" "\t [-m max-msgsize]\n" "\t [-L num-ports] [-S num-ports]\n" "\t [-a assoc-pattern]\n" "\t [-i interface]\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, "\t-a assoc_pattern in the mixed mode\n"); fprintf(stderr, "\t 0 = sequential ascending(default)\n"); fprintf(stderr, "\t 1 = random\n"); fprintf(stderr, "\t-d debug\n"); fprintf(stderr, "\t 0 = none\n"); fprintf(stderr, "\t 1 = min(default)\n"); fprintf(stderr, "\t 2 = max\n"); fprintf(stderr, "\t-c testcase\n"); fprintf(stderr, "\t 0 = 1 byte packets.\n"); fprintf(stderr, "\t 1 = 1452 byte packets.\n"); fprintf(stderr, "\t (fragmentation point for an i/f with "); fprintf(stderr, "1500 as mtu.)\n"); fprintf(stderr, "\t 2 = 1453 byte packets.\n"); fprintf(stderr, "\t (min. size at which fragmentation occurs\n"); fprintf(stderr, "\t for an i/f with 1500 as mtu.)\n"); fprintf(stderr, "\t 3 = Sequence of 1, 1453, 32768 byte packets.\n"); fprintf(stderr, "\t 4 = Sequence of following size packets.\n"); fprintf(stderr, "\t (1, 1000, 2000, 3000, 5000, 10000,"); fprintf(stderr, "15000, 20000, 25000, 32768)\n"); fprintf(stderr, "\t 5 = 32768 byte packets.\n"); fprintf(stderr, "\t (default max receive window size.)\n"); fprintf(stderr, "\t 6 = random size packets.\n"); fprintf(stderr, "\t -ve value = Packets of specifed size.\n"); fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n"); fprintf(stderr, "\t-x number of repeats\n"); fprintf(stderr, "\t-o order-pattern\n"); fprintf(stderr, "\t 0 = all unordered(default) \n"); fprintf(stderr, "\t 1 = all ordered \n"); fprintf(stderr, "\t 2 = alternating \n"); fprintf(stderr, "\t 3 = random\n"); fprintf(stderr, "\t-t stream-pattern\n"); fprintf(stderr, "\t 0 = sequential ascending(default)\n"); fprintf(stderr, "\t 1 = random\n"); fprintf(stderr, "\t-M max-stream (default value 0)\n"); fprintf(stderr, "\t-r seed (default 0, use time())\n"); fprintf(stderr, "\t-L num-ports (default value 0). Run the mixed mode\n"); fprintf(stderr, "\t-S num-ports (default value 0). Run the mixed mode\n"); fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n"); fprintf(stderr, "\n"); fflush(stderr);} /* usage() */void *build_msg(int len){ int i = len - 1; int n; char *msg_buf, *p; msg_buf = malloc(len); if (NULL == msg_buf) { fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n"); exit(1); } p = msg_buf; do { n = ((i > 50)?50:i); memcpy(p, msg, ((i > 50)?50:i)); p += n; i -= n; } while (i > 0); msg_buf[len-1] = '\0'; return(msg_buf);} /* build_msg() */static intprint_cmsg(int type, sctp_cmsg_data_t *data){ switch(type) { case SCTP_INIT: DEBUG_PRINT(DEBUG_MAX, "\tINIT\n"); if (DEBUG_MAX == debug_level) { printf("\t\tsinit_num_ostreams=%d ", data->init.sinit_num_ostreams); printf("sinit_max_instreams=%d ", data->init.sinit_max_instreams); printf("sinit_max_attempts=%d ", data->init.sinit_max_attempts); printf("sinit_max_init_timeo=%d\n", data->init.sinit_max_init_timeo); } break; case SCTP_SNDRCV: DEBUG_PRINT(DEBUG_MAX, "\t SNDRCV"); if (DEBUG_MAX == debug_level) { printf("(stream=%u ", data->sndrcv.sinfo_stream); printf("ssn=%u ", data->sndrcv.sinfo_ssn); printf("tsn=%u ", data->sndrcv.sinfo_tsn); printf("flags=0x%x ", data->sndrcv.sinfo_flags); printf("ppid=%u\n", data->sndrcv.sinfo_ppid); printf("cumtsn=%u\n", data->sndrcv.sinfo_cumtsn); } break; default: DEBUG_PRINT(DEBUG_MIN, "\tUnknown type: %d\n", type); break; } fflush(stdout); return 0;} /* print_cmsg() *//* This function prints the message. */static intprint_message(const int sk, struct msghdr *msg, size_t msg_len) { struct cmsghdr *scmsg; sctp_cmsg_data_t *data; int i; if (!(MSG_NOTIFICATION & msg->msg_flags)) { int index = 0; DEBUG_PRINT(DEBUG_MIN, "Data %d bytes.", msg_len); DEBUG_PRINT(DEBUG_MAX, " First %d bytes: ", (msg_len < BODYSIZE)?msg_len:BODYSIZE); /* Make sure that everything is printable and that we * are NUL terminated... */ while ( msg_len > 0 ) { char *text, tmptext[BODYSIZE]; int len; memset(tmptext, 0x0, BODYSIZE); text = msg->msg_iov[index].iov_base; len = msg->msg_iov[index].iov_len; if (msg_len == 1 && text[0] == 0) { DEBUG_PRINT(DEBUG_MIN, "<empty> text[0]=%d", text[0]); break; } if ( len > msg_len ) { /* text[(len = msg_len) - 1] = '\0'; */ text[(len = msg_len)] = '\0'; } if ( (msg_len -= len) > 0 ) { index++; } for (i = 0; i < len - 1; ++i) { if (!isprint(text[i])) text[i] = '.'; } strncpy(tmptext, text, BODYSIZE); tmptext[BODYSIZE-1] = '\0'; DEBUG_PRINT(DEBUG_MAX, "%s", tmptext); } DEBUG_PRINT(DEBUG_MIN, "\n"); fflush(stdout); } else { /* if(we have notification) */ struct sctp_assoc_change *sac; struct sctp_send_failed *ssf; struct sctp_paddr_change *spc; struct sctp_remote_error *sre; union sctp_notification *snp; char addrbuf[INET6_ADDRSTRLEN]; const char *ap; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; int index = 0; snp = (union sctp_notification *)msg->msg_iov[index].iov_base; DEBUG_PRINT(DEBUG_MIN, "Notification:"); switch (snp->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: sac = &snp->sn_assoc_change; DEBUG_PRINT(DEBUG_MIN, " SCTP_ASSOC_CHANGE(%s)\n", sac_state_tbl[sac->sac_state]); DEBUG_PRINT(DEBUG_MAX, "\t\t(assoc_change: state=%hu, " "error=%hu, instr=%hu " "outstr=%hu)\n", sac->sac_state, sac->sac_error, sac->sac_inbound_streams, sac->sac_outbound_streams); break; case SCTP_PEER_ADDR_CHANGE: spc = &snp->sn_paddr_change; DEBUG_PRINT(DEBUG_MIN, " SCTP_PEER_ADDR_CHANGE\n"); if (spc->spc_aaddr.ss_family == AF_INET) { sin = (struct sockaddr_in *) &spc->spc_aaddr; ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET6_ADDRSTRLEN); } else { sin6 = (struct sockaddr_in6 *) &spc->spc_aaddr; ap = inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN); } DEBUG_PRINT(DEBUG_MAX, "\t\t(peer_addr_change: %s " "state=%d, error=%d)\n", ap, spc->spc_state, spc->spc_error); break; case SCTP_SEND_FAILED: ssf = &snp->sn_send_failed; DEBUG_PRINT(DEBUG_MIN, " SCTP_SEND_FAILED\n"); DEBUG_PRINT(DEBUG_MAX, "\t\t(sendfailed: len=%hu " "err=%d)\n", ssf->ssf_length, ssf->ssf_error); break; case SCTP_REMOTE_ERROR: sre = &snp->sn_remote_error; DEBUG_PRINT(DEBUG_MIN, " SCTP_REMOTE_ERROR\n"); DEBUG_PRINT(DEBUG_MAX, "\t\t(remote_error: err=%hu)\n", ntohs(sre->sre_error)); break; case SCTP_SHUTDOWN_EVENT: DEBUG_PRINT(DEBUG_MIN, " SCTP_SHUTDOWN_EVENT\n"); break; default: DEBUG_PRINT(DEBUG_MIN, " Unknown type: %hu\n", snp->sn_header.sn_type); break; } fflush(stdout); return 1; } /* notification received */ for (scmsg = CMSG_FIRSTHDR(msg); scmsg != NULL; scmsg = CMSG_NXTHDR(msg, scmsg)) { data = (sctp_cmsg_data_t *)CMSG_DATA(scmsg); if (debug_level) print_cmsg(scmsg->cmsg_type, data); } fflush(stdout); return 0;} /* print_message() */int socket_r(void){ struct sctp_event_subscribe subscribe; int sk, error; DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_SEQPACKET, IPPROTO_SCTP)"); if ((sk = socket(s_loc.ss_family, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0 ) { if (do_exit) { fprintf(stderr, "\n\n\t\t*** socket: failed to create" " socket: %s ***\n", strerror(errno)); exit(1); } else { return -1; } } DEBUG_PRINT(DEBUG_MIN, " -> sk=%d\n", sk); memset(&subscribe, 0, sizeof(subscribe)); subscribe.sctp_data_io_event = 1; subscribe.sctp_association_event = 1; error = setsockopt(sk, SOL_SCTP, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)); if (error) { fprintf(stderr, "SCTP_EVENTS: error: %d\n", error); exit(1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -