blob: e3e1b1954ed168dfe51dc04a11277aea7fe3ab41 [file] [log] [blame]
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <signal.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <poll.h>
#include <sys/uio.h>
#include <netdb.h>
#include "sctp_csum.h"
#include <netinet/sctp.h>
#include <netinet/sctp_uio.h>
#ifdef __NetBSD__
#include <sys/inttypes.h>
#endif
static unsigned char buffer1[4100];
static unsigned char buffer2[4100];
static unsigned char buffer3[4100];
static unsigned char buffer4[4100];
static struct sockaddr_in bindto,got,to;
static socklen_t len;
static u_int32_t at = 468700;
void
prepare_buffers()
{
/* Prepare buffers */
u_int32_t temp,*p;
int i;
p = (u_int32_t *)buffer1;
printf("Buffer1 data value starts at 0x%x", at);
for(i=0;i<(sizeof(buffer1)/4);i++){
*p = at;
at++;
p++;
}
/* backup over the last int */
p--;
*p = 0;
temp = 0xffffffff;
temp = update_crc32(temp,buffer1,(sizeof(buffer1)-4));
*p = sctp_csum_finalize(temp);
printf(", csum is 0x%x\n", *p);
p = (u_int32_t *)buffer2;
printf("Buffer2 data value starts at 0x%x", at);
for(i=0;i<(sizeof(buffer2)/4);i++){
*p = at;
at++;
p++;
}
p--;
*p = 0;
temp = 0xffffffff;
temp = update_crc32(temp,buffer2,(sizeof(buffer2)-4));
*p = sctp_csum_finalize(temp);
printf(", csum is 0x%x\n", *p);
p = (u_int32_t *)buffer3;
printf("Buffer3 data value starts at 0x%x", at);
for(i=0;i<(sizeof(buffer3)/4);i++){
*p = at;
at++;
p++;
}
p--;
*p = 0;
temp = 0xffffffff;
temp = update_crc32(temp,buffer3,(sizeof(buffer3)-4));
*p = sctp_csum_finalize(temp);
printf(", csum is 0x%x\n", *p);
p = (u_int32_t *)buffer4;
printf("Buffer4 data value starts at 0x%x", at);
for(i=0;i<(sizeof(buffer4)/4);i++){
*p = at;
at++;
p++;
}
p--;
*p = 0;
temp = 0xffffffff;
temp = update_crc32(temp,buffer4,(sizeof(buffer4)-4));
*p = sctp_csum_finalize(temp);
printf(", csum is 0x%x\n", *p);
}
static int
my_handle_notification(int fd,char *notify_buf) {
union sctp_notification *snp;
struct sctp_assoc_change *sac;
struct sctp_paddr_change *spc;
struct sctp_remote_error *sre;
struct sctp_send_failed *ssf;
struct sctp_shutdown_event *sse;
int asocDown;
char *str;
char buf[256];
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
asocDown = 0;
snp = (union sctp_notification *)notify_buf;
switch(snp->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
sac = &snp->sn_assoc_change;
switch(sac->sac_state) {
case SCTP_COMM_UP:
str = "COMMUNICATION UP";
break;
case SCTP_COMM_LOST:
str = "COMMUNICATION LOST";
asocDown = 1;
break;
case SCTP_RESTART:
str = "RESTART";
break;
case SCTP_SHUTDOWN_COMP:
str = "SHUTDOWN COMPLETE";
asocDown = 1;
break;
case SCTP_CANT_STR_ASSOC:
str = "CANT START ASSOC";
printf("EXIT:SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str,
(u_int32_t)sac->sac_assoc_id);
exit(0);
break;
default:
str = "UNKNOWN";
} /* end switch(sac->sac_state) */
printf("SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str,
(u_int32_t)sac->sac_assoc_id);
break;
case SCTP_PEER_ADDR_CHANGE:
spc = &snp->sn_paddr_change;
switch(spc->spc_state) {
case SCTP_ADDR_AVAILABLE:
str = "ADDRESS AVAILABLE";
break;
case SCTP_ADDR_UNREACHABLE:
str = "ADDRESS UNAVAILABLE";
break;
case SCTP_ADDR_REMOVED:
str = "ADDRESS REMOVED";
break;
case SCTP_ADDR_ADDED:
str = "ADDRESS ADDED";
break;
case SCTP_ADDR_MADE_PRIM:
str = "ADDRESS MADE PRIMARY";
break;
case SCTP_ADDR_CONFIRMED:
str = "ADDRESS CONFIRMED";
break;
default:
str = "UNKNOWN";
} /* end switch */
sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
if (sin6->sin6_family == AF_INET6) {
inet_ntop(AF_INET6, (char*)&sin6->sin6_addr, buf, sizeof(buf));
} else {
sin = (struct sockaddr_in *)&spc->spc_aaddr;
inet_ntop(AF_INET, (char*)&sin->sin_addr, buf, sizeof(buf));
}
printf("SCTP_PEER_ADDR_CHANGE: %s, addr=%s, assoc=%xh\n", str,
buf, (u_int32_t)spc->spc_assoc_id);
break;
case SCTP_REMOTE_ERROR:
sre = &snp->sn_remote_error;
printf("SCTP_REMOTE_ERROR: assoc=%xh\n",
(u_int32_t)sre->sre_assoc_id);
break;
case SCTP_SEND_FAILED:
ssf = &snp->sn_send_failed;
printf("SCTP_SEND_FAILED: assoc=%xh\n",
(u_int32_t)ssf->ssf_assoc_id);
break;
case SCTP_ADAPTION_INDICATION:
{
struct sctp_adaption_event *ae;
ae = &snp->sn_adaption_event;
printf("\nSCTP_adaption_indication bits:0x%x\n",
(u_int)ae->sai_adaption_ind);
}
break;
case SCTP_PARTIAL_DELIVERY_EVENT:
{
struct sctp_pdapi_event *pdapi;
pdapi = &snp->sn_pdapi_event;
printf("SCTP_PD-API event:%u\n",
pdapi->pdapi_indication);
if(pdapi->pdapi_indication == SCTP_PARTIAL_DELIVERY_ABORTED){
printf("PDI- Aborted\n");
}
}
break;
case SCTP_SHUTDOWN_EVENT:
sse = &snp->sn_shutdown_event;
printf("SCTP_SHUTDOWN_EVENT: assoc=%xh\n",
(u_int32_t)sse->sse_assoc_id);
break;
default:
printf("Unknown notification event type=%xh\n",
snp->sn_header.sn_type);
} /* end switch(snp->sn_type) */
if(asocDown){
printf("Bring association back up\n");
len = sizeof(to);
if(connect(fd,(struct sockaddr *)&to,len) == -1){
printf("Sorry connect fails %d\n",errno);
}
return(1);
}
return(0);
}
int
my_sctpReadInput(int fd)
{
/* receive some number of datagrams and
* act on them.
*/
struct sctp_sndrcvinfo *s_info;
int sz,i,disped;
struct msghdr msg;
struct iovec iov[2];
unsigned char from[200];
char readBuffer[65535];
char controlVector[65535];
disped = i = 0;
s_info = NULL;
iov[0].iov_base = readBuffer;
iov[0].iov_len = sizeof(readBuffer);
iov[1].iov_base = NULL;
iov[1].iov_len = 0;
msg.msg_name = (caddr_t)from;
msg.msg_namelen = sizeof(from);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)controlVector;
msg.msg_controllen = sizeof(controlVector);
errno = 0;
sz = recvmsg(fd,&msg,0);
if(sz <= 0){
printf("Read returns %d errno:%d control len is %d msgflg:%x\n",
sz,errno,
msg.msg_controllen,msg.msg_flags);
}
if (msg.msg_flags & MSG_NOTIFICATION) {
return(my_handle_notification(fd,readBuffer));
}else{
printf("Huh, I got data?.. ignored (%d bytes)\n",sz);
return(0);
}
}
int
clear_fds(int fd,int fd1)
{
int felldown;
int max,notdone;
fd_set readfds,writefds,exceptfds;
struct timeval tv;
memset(&tv,0,sizeof(tv));
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
felldown = 0;
FD_SET(fd,&readfds);
FD_SET(fd1,&readfds);
if(fd > fd1){
max = fd + 1;
}else{
max = fd1 + 1;
}
notdone = 1;
while(notdone){
select(max,&readfds,&writefds,&exceptfds,&tv);
notdone = 0;
if(FD_ISSET(fd,&readfds)){
notdone++;
printf("clearing fd:%d\n",fd);
felldown += my_sctpReadInput(fd);
notdone = 1;
}
if(FD_ISSET(fd1,&readfds)){
notdone++;
printf("clearing fd1:%d\n",fd1);
felldown += my_sctpReadInput(fd1);
}
}
return(felldown);
}
void
process_out_data(int fd,int fd1)
{
int notdone,x,ret;
while(1){
/* Prepare the buffers */
prepare_buffers();
/* send out the 4 buffers */
ret = sendto(fd,buffer1,sizeof(buffer1),0,
(struct sockaddr *)&to,sizeof(to));
if(ret < sizeof(buffer1)){
printf("Gak1, error:%d ret:%d\n",errno,ret);
}
printf("Sent buffer1 to fd %d\n", fd);
ret = sendto(fd1,buffer2,sizeof(buffer1),0,
(struct sockaddr *)&to,sizeof(to));
if(ret < sizeof(buffer2)){
printf("Gak2, error:%d ret:%d\n",errno,ret);
}
printf("Sent buffer2 to fd1 %d\n", fd1);
ret = sendto(fd,buffer3,sizeof(buffer1),0,
(struct sockaddr *)&to,sizeof(to));
if(ret < sizeof(buffer3)){
printf("Gak3, error:%d ret:%d\n",errno,ret);
}
printf("Sent buffer3 to fd %d\n", fd);
ret = sendto(fd1,buffer4,sizeof(buffer1),0,
(struct sockaddr *)&to,sizeof(to));
if(ret < sizeof(buffer4)){
printf("Gak4, error:%d ret:%d\n",errno,ret);
}
printf("Sent buffer4 to fd1 %d\n", fd1);
/* now wait until we get a assoc failing */
notdone = 1;
while(notdone){
x = clear_fds(fd,fd1);
if(x){
notdone = 0;
}
sleep(1);
}
}
}
int
main(int argc, char **argv)
{
int i,fd,fd1;
char *addr=NULL;
u_int16_t port=0;
int protocol_touse = IPPROTO_SCTP;
while((i= getopt(argc,argv,"p:h:")) != EOF){
switch(i){
case 'h':
addr = optarg;
break;
case 'p':
port = (u_int16_t)strtol(optarg,NULL,0);
break;
};
}
memset(&to,0,sizeof(to));
if((addr == NULL) || (port == 0)){
printf("Sorry you must specify -h addr and -p port\n");
return(-1);
}
if(inet_pton(AF_INET, addr, (void *) &to.sin_addr)){
to.sin_len = sizeof(to);
to.sin_family = AF_INET;
printf("port selected is %d\n",port);
printf("addr %x\n",(u_int)ntohl(to.sin_addr.s_addr));
to.sin_port = htons(port);
}else{
printf("Can't translate the address\n");
return(-1);
}
/**********************socket 1 *******************/
fd = socket(AF_INET, SOCK_SEQPACKET, protocol_touse);
if(fd == -1){
printf("can't open socket:%d\n",errno);
return(-1);
}
memset(&bindto,0,sizeof(bindto));
len = bindto.sin_len = sizeof(bindto);
bindto.sin_family = AF_INET;
bindto.sin_port = 0;
if(bind(fd,(struct sockaddr *)&bindto, len) < 0){
printf("can't bind a socket:%d\n",errno);
close(fd);
return(-1);
}
if(getsockname(fd,(struct sockaddr *)&got,&len) < 0){
printf("get sockname failed err:%d\n",errno);
close(fd);
return(-1);
}
printf("fd uses port %d\n",ntohs(got.sin_port));
/**********************socket 2 *******************/
fd1 = socket(AF_INET, SOCK_SEQPACKET, protocol_touse);
if(fd1 == -1){
printf("can't open socket:%d\n",errno);
close(fd);
return(-1);
}
memset(&bindto,0,sizeof(bindto));
len = bindto.sin_len = sizeof(bindto);
bindto.sin_family = AF_INET;
bindto.sin_port = 0;
if(bind(fd1,(struct sockaddr *)&bindto, len) < 0){
printf("can't bind a socket:%d\n",errno);
close(fd);
close(fd1);
return(-1);
}
if(getsockname(fd1,(struct sockaddr *)&got,&len) < 0){
printf("get sockname failed err:%d\n",errno);
close(fd);
close(fd1);
return(-1);
}
printf("fd1 uses port %d\n",ntohs(got.sin_port));
if(connect(fd,(struct sockaddr *)&to,len) == -1){
printf("Sorry connect fails %d\n",errno);
close(fd);
return(-1);
}
if(connect(fd1,(struct sockaddr *)&to,len) == -1){
printf("Sorry connect fails %d\n",errno);
close(fd);
return(-1);
}
printf("Connected\n");
clear_fds(fd,fd1);
process_out_data(fd,fd1);
return(0);
}