/* File : sctp_server_send_receive_echo_messages_from_one_stream.c Programmer : Nasif Ekiz Date : 9/27/2006 Description : This is a SCTP server application which accepts association requests from clients. Basicly, it gets a message from a client and echoes the incomming message to the client back. This program is a SCTP one-to-many style application. */ #include #include #include #include #define BUFFSIZE 8192 #define SERV_PORT 7000 int main (int argc, char **argv) { int sock_fd, msg_flags; // socket identifier, message flags char readbuf[BUFFSIZE]; // receive message buffer struct sockaddr_in servaddr, cliaddr; // server and client address structures to keep IPv4 address struct sctp_sndrcvinfo sri; // sctp_sndrcvinfo structure used to set default // parameters for the association struct sctp_event_subscribe evnts; /* this structure is used to enable/disable various SCTP notifications 0 - unsubscribe, 1 - subscribe */ int stream_increment = 1; // this integer variable is used to determine weather to // send messages from incomming stream or next stream socklen_t len; size_t rd_sz; size_t sd_sz; // checks if an argument is passed for stream_increment if so use this value for stream_increment if (argc == 2) stream_increment = atoi(argv[1]); // open a socket // AF_INET - IPv4 protocol // SOCK_SEQPACKET - sequenced packet socket // IPPROTO_SCTP - SCTP transport protocol sock_fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); // check for errors if (sock_fd < 0) { perror("Server can't open socket!"); exit(1); } // clear server address structure memset(&servaddr, 0, sizeof(servaddr)); // set server address information servaddr.sin_family = AF_INET; // IPv4 protocol servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // in the case of multiple interfaces accept // connection on any host interface servaddr.sin_port = htons(SERV_PORT); // set server's application port number // assign a local protocol address (IP + port number) to socket if ((bind(sock_fd, (struct sockaddr *) &servaddr, sizeof(servaddr))) < 0 ) { perror("Server can't bind to local address!"); exit(1); } // clear sctp_event_subscribe structure memset(&evnts, 0, sizeof(evnts)); // enable sctp_sndrcvinfo to come with each sctp_recvmsg function evnts.sctp_data_io_event = 1; // set the options for the socket // SCTP_EVENTS option allows a caller to fetch, enable/disable various SCTP notifications if ((setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts))) < 0 ) { perror("Error in setsockopt!"); exit(1); } /* listen for incomming client requests the second parameter specifies the maximum number of connections the kernel should queue for the socket */ if ((listen(sock_fd, 1024)) < 0) { perror("Server can't listen for incomming connection requests!"); exit(1); } for( ; ; ) { len = sizeof(struct sockaddr_in); // length of client address structure // read a message from one of the clients rd_sz = sctp_recvmsg(sock_fd, readbuf, sizeof(readbuf), (struct sockaddr *) &cliaddr, &len, &sri, &msg_flags); // error in reading data if (rd_sz < 0) { perror("Error in sctp_recvmsg while reading data!"); exit(1); } // if stream_increment argument is presented then send the echo message from the next stream if(stream_increment) { // sinfo_stream specifies the default stream that messages will be sent sri.sinfo_stream++; // default value for number of opened streams in an association is 10 if (sri.sinfo_stream >= 10) { sri.sinfo_stream = 0; } } // send an echo message to the client that sent the last message sd_sz = sctp_sendmsg(sock_fd, readbuf, rd_sz, (struct sockaddr *) &cliaddr, len, sri.sinfo_ppid, sri.sinfo_flags, sri.sinfo_stream, 0, 0); // error in sending data if (sd_sz < 0) { perror("Error in sctp_sendmsg while sending data!"); exit(1); } } }