📄 sctp_xconnect.c
字号:
/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2003 * * 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 given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * * Written or modified by: * Ryan Layer <rmlayer@us.ibm.com> */#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#include <errno.h>#include <netinet/sctp.h>#include <sctputil.h>#include <netdb.h>#include <getopt.h>char *TCID = __FILE__;int TST_TOTAL = 1;int TST_CNT = 0;#define MAXHOSTNAME 64#define MAXCLIENTNUM 10000#define TRUE 1#define SERVER 1#define CLIENT 0#define NOT_DEFINED -1int mode = NOT_DEFINED;int assoc_num, remote_port, local_port;int active = 0;char *local_host = NULL;char *remote_host = NULL;sockaddr_storage_t client_loop, server_loop;struct hostent *hst;void usage(char *argv0);void parse_arguments(int argc, char*argv[]);void data_received(struct msghdr *inmessage, int len, int stream, int server_socket);int event_received(struct msghdr *inmessage, int assoc_num);void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds);void server_mode(void);void client_mode(void);/* Print the syntax/usage */void usage(char *argv0){ printf("usage: %s -H localhost -P localport -l|c [-h remotehost]\n" "\t\t[-p remoteport] [-a] [-n <cnt>]\n" " -H\t\tspecify a local address.\n" " -P\t\tspecify the local port number to be used\n" " -l\t\trun in server mode.\n" " -c\t\trun in client mode.\n" " -h\t\tspecify the peer address.\n" " -p\t\tspecify the port number for the peer address.\n" " -a\t\tactively generate traffic with the server.\n" " -n\t\tspecify the number of associations to create.\n", argv0);}/* Parse command line options */void parse_arguments(int argc, char*argv[]) { int c; while ((c = getopt(argc, argv, ":H:P:ach:ln:p:")) >= 0) { switch (c) { case 'H': local_host = optarg; break; case 'P': local_port = atoi(optarg); break; case 'c': if (mode == NOT_DEFINED) mode = CLIENT; else { usage(argv[0]); exit(0); } break; case 'a': active = 1; break; case 'h': remote_host = optarg; break; case 'l': if (mode == NOT_DEFINED) mode = SERVER; else { usage(argv[0]); exit(0); } break; case 'n': assoc_num = atoi(optarg); break; case 'p': remote_port = atoi(optarg); break; default: usage(argv[0]); exit(0); } } /* while() */ if (mode == CLIENT) { if (assoc_num) { if (assoc_num > MAXCLIENTNUM) { printf("The number of associations indicated " "is greater than the"); printf("max number of associations " "allowed(%d).", MAXCLIENTNUM); usage(argv[0]); exit(0); } } else assoc_num = 1; if (remote_host && remote_port) { hst = gethostbyname(remote_host); memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0], sizeof(server_loop.v4.sin_addr)); server_loop.v4.sin_family = AF_INET;server_loop.v4.sin_port = htons(remote_port); } else { printf("Remote host and remote port must be defined " "in client mode\n"); usage(argv[0]); exit(0); } if (local_host) { hst = gethostbyname(local_host); memcpy(&client_loop.v4.sin_addr, hst->h_addr_list[0], sizeof(client_loop.v4.sin_addr)); } else client_loop.v4.sin_addr.s_addr = INADDR_ANY; if (local_port) client_loop.v4.sin_port = htons(local_port); else client_loop.v4.sin_port = 0; client_loop.v4.sin_family = AF_INET; } else if (mode == SERVER) { if (active) { printf("This option if for client use only"); usage(argv[0]); exit(0); } if (remote_host || remote_port) { printf("Remote values not needed in server mode.\n"); usage(argv[0]); exit(0); } if (local_host) { hst = gethostbyname(local_host); memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0], sizeof(server_loop.v4.sin_addr)); } else server_loop.v4.sin_addr.s_addr = INADDR_ANY; if (local_port) server_loop.v4.sin_port = htons(local_port); else { printf("Specify a local port in server mode.\n"); usage(argv[0]); exit(0); } server_loop.v4.sin_family = AF_INET; } else { printf("Must assisgn a client or server mode.\n"); usage(argv[0]); exit(0); }} /* parse_arguments() *//* Handle data recieved */void data_received(struct msghdr *inmessage, int len, int stream, int socket) { int ppid, error; char *ping = "PING"; if (mode == SERVER) { ppid = rand(); error = sctp_sendmsg(socket, inmessage->msg_iov->iov_base, len, (struct sockaddr *)inmessage->msg_name, inmessage->msg_namelen, ppid, 0, stream, 0, 0); if (error < 0) { printf("Send Failure: %s.\n", strerror(errno)); DUMP_CORE; } } else { ppid = rand(); printf("Data Received by socket #: %d.\n", socket); printf("\tMessage = %s\n", (char *)inmessage->msg_iov->iov_base); if (active) { sctp_sendmsg(socket, ping, strlen(ping) + 1, (struct sockaddr *)&server_loop, sizeof (server_loop), ppid, 0, stream, 0, 0); } }}/* This will print what type of SCTP_ASSOC_CHANGE state that was recieved */void print_sctp_sac_state(struct msghdr *msg) { char *data; union sctp_notification *sn; if (msg->msg_flags & MSG_NOTIFICATION) { data = (char *)msg->msg_iov[0].iov_base; sn = (union sctp_notification *)data; switch (sn->sn_assoc_change.sac_state) { case SCTP_COMM_UP: printf("SCTP_COMM_UP\n"); break; case SCTP_COMM_LOST: printf("SCTP_COMM_LOST\n"); break; case SCTP_RESTART: printf("SCTP_RESTART"); break; case SCTP_SHUTDOWN_COMP: printf("SCTP_SHUTDOWN_COMP\n"); break; case SCTP_CANT_STR_ASSOC: printf("SCTP_CANT_STR_ASSOC\n"); break; default: break; } }} /* void print_sctp_sac_state() *//* Tests what type of MSG_NOTIFICATION has been received.* For now this fucntion only works with SCTP_ASSOC_CHANGE * types, but can be easily expanded.** Will return...* -1 if the msg_flags is not MSG_NOTIFICATION* 0 if the MSG_NOTIFICATION type differs from the type* passed into the additional variable* 1 if the MSG_NOTIFICATION type matches the type* passed into the additional variable*/int test_check_notification_type(struct msghdr *msg, uint16_t sn_type, uint32_t additional) { char *data; union sctp_notification *sn; if (!(msg->msg_flags & MSG_NOTIFICATION)) { return -1; } else { /* Fixup for testframe. */ data = (char *)msg->msg_iov[0].iov_base; sn = (union sctp_notification *)data; if (sn->sn_header.sn_type != sn_type) return 0; else if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) if (sn->sn_assoc_change.sac_state == additional) return 1; return 0; }}/* Determine the type of event and make correct adjustments to the* association count*/int event_received(struct msghdr *inmessage, int assoc_num) { int error; printf("Event Received\n"); print_sctp_sac_state(inmessage); if (mode == SERVER) { /* Test type of Event */ error = test_check_notification_type(inmessage, SCTP_ASSOC_CHANGE, SCTP_COMM_UP); if (error > 0) { assoc_num++; printf("Assosiation Established: count = %d.\n", assoc_num); } else { error = test_check_notification_type(inmessage, SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); if (error > 0) { assoc_num--; printf("Assosiation Shutdown: count = %d.\n", assoc_num); } } } return assoc_num;}void server_mode() { sockaddr_storage_t msgname; int server_socket, error, stream; int assoc_num =0; struct msghdr inmessage; struct iovec iov; char *big_buffer; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; if ((big_buffer = malloc(REALLY_BIG)) == NULL) { printf("malloc failure: %s\n", strerror(errno)); DUMP_CORE; } printf("Running in Server Mode...\n"); memset(&inmessage, 0, sizeof(inmessage)); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen =1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof (msgname); stream = 1; server_socket = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if (server_socket < 0) { printf("Socket Failure: %s.\n", strerror(errno)); DUMP_CORE; } error = bind(server_socket, &server_loop.sa, sizeof(server_loop)); if (error != 0 ) { printf("Bind Failure: %s.\n", strerror(errno)); DUMP_CORE; } error = listen(server_socket, 1); if (error != 0) { printf("Listen Failure: %s.\n", strerror(errno)); DUMP_CORE; } while (TRUE) { error = recvmsg(server_socket, &inmessage, MSG_WAITALL); if (error < 0) { printf("Receive Failure: %s\n", strerror(errno)); } else { if (inmessage.msg_flags & MSG_NOTIFICATION) assoc_num = event_received(&inmessage, assoc_num); else data_received(&inmessage, error, stream, server_socket); } }}void client_mode() { int i, error, stream, max_socket = 0; uint32_t ppid = 0; int client_socket[assoc_num]; char *message = "Awake"; fd_set rfds; struct timeval tv; stream = 1; printf("Running in Client Mode...\n"); /* Create the sockets */ for (i = 0; i < assoc_num; i++) { client_socket[i] = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if (client_socket[i] < 0 ){ printf("Socket Failure: %s.\n", strerror(errno)); DUMP_CORE; } if (local_port) { error = bind(client_socket[i], &client_loop.sa, sizeof(client_loop)); if (error < 0) { printf("Bind Failure: %s\n", strerror(errno)); DUMP_CORE; } } printf("Create Socket #: %d\n", client_socket[i]); /* Connect to server and send initial message */ error = connect(client_socket[i], &server_loop.sa, sizeof(server_loop)); if (error < 0){ printf("Connect Failure: %s.\n", strerror(errno)); DUMP_CORE; } max_socket = client_socket[i]; ppid++; /* Send initial message */ error = sctp_sendmsg(client_socket[i], message, strlen(message) + 1, (struct sockaddr *)&server_loop, sizeof(server_loop), ppid, 0, stream, 0, 0); if (error < 0 ) { printf("Send Failure: %s.\n", strerror(errno)); DUMP_CORE; } } while (TRUE){ /* Clear the set for select() */ FD_ZERO(&rfds); /* Set time out values for select() */ tv.tv_sec = 5; tv.tv_usec = 0; /* Add the sockets select() will examine */ for (i = 0; i < assoc_num; i++) { FD_SET(client_socket[i], &rfds); } /* Wait until there is data to be read from one of the * sockets, or until the timer expires */ error = select(max_socket + 1, &rfds, NULL, NULL, &tv); if (error < 0) { printf("Select Failure: %s.\n", strerror(errno)); DUMP_CORE; } else if (error) { /* Loop through the array of sockets to find the ones *that have information to be read */ process_ready_sockets(client_socket, assoc_num, &rfds); } }}void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds) { int i, stream, error; struct msghdr inmessage; struct iovec iov; char *big_buffer; char incmsg[CMSG_SPACE(sizeof (sctp_cmsg_data_t))]; sockaddr_storage_t msgname; if ((big_buffer = malloc(REALLY_BIG)) == NULL) { printf("malloc failure: %s\n", strerror(errno)); DUMP_CORE; } /* Setup inmessage to be able to receive in incomming message */ memset(&inmessage, 0, sizeof (inmessage)); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen =1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof (incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof (msgname); stream = 1; for( i = 0; i < assoc_num; i++) { if (FD_ISSET(client_socket[i], rfds)) { error = recvmsg(client_socket[i], &inmessage, MSG_WAITALL); if (error < 0) printf("Receive Failure: %s\n", strerror(errno)); else { /* Test to find the type of message that was read(event/data) */ if (inmessage.msg_flags & MSG_NOTIFICATION) event_received(&inmessage, 0); else data_received(&inmessage, error, stream, client_socket[i]); } } }}int main(int argc, char *argv[]) { parse_arguments(argc, argv); if (mode == SERVER) { server_mode(); } else if (mode == CLIENT){ client_mode(); } exit(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -