 |
» |
|
|
 |
This section lists the sample server programs in one-to-one
and one-to-many associations. This section addresses the following topics: One-to-One Server Program |  |
The following sample program is an implementation of an echo
server over SCTP in a one-to-one association:  |
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/sctp.h>
#include <sys/uio.h>
#define BUFLEN 100
int debug=0;
static void
handle_event(void *buf)
{
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;
snp = buf;
switch (snp->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
sac = &snp->sn_assoc_change;
printf("^^^ 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_SEND_FAILED:
ssf = &snp->sn_send_failed;
printf("^^^ sendfailed: len=%hu err=%d\n", ssf->ssf_length,
ssf->ssf_error);
break;
case SCTP_PEER_ADDR_CHANGE:
spc = &snp->sn_paddr_change;
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);
}
printf("^^^ intf_change: %s state=%d, error=%d\n", ap,
spc->spc_state, spc->spc_error);
break;
case SCTP_REMOTE_ERROR:
sre = &snp->sn_remote_error;
printf("^^^ remote_error: err=%hu len=%hu\n",
ntohs(sre->sre_error), ntohs(sre->sre_length));
break;
case SCTP_SHUTDOWN_EVENT:
printf("^^^ shutdown event\n");
break;
default:
printf("unknown type: %hu\n", snp->sn_header.sn_type);
break;
}
}
int main(int argc, char **argv)
{
int fd, new_fd, sz, len, msg_flags;
int idleTime = 20;
struct sockaddr_in sin[1], cli_addr;
struct sctp_event_subscribe event;
char readbuf[100];
struct sctp_sndrcvinfo sri;
fd_set fdset;
if (argc < 2) {
printf ("\nUsage: <%s> \n\n", argv[0]);
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
perror("socket");
exit(1);
}
sin->sin_family = AF_INET;
sin->sin_port = htons(atoi(argv[1]));
sin->sin_addr.s_addr = INADDR_ANY;
if (bind(fd, (struct sockaddr *)sin, sizeof (*sin)) == -1) {
perror("bind");
exit(1);
}
/* Allow new associations to be accepted */
if (listen(fd, 1) < 0) {
perror("listen");
exit(1);
}
memset (&sri, 0, sizeof(sri));
printf ("{one-to-one}: Waiting for associations ...\n");
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
/* Wait for new associations */
while(1) {
if (select (fd+1, &fdset, 0, 0, 0) <= 0)
continue;
new_fd = accept (fd, (struct sockaddr *) &cli_addr, (socklen_t *) &le);
if (new_fd >=0 )
printf ("\n Connection from: %s\n", inet_ntoa(cli_addr.sin_addr));
/* Not interested in any events for now */
memset (&event, 0, sizeof(event));
if (setsockopt(new_fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
perror("setevent failed");
exit(1);
}
while (1) {
/* Echo back any and all data */
memset (readbuf, 0, sizeof(readbuf));
len = sizeof (struct sockaddr_in);
#if 0
sz = recv(new_fd, readbuf, sizeof(readbuf), 0);
if (debug)
printf ("recv:[%d,e:%d]: ", sz, errno);
#endif
sz = sctp_recvmsg (new_fd, readbuf, sizeof(readbuf),
0, 0, &sri, 0);
if (debug) printf ("sctp_recvmsg:[%d,e:%d,fl:%X]: ", sz, errno, msg_flags);
if (sz <= 0)
break;
printf ("<-- %s on str: %d\n", readbuf,
sri.sinfo_stream);
sz = sctp_sendmsg (new_fd, readbuf, sz, 0, len, 0, 0,
sri.sinfo_stream, 0, 0);
if (debug)
printf ("sctp_sendmsg:[%d,e:%d]\n", sz, errno);
}
close(new_fd);
}
/* unreachable */
close(fd);
}
|
 |
One-to-Many Server Program |  |
The following sample program is an implementation of an echo
server over SCTP in a one-to-many association:  |
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/sctp.h>
#include <sys/uio.h>
#define BUFLEN 100
int debug=0;
static void
handle_event(void *buf)
{
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;
snp = buf;
switch (snp->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
sac = &snp->sn_assoc_change;
printf("^^^ 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_SEND_FAILED:
ssf = &snp->sn_send_failed;
printf("^^^ sendfailed: len=%hu err=%d\n", ssf->ssf_length,
ssf->ssf_error);
break;
case SCTP_PEER_ADDR_CHANGE:
spc = &snp->sn_paddr_change;
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);
}
printf("^^^ intf_change: %s state=%d, error=%d\n", ap,
spc->spc_state, spc->spc_error);
break;
case SCTP_REMOTE_ERROR:
sre = &snp->sn_remote_error;
printf("^^^ remote_error: err=%hu len=%hu\n",
ntohs(sre->sre_error), ntohs(sre->sre_length));
break;
case SCTP_SHUTDOWN_EVENT:
printf("^^^ shutdown event\n");
break;
default:
printf("unknown type: %hu\n", snp->sn_header.sn_type);
break;
}
}
int main(int argc, char **argv)
{
int fd, sz, len, msg_flags;
int idleTime = 20;
struct sockaddr_in sin[1], cli_addr;
struct sctp_event_subscribe event;
char readbuf[100];
struct sctp_sndrcvinfo sri;
if (argc < 2) {
printf ("\nUsage: <%s> <port>\n\n", argv[0]);
return -1;
}
if ((fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) == -1) {
perror("socket");
exit(1);
}
sin->sin_family = AF_INET;
sin->sin_port = htons(atoi(argv[1]));
sin->sin_addr.s_addr = INADDR_ANY;
if (bind(fd, (struct sockaddr *)sin, sizeof (*sin)) == -1) {
perror("bind");
exit(1);
}
#if 0
/* Not interested in any events for now */
memset (&event, 0, sizeof(event));
#else
/* Enable all events */
event.sctp_data_io_event = 1;
event.sctp_association_event = 1;
event.sctp_address_event = 1;
event.sctp_send_failure_event = 1;
event.sctp_peer_error_event = 1;
event.sctp_shutdown_event = 1;
event.sctp_partial_delivery_event = 1;
event.sctp_adaption_layer_event = 1;
#endif
if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
perror("setevent failed");
exit(1);
}
/* Set associations to auto-close in 20 seconds of
* inactivity
*/
if (setsockopt(fd, IPPROTO_SCTP, SCTP_AUTOCLOSE,
&idleTime, 4) < 0) {
perror("setsockopt SCTP_AUTOCLOSE");
exit(1);
}
/* Allow new associations to be accepted */
if (listen(fd, 1) < 0) {
perror("listen");
exit(1);
}
memset (&sri, 0, sizeof(sri));
printf ("{one-to-many}: Waiting for associations ...\n");
/* Wait for new associations */
while(1) {
/* Echo back any and all data */
memset (readbuf, 0, sizeof(readbuf));
len = sizeof (struct sockaddr_in);
sz = sctp_recvmsg (fd, readbuf, sizeof(readbuf),
&cli_addr, &len, &sri, &msg_flags);
if (debug)
printf ("sctp_recvmsg:[%d,e:%d,fl:%X]: ", sz, errno, msg_flags);
if (sz <= 0)
break;
if (msg_flags & MSG_NOTIFICATION) {
handle_event(readbuf);
continue;
}
printf ("<-- %s on str: %d\n", readbuf, sri.sinfo_stream);
sz = sctp_sendmsg (fd, readbuf, sz, &cli_addr, len,
sri.sinfo_ppid, sri.sinfo_flags,
sri.sinfo_stream, 0, 0);
if (debug)
printf ("sctp_sendmsg:[%d,e:%d]\n", sz, errno);
}
close(fd);
}
|
 |
|