- From: "Sumathi.Elangovan" <Sumathi.Elangovan AT uk.thalesgroup.com>
- To: discussion AT sctp.de, "'Thomas Dreibholz'" <dreibh AT exp-math.uni-essen.de>
- Subject: [SCTP-Discussion] Partial Delivery!!
- Date: Fri Dec 13 12:12:02 2002
- List-id: SCTP Discussions <discussion.sctp.de>
>
Hi!
>
I am using the sctp implementation version 1.0.1...I have attached part of
>
my code ("SCTP CODE") which allows association,data transfer and a
>
graceful shutdown. The problem arises when the sender is given a message to
>
send larger than its receiver window where it just hangs. This can be seen
>
in my other attachment ("after the sctp code") with the trace viewed with
>
the Ethereal.
>
The sender fragments the message and sends the fragments to the receiver.
>
The receiver is constrained to hold onto the fragments till the whole
>
message has been reconstructed.
>
Eventually the receiver returns an a_rwnd of 0 which can be seen at frame
>
63. The association hangs.
>
>
Why I am getting a FORWARD TSN at frame 64...What is the significance of
>
this message? I know that FORWARD TSN means that the message received until
>
this frame (64) is unordered......
>
>
In RFC 2960,section 6.9:
>
"Note: If the data receiver runs out of buffer space while still
>
waiting for more fragments to complete the re-assembly of the
>
message, it should dispatch part of its inbound message through a
>
partial delivery API (see Section 10), freeing some of its receive
>
buffer space so that the rest of the message may be received."
>
>
In section 5.3.1 of the sctp socket api - 05 .. ..it mentions the
>
SCTP_PARTIAL_DELIVERY_EVENT to be set....Does the ESSEN implement this
>
feature? How can I overcome the "hang" problem? Am I missing something
>
vital in my code to perform the partial delivery?
>
Thanks for your help!!!
>
>
******************** SCTP CODE **************************
>
#include <arpa/inet.h>
#include <bits/time.h>
#include <bits/types.h>
#include <config.h>
#include <ext_socket.h>
#include <features.h>
#include <gnu_getopt.h>
#include <net/route.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sctp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
#include <util.h>
#define MAX_BUF_LEN (128 *1024)
#define PATTERN_LEN 26
#define SERVER_PORT_NUM 2960
#define LONG_OPTIONS()
#define SHORT_OPTIONS()
#define DEBUG_PRINT(x) printf(x)
#define DEBUG_PRINT_1(x,y) printf(x,y)
#define DEBUG_PRINT_2(x,y,z) printf(x,y,z)
extern int gnu_getopt_long( int argc,char *const *argv,const char
*options,const struct option *long_options,int *opt_index );
extern double byte_atof( const char *inString );
extern const char *inet_ntop(af, src, dst, size);
struct msghdr msg[1];
int mBufLen = MAX_BUF_LEN;
int mAmount = 10;
int isServer = 0;
char *mHost;
long timeStart = 0;
long timeDiff = 0;
/* to get the time */
long getTime()
{
long longTime;
struct timeb thetime;
ftime(&thetime);
longTime = (thetime.time * 1000) + thetime.millitm;
DEBUG_PRINT_1("\nTime = %d ms\n", thetime.millitm);
return longTime;
}
/* to calculate the difference between start and end time*/
long getTimeDiff(long startTime)
{
long endTime;
endTime = getTime();
return (endTime-startTime);
}
/* this function gives the SCTP header information */
void printSCTPHeaderInfo(struct sctp_sndrcvinfo *info)
{
DEBUG_PRINT_1("Send Receive Info for assoc: %x\n", info ->
sinfo_assoc_id);
DEBUG_PRINT_1("Stream = %d \n", info -> sinfo_stream);
DEBUG_PRINT_1("SSN = %d \n", info -> sinfo_ssn);
DEBUG_PRINT_1("Flags = %x \n", info -> sinfo_flags);
DEBUG_PRINT_1("PPID = %x \n", info -> sinfo_ppid);
DEBUG_PRINT_1("Context = %d \n", info -> sinfo_context);
DEBUG_PRINT_1("TTL = %d \n", info -> sinfo_timetolive);
DEBUG_PRINT_1("TSN = %x \n", info -> sinfo_tsn);
}
/* to handle various events*/
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;
struct sockaddr_in *sin;
struct sctp_rcv_pdapi_event *pdapi;
union sctp_notification *snp;
char addrbuf[INET6_ADDRSTRLEN];
const char *ap;
snp = buf;
switch(snp -> h.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);
if(sac -> sac_state == COMMUNICATION_UP)
{
timeStart = getTime();
}
if(sac ->sac_state == SHUTDOWN_COMPLETE)
{
timeDiff = getTimeDiff(timeStart);
}
break;
case SCTP_SEND_FAILED:
ssf = &snp -> sn_send_failed;
DEBUG_PRINT_2("*** send_failed: len = %hu err =
%hu\n", ssf -> ssf_length, ssf -> ssf_error);
break;
case SCTP_PEER_ADDR_CHANGE:
spc = &snp -> sn_paddr_change;
if(((struct sockaddr_in *)&spc ->
spc_aaddr)->sin_family == AF_INET)
{
sin = (struct sockaddr_in *)&spc->spc_aaddr;
ap = inet_ntop(AF_INET, &sin ->
sin_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;
DEBUG_PRINT_1("*** remote_error: err
=%hu\n",ntohs(sre -> sre_error));
break;
case SCTP_SHUTDOWN_EVENT:
DEBUG_PRINT("*** shutdown event\n");
break;
case SCTP_PARTIAL_DELIVERY_EVENT:
pdapi = &snp -> sn_rcv_pdapi_event;
printf("*** partial_delivery: length = %hu, indi =
%hu\n",pdapi -> pdapi_length,pdapi -> pdapi_indication);
break;
default:
DEBUG_PRINT_1("unknown type: %hu\n",snp -> h.sn_type);
break;
}
}
/* function sctp_recvmsg which uses the ext_recvmsg to obtain the data from
the client and a MSG_EOR
* flag set for each received message */
void *sctp_recvmsg(int fd, struct msghdr *msg, void *buf, size_t *buflen,
ssize_t *nrp, size_t cmsglen)
{
int bytesReceived = 0;
int numReads = 0;
ssize_t nr = 0;
for(;;)
{
struct iovec iov[1];
iov -> iov_base = buf;
msg -> msg_iov = iov;
msg -> msg_iovlen = 1;
msg -> msg_flags =0;
msg -> msg_iov -> iov_len = *buflen;
msg -> msg_controllen = cmsglen;
nr = ext_recvmsg(fd,msg,0);
numReads++;
if(nr <= 0)
{
bytesReceived = nr;
DEBUG_PRINT_1("bytes received = %d\n\n", nr);
DEBUG_PRINT_1("sctp_recvmsg: number of reads = %d \n\n", numReads);
return(NULL);
}
if((msg -> msg_flags & MSG_EOR) != 0)
{
*nrp = nr;
return(buf);
}
}
}
/* ext_setsockopt() defined */
void setSocketOptions(int sock)
{
struct sctp_event_subscribe events;
DEBUG_PRINT("setting socket option.\n");
memset((char*)&events,1,sizeof(events));
if(ext_setsockopt(sock, IPPROTO_SCTP, SCTP_SET_EVENTS, &events,
sizeof(events)) < 0)
{
printf("setsocketopt failed\n");
exit(1);
}
DEBUG_PRINT("socket options set\n");
}
/* socket(),bind() and listen() functions called */
int setUpSocket(int portNum)
{
int sock;
struct sockaddr_in sockAddr;
if((sock = ext_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
{
printf("socket() failed");
exit(1);
}
DEBUG_PRINT("socket created()\n");
memset(&sockAddr, 0 , sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = INADDR_ANY;
sockAddr.sin_port = htons(portNum);
if(ext_bind(sock, (struct sockaddr *) &sockAddr, sizeof(sockAddr)) <
0)
{
printf("bind() failed");
exit(1);
}
DEBUG_PRINT("address bounded\n");
setSocketOptions(sock);
if(ext_listen(sock, 0) < 0)
{
printf("listen() failed");
exit(1);
}
return sock;
}
/*sets up the server side of sctp which calls
setUpSocket(),sctp_recvmsg(),handleEvent() and calculates
* the Bandwidth */
void SctpServer()
{
int servSock;
int numReads = 0;
int totalBytesReceived = 0;
double throughput;
ssize_t bytesReceived = 0;
struct sctp_sndrcvinfo *sri;
struct cmsghdr *cmsg;
char cbuf[sizeof(*cmsg) + sizeof(*sri)];
char *buf = NULL;
size_t bufLen;
size_t cmsglen = sizeof(*cmsg) + sizeof(*sri);
servSock = setUpSocket(SERVER_PORT_NUM);
for (;;)
{
DEBUG_PRINT("***************************************************************.\n");
bufLen = MAX_BUF_LEN;
DEBUG_PRINT_1("Maximum buffer length: %d\n", bufLen);
if(!(buf = malloc(bufLen)))
{
printf("out of memory");
exit(1);
}
DEBUG_PRINT("memory allocated\n");
memset(msg,0,sizeof(*msg));
msg -> msg_control = cbuf;
msg -> msg_controllen = cmsglen;
msg -> msg_flags = 0;
cmsg = (struct cmsghdr *)cbuf;
sri = (struct sctp_sndrcvinfo *) (cmsg+1);
numReads = 0;
while((buf = sctp_recvmsg(servSock, msg, buf, &bufLen,
&bytesReceived, cmsglen)))
{
numReads++;
totalBytesReceived += bytesReceived;
//printSCTPHeaderInfo(sri);
if(msg -> msg_flags & MSG_NOTIFICATION)
{
handle_event(buf);
if(timeDiff != 0)
{
printf("Total bytes received %d in %d
msecs\n",totalBytesReceived, timeDiff);
throughput = ((totalBytesReceived *
8) / timeDiff);
printf("Bandwidth: %.2f kbits/sec
\n\n",throughput);
timeDiff = 0;
}
continue;
}
}
}
}
/*the client side created which calls up setUpSocket() and ext_sendmsg() */
void SctpClient()
{
int bytesReceived;
int clntSock;
int bytesSent = 0;
int loopIndex;
int i;
int count;
char *buf;
int numWrites = 0;
int readBufLen = 100;
char readBuf[100];
struct sockaddr_in servAddr;
struct iovec iov[1];
struct sctp_sndrcvinfo *sri;
struct cmsghdr *cmsg;
char cbuf[sizeof(*cmsg) + sizeof(*sri)];
size_t cmsglen = sizeof(*cmsg) + sizeof(*sri);
clntSock = setUpSocket(SERVER_PORT_NUM);
/* The server address that the client needs to connect */
servAddr.sin_family = AF_INET;
if(inet_aton(mHost, &servAddr.sin_addr) != 1)
{
printf("mHost failed.\n\n");
exit(1);
}
servAddr.sin_port = htons(SERVER_PORT_NUM);
buf = malloc(mBufLen);
(&iov[0]) -> iov_base = buf;
(&iov[0]) -> iov_len = mBufLen;
memset(msg,0,sizeof(*msg)); // added by iain
msg -> msg_iov = iov;
msg -> msg_iovlen = 1;
msg -> msg_name = (void *) &servAddr;
msg -> msg_namelen = sizeof(servAddr);
// added by iain
cmsg = (struct cmsghdr *) cbuf;
sri = (struct sctp_sndrcvinfo *) (cmsg + 1);
memset(cbuf,0,(sizeof(*cmsg) + sizeof(*sri)));
cmsg -> cmsg_level = IPPROTO_SCTP;
cmsg -> cmsg_type = SCTP_SNDRCV;
cmsg -> cmsg_len = cmsglen;
msg -> msg_control = cbuf;
msg -> msg_controllen = cmsglen;
msg -> msg_flags = 0;
// end of iain addition
for(i = 0 ; i < mBufLen; i++)
{
buf[i] = (char) (i % 256);
}
loopIndex = (mAmount/mBufLen);
DEBUG_PRINT_1("\nLoopIndex = %d.\n",loopIndex);
for(i = 0; i < loopIndex; i++)
{
if((count = ext_sendmsg(clntSock,msg, 0)) < 0)
{
printf("send() failed.\n\n");
exit(1);
}
bytesSent += count;
numWrites++;
}
DEBUG_PRINT_1("Number of writes %d \n\n", numWrites);
msg -> msg_flags = 0;
cmsg = (struct cmsghdr *)cbuf;
sri = (struct sctp_sndrcvinfo *) (cmsg+1);
sri -> sinfo_flags = MSG_EOF;
sri -> sinfo_assoc_id = 1;
/* in order to shutdown the association gracefully ,need to send an empty
buffer */
(&iov[0]) -> iov_base = buf;
(&iov[0]) -> iov_len = 0;
msg -> msg_iov = iov;
msg -> msg_iovlen = 1;
DEBUG_PRINT("For Graceful Shutdown\n");
if((count = ext_sendmsg(clntSock,msg,0)) > 0)
{
printf("buffer greater than 0:failed()");
exit(1);
}
DEBUG_PRINT_1("Empty Buffer:%d\n",count);
msg -> msg_flags = 0;
(&iov[0]) -> iov_base = readBuf;
(&iov[0]) -> iov_len = readBufLen;
msg -> msg_iov = iov;
msg -> msg_iovlen = 1;
buf = sctp_recvmsg(clntSock, msg, readBuf, &readBufLen,
&bytesReceived, cmsglen);
//{
if(msg -> msg_flags & MSG_NOTIFICATION);
{
handle_event(buf);
// continue;
}
//}
printSCTPHeaderInfo(sri);
//ext_close(clntSock);
DEBUG_PRINT("********** This will timeout soon...inorder to break
do Ctrl c ************ \n");
sleep(300);
exit(1);
}
>
***************************************************** TRACE SHOWN BY THE
>
ETHEREAL*****************************************
>
No. Time Source Destination Protocol
>
Info
21 29.147839 Node B Node A SCTP INIT
22 29.148184 Node A Node B SCTP INIT_ACK
23 29.155720 Node B Node A SCTP COOKIE_ECHO
24 29.155933 Node A Node B SCTP COOKIE_ACK
25 29.176618 Node B Node A SCTP DATA
26 29.176816 Node A Node B SCTP SACK
27 29.182558 Node B Node A SCTP DATA
28 29.188527 Node B Node A SCTP DATA
29 29.188681 Node A Node B SCTP SACK
30 29.200215 Node B Node A SCTP DATA
31 29.206138 Node B Node A SCTP DATA
32 29.206268 Node A Node B SCTP SACK
33 29.212063 Node B Node A SCTP DATA
34 29.218000 Node B Node A SCTP DATA
35 29.218122 Node A Node B SCTP SACK
36 29.223930 Node B Node A SCTP DATA
37 29.229852 Node B Node A SCTP DATA
38 29.229967 Node A Node B SCTP SACK
39 29.235775 Node B Node A SCTP DATA
40 29.241714 Node B Node A SCTP DATA
41 29.241797 Node A Node B SCTP SACK
42 29.247734 Node B Node A SCTP DATA
43 29.253577 Node B Node A SCTP DATA
44 29.253664 Node A Node B SCTP SACK
45 29.259504 Node B Node A SCTP DATA
46 29.265422 Node B Node A SCTP DATA
47 29.265538 Node A Node B SCTP SACK
48 29.271355 Node B Node A SCTP DATA
49 29.277284 Node B Node A SCTP DATA
50 29.277386 Node A Node B SCTP SACK
51 29.283222 Node B Node A SCTP DATA
52 29.289176 Node B Node A SCTP DATA
53 29.289269 Node A Node B SCTP SACK
54 29.295083 Node B Node A SCTP DATA
55 29.301033 Node B Node A SCTP DATA
56 29.301121 Node A Node B SCTP SACK
57 29.306941 Node B Node A SCTP DATA
58 29.312882 Node B Node A SCTP DATA
59 29.312983 Node A Node B SCTP SACK
60 29.333917 Node B Node A SCTP DATA
61 29.542687 Node A Node B SCTP SACK
62 29.564601 Node B Node A SCTP DATA
63 29.564718 Node A Node B SCTP SACK
64 30.569279 Node B Node A SCTP FORWARD TSN
65 30.773141 Node A Node B SCTP SACK
78 59.903598 Node A Node B SCTP SHUTDOWN
83 62.903638 Node A Node B SCTP SHUTDOWN
84 68.903799 Node A Node B SCTP SHUTDOWN
89 80.904099 Node A Node B SCTP SHUTDOWN
92 104.904727 Node A Node B SCTP SHUTDOWN
>
Regards
>
Sumathi Elangovan
>
>
Sumathi Elangovan
>
Design Engineer
>
Thales Research Limited
>
Reading
>
Tel: 0118 923 8272
>
Email :
>
Sumathi.Elangovan AT uk.thalesgroup.com
>
>
**********************************************************************
This email and any files transmitted with it are intended solely for
the use of the individual or entity to whom they are addressed and may
not be divulged to any third party without the express permission of
the originator. Any views expressed in this message are those of the
individual sender, except where the sender specifically states them to
be the views of Thales Research & Technology (UK) Ltd.
**********************************************************************
- [SCTP-Discussion] Partial Delivery!!, Sumathi.Elangovan, 12/13/2002
Archive powered by MHonArc 2.6.19+.