📄 sctp_darn.c
字号:
/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999 Cisco * Copyright (c) 1999, 2000, 2001 Motorola * Copyright (c) 2001 Nokia * Copyright (c) 2001 La Monte H.P. Yarroll * * The SCTP implementation 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. * * The SCTP implementation 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 * * Any bugs reported to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * * Written or modified by: * La Monte H.P. Yarroll <piggy@acm.org> * Karl Knutson <karl@athena.chicago.il.us> * Hui Huang <hui.huang@nokia.com> * Daisy Chang <daisyc@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com> *//* This is a userspace test application for the SCTP kernel * implementation state machine. It is vaguely inspired by Stevens' * program "sock". * * It has the limited ability to send messages and to listen for messages * sent via SCTP. */#include <stdio.h>#include <fcntl.h>#include <stdlib.h>//#define _GNU_SOURCE#include <getopt.h>#include <netdb.h>#include <ctype.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#include <sys/errno.h>#include <sys/param.h>#include <sys/poll.h>#include <arpa/inet.h>#include <errno.h>#include <net/if.h>#include <netinet/sctp.h>#include <unistd.h>#include <string.h>#include <signal.h>#include "sctp_darn.h"char *TCID = __FILE__;int TST_TOTAL = 1;int TST_CNT = 0;#define GEN_DATA_FIRST 0x21#define GEN_DATA_LAST 0x7e/* Display an IPv4 address in readable format. */#define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3]/* Display an IPv6 address in readable format. */#define NIP6(addr) \ ntohs((addr).s6_addr16[0]), \ ntohs((addr).s6_addr16[1]), \ ntohs((addr).s6_addr16[2]), \ ntohs((addr).s6_addr16[3]), \ ntohs((addr).s6_addr16[4]), \ ntohs((addr).s6_addr16[5]), \ ntohs((addr).s6_addr16[6]), \ ntohs((addr).s6_addr16[7])/* These are the global options. */char *local_host = NULL;int local_port = 0;char *remote_host = NULL;int remote_port = 0;command_t command = COMMAND_NONE;struct sockaddr *bindx_add_addrs = NULL;int bindx_add_count = 0;struct sockaddr *bindx_rem_addrs = NULL;int bindx_rem_count = 0;struct sockaddr *connectx_addrs = NULL;int connectx_count = 0;int interactive_mode = 0;int poll_skn = 0;int nonblocking = 0;int opt_space = 0;char gen_data = GEN_DATA_FIRST;char *inter_outbuf = NULL;int inter_outlen = 0;int inter_sk = 0;int poll_snd_size = 0;int use_poll = 0;int socket_type = SOCK_SEQPACKET;sctp_assoc_t associd = 0;int echo = 0;char *interface = "eth0";int if_index = 0;sockaddr_storage_t remote_addr;sa_family_t ra_family; /* What family is remote_addr? */int ra_len = 0; /* How long is remote_addr? */void *ra_raw; /* This is the addr part of remote_addr. */int new_connection = 1;enum inter_cmd_num { INTER_SND = 0, INTER_RCV, INTER_SNDBUF, INTER_RCVBUF, INTER_BINDX_ADD, INTER_BINDX_REM, INTER_SET_PRIM, INTER_SET_PEER_PRIM, INTER_SHUTDOWN, INTER_ABORT, INTER_NODELAY, INTER_MAXSEG};enum shutdown_type { SHUTDOWN_ABORT = 0, SHUTDOWN_SHUTDOWN};struct inter_entry { char *cmd; int cmd_num;};struct inter_entry inter_commands[] = { {"snd", INTER_SND}, {"rcv", INTER_RCV}, {"sndbuf", INTER_SNDBUF}, {"rcvbuf", INTER_RCVBUF}, {"bindx-add", INTER_BINDX_ADD}, {"bindx-rem", INTER_BINDX_REM}, {"primary", INTER_SET_PRIM}, {"peer_primary", INTER_SET_PEER_PRIM}, {"shutdown", INTER_SHUTDOWN}, {"abort", INTER_ABORT}, {"nodelay", INTER_NODELAY}, {"maxseg", INTER_MAXSEG}, {NULL, -1},};#define POLL_SK_MAX 256 /* The max number of sockets to select/poll. */int poll_sks[POLL_SK_MAX]; /* The array for using select(). */struct pollfd poll_fds[POLL_SK_MAX]; /* The array for using poll(). */#define POLL_SND_SIZE 16384 /* Default message size in the poll mode. */struct sockaddr *append_addr(const char *parm, struct sockaddr *addrs, int *ret_count) ;int build_endpoint(char *argv0, int portnum);static int parse_inter_commands(char *, char *, int);static void snd_func(char *);static void sndbuf_func(char *, int, int, int);static void rcvbuf_func(char *, int, int, int);static struct sockaddr *get_bindx_addr(char *, int *);static int bindx_func(char *, int, struct sockaddr *, int, int, int);static int connectx_func(char *, int, struct sockaddr *, int);static void primary_func(char *, int, char *, int);static void peer_primary_func(char *, int, char *, int);static int nodelay_func(char *, int, int val, int set);static int maxseg_func(char *, int, int val, int set);static int shutdown_func(char *argv0, int *skp, int shutdown_type);static int test_sk_for_assoc(int sk, sctp_assoc_t assoc_id);static char * gen_message(int);static sctp_assoc_t test_recv_assoc_change(int);static sctp_assoc_t test_verify_assoc_change(struct msghdr *);void print_addr_buf(void * laddrs, int n_laddrs);int print_sockaddr(struct sockaddr *sa_addr);intmain(int argc, char *argv[]) { int sk = -1; int error = 0; int i; signal(SIGPIPE, SIG_IGN); parse_arguments(argc, argv); switch(command) { case COMMAND_NONE: fprintf(stderr, "%s: Please specify a command.\n", argv[0]); exit(1); break; case COMMAND_LISTEN: sk = build_endpoint(argv[0], local_port); error = command_listen(argv[0], sk); break; case COMMAND_SEND: sk = build_endpoint(argv[0], local_port); error = command_send(argv[0], &sk); break; case COMMAND_POLL: if (use_poll) { for (i = 0; i < poll_skn; i++) { poll_fds[i].fd = build_endpoint(argv[0], local_port + i); } } else { for (i = 0; i < poll_skn; i++) { poll_sks[i] = build_endpoint(argv[0], local_port + i); } } error = command_poll(argv[0]); break; default: fprintf(stderr, "%s: illegal command %d\n", argv[0], command); exit(1); } /* Shut down the link. */ if (COMMAND_POLL != command) { close(sk); } else { /* Shutdown all links. */ if (use_poll) { for (i = 0; i < poll_skn; i++) { close(poll_fds[i].fd); } } else { for (i = 0; i < poll_skn; i++) { close(poll_sks[i]); } } } exit(error);}/******************************************************************** * 2nd Level Abstractions ********************************************************************/voidparse_arguments(int argc, char *argv[]) { int option_index = 0; int c; struct sockaddr *tmp_addrs = NULL; static struct option long_options[] = { {"local", 1, 0, 1}, {"local-port", 1, 0, 2}, {"remote", 1, 0, 3}, {"remote-port", 1, 0, 4}, {"listen", 0, 0, 10}, {"send", 0, 0, 11}, {"bindx-add", 1, 0, 15}, {"bindx-rem", 1, 0, 16}, {"use-poll", 0, 0, 20}, {"echo", 0, 0, 'e'}, {"interface", optional_argument, 0, 5,}, {"connectx", 1, 0, 17}, {0, 0, 0, 0} }; /* Parse the arguments. */ while (1) { c = getopt_long (argc, argv, "B:H:IP:b:h:i:p:lm:nstz:ec:", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); break; case 1: /* local host */ case 'H': local_host = optarg; break; case 2: /* local port */ case 'P': local_port = atoi(optarg); break; case 3: /* remote host */ case 'h': remote_host = optarg; break; case 4: /* remote port */ case 'p': remote_port = atoi(optarg); break; case 5: /* interface for sin6_scope_id */ if (optarg) interface = optarg; if_index = if_nametoindex(interface); if (!if_index) { printf("Interface %s unknown\n", interface); exit(1); } break; /* COMMANDS */ case 10: /* listen */ case 'l': if (command) { fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]); exit(1); } else { command = COMMAND_LISTEN; } break; case 11: /* send */ case 's': if (command) { fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]); exit(1); } else { command = COMMAND_SEND; } break; case 15: /* bindx_add */ case 'B': tmp_addrs = append_addr(optarg, bindx_add_addrs, &bindx_add_count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, optarg); fprintf(stderr, "\n"); exit(2); } bindx_add_addrs = tmp_addrs; break; case 16: /* bindx_rem */ case 'b': tmp_addrs = append_addr(optarg, bindx_rem_addrs, &bindx_rem_count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, optarg); fprintf(stderr, "\n"); exit(2); } bindx_rem_addrs = tmp_addrs; break; case 17: /* connectx */ case 'c': tmp_addrs = append_addr(optarg, connectx_addrs, &connectx_count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, optarg); fprintf(stderr, "\n"); exit(2); } connectx_addrs = tmp_addrs; break; case 20: /* use-poll */ use_poll = 1; break; case 'I': interactive_mode = 1; break; case 'i': command = COMMAND_POLL; poll_skn = atoi(optarg); if (poll_skn <= 0 || poll_skn > POLL_SK_MAX) { fprintf(stderr, "Too many sockets for "); fprintf(stderr, "for polling\n"); exit(2); } break; case 'm': opt_space = atoi(optarg); break; case 'n': nonblocking = 1; break; case 't': socket_type = SOCK_STREAM; break; case 'z': poll_snd_size = atoi(optarg); if (poll_snd_size <= 0) { fprintf(stderr, "Bad message size.\n"); exit(2); } break; case 'e': echo = 1; break; case '?': usage(argv[0]); exit(1); default: printf ("%s: unrecognized option 0%c\n", argv[0], c); usage(argv[0]); exit(1); } } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf (stderr, "\n"); usage(argv[0]); exit(1); } if (NULL == local_host) { fprintf(stderr, "%s: You MUST provide a local host.\n", argv[0]); usage(argv[0]); exit(1); } if (command == COMMAND_SEND && NULL == remote_host && connectx_count == 0) { fprintf(stderr, "%s: You MUST provide a remote host for sending.\n", argv[0]); usage(argv[0]); exit(1); } if (remote_host != NULL && connectx_count != 0) { fprintf(stderr, "%s: You can not provide both -h and -c options.\n", argv[0]); usage(argv[0]); exit(1); }} /* parse_arguments() *//* Set up the local endpoint. */intbuild_endpoint(char *argv0, int portnum){ int retval; struct hostent *hst; sockaddr_storage_t local_addr; sa_family_t la_family; /* What family is local_addr? */ int la_len; /* How long is local_addr? */ void *la_raw; /* This is the addr part of local_addr. */ int error; struct sctp_event_subscribe subscribe; /* Get the transport address for the local host name. */ hst = gethostbyname(local_host); if (hst == NULL) { hst = gethostbyname2(local_host, AF_INET6); } if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host); exit(1); } la_family = hst->h_addrtype; switch (la_family) { case AF_INET: la_len = sizeof(local_addr.v4); la_raw = &local_addr.v4.sin_addr; local_addr.v4.sin_port = htons(portnum); local_addr.v4.sin_family = AF_INET; break; case AF_INET6: la_len = sizeof(local_addr.v6); la_raw = &local_addr.v6.sin6_addr; local_addr.v6.sin6_port = htons(portnum); local_addr.v6.sin6_family = AF_INET6; local_addr.v6.sin6_scope_id = if_index; break; default: fprintf(stderr, "Invalid address type.\n"); exit(1); break; } memcpy(la_raw, hst->h_addr_list[0], hst->h_length); /* Create the local endpoint. */ retval = socket(la_family, socket_type, IPPROTO_SCTP); if (retval < 0) { fprintf(stderr, "%s: failed to create socket: %s.\n", argv0, strerror(errno)); exit(1); } if (SOCK_SEQPACKET == socket_type) { memset(&subscribe, 0, sizeof(subscribe)); subscribe.sctp_data_io_event = 1; subscribe.sctp_association_event = 1; error = setsockopt(retval, SOL_SCTP, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)); if (error) { fprintf(stderr, "SCTP_EVENTS: error: %d\n", error); exit(1); } } /* Bind this socket to the test port. */ error = bind(retval, &local_addr.sa, la_len); if (error != 0) { fprintf(stderr, "%s: can not bind to %s:%d: %s.\n", argv0, local_host, portnum, strerror(errno)); exit(1); } /* Do we need to do bindx() to add any additional addresses? */ if (bindx_add_addrs) { if (0 != bindx_func(argv0, retval, bindx_add_addrs, bindx_add_count, SCTP_BINDX_ADD_ADDR, portnum)) { fprintf(stderr, "bindx_func (add) failed.\n"); exit(1); } } /* if (bindx_add_addrs) */ /* Do we need to do bindx() to remove any bound addresses? */ if (bindx_rem_addrs) { if (0 != bindx_func(argv0, retval, bindx_rem_addrs, bindx_rem_count, SCTP_BINDX_REM_ADDR, portnum)) { fprintf(stderr, "bindx_func (remove) failed.\n"); exit(1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -