SCTP Discussions

Text archives Help


Re: [SCTP-Discussion] Sending by which stream?


Chronological Thread 
  • From: Thomas Dreibholz <dreibh AT exp-math.uni-essen.de>
  • To: "Oon Heok Kee" <oonheokkee78 AT hotmail.com>
  • Cc: discussion AT sctp.de
  • Subject: Re: [SCTP-Discussion] Sending by which stream?
  • Date: Mon Sep 2 10:37:03 2002
  • List-id: SCTP Discussions <discussion.sctp.de>
  • Organization: University of Essen, Institute for Experimental Mathematics

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am Montag, 2. September 2002 03:25 schrieb Oon Heok Kee:
> Hi,
>
> Very sorry to trouble you... here's the code...

Tye cmsg type for sctp_sndrcvinfo is SCTP_SNDRCV. SCTP_INITMSG is only used
for ext_setsockopt() to set the sctp_initmsg parameters. After setting
"cmsg->cmsg_type = SCTP_SNDRCV", the stream ID is correctly transmitted.

ext_sendmsg() returns the number of bytes transmitted. Therefore,
if (ext_sendmsg(sock, msg, 0))
DieWithError(...
aborts when the send call is successful. Use
if (ext_sendmsg(sock, msg, 0) < 0)
DieWithError(...
instead.

You have to initialize the msghdr structure before receiving the reply using
ext_recvmsg(). In your program, the user data buffer still points to
echoString with a length of strlen(echoString). Therefore, the reply will be
written to this destination and not echoBuffer as it is desired. Furthermore,
msg->controllen is still set to the length of the data for ext_sendmsg(), it
should be sizeof(cbuf) - for the case of a longer reply.

(&iov[0])->iov_base = echoBuffer;
(&iov[0])->iov_len = sizeof(echoBuffer);
msg->msg_iov = (struct iovec*)&iov;
msg->msg_iovlen = 1;
msg->msg_control = cbuf;
msg->msg_controllen = sizeof(cbuf);
msg->msg_flags = 0;
msg->msg_name = NULL;
msg->msg_namelen = 0;


> I have some other questions as well. Firstly, this client code seems
> to
> terminate itself by sending an ABORT signal to the server, even before the
> server had echoed back the string. Can you advise me on what's wrong?

The socket API is written in C++, therefore the destructor for the instance
is called after you call exit(...) in your program. To make the removal of
the instance as clean as possible, an ABORT is sent to all open instances. To
avoid this, give the SCTP instance some time to complete a clean shutdown by
inserting an usleep(100000) before the exit() call. This will pause the
current thread for 100ms and should be sufficient for a clean shutdown.


> Second, we all know that colored pictures are made up of the 3 primary
> colors (red, green and blue). Suppose I have a colored picture and it has
> been decoded into these 3 frames. How do I send these 3 frames from one end
> to the other? Do I have to have 1 end doing ext_sendmsg() 3 times (once for
> each frame) and the receving end doing ext_rcvmsg() 3 times as well? Or how
> do I send the 3 frames via 3 different streams? Basic idea is, I want them
> to be sent with different reliability and at least sent on a different
> stream each.

You have to call ext_sendmsg() 3 times, each with a different sctp_sndrcvinfo
setting (for the stream IDs). The received side has to call ext_recvmsg()
three times. If data IO events are registered, you will also receive a
sctp_sndrcvinfo for each call.


I have attached the changed version of your source to this mail. This
includes the bugfixes above and an example how to get the sctp_sndrcv
structure using ext_recvmsg().




> Thanks a lot for your help... really appreciate it!!
>
>
> Oon, Heok Kee
>
> *********************************************************************
> /* Echo Client Example */
>
> /* SCTP client */
>
> /* Compile this file with "gcc -o sctp_client sctp_client.c -Wall
> -lsctpsocket -lsctp -lglib -lstdc++ -lpthread". */
>
> #include <stdio.h> /* for printf() and fprintf() */
> #include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
> #include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
> #include <stdlib.h> /* for atoi() */
> #include <string.h> /* for memset() */
> #include <unistd.h> /* for close() */
> #include <sys/types.h>
> #include <sys/time.h>
> #include <ext_socket.h>
> #include <net/route.h>
> #include <net/if.h>
> #include <netinet/in.h>
> #include <sctp.h>
>
> #define RCVBUFSIZE 16 /* Size of receive buffer */
> #define OUTSTREAM 3 /* Number of out-bound streams */
> #define INSTREAM 2 /* Number of in-bound streams */
>
>
> void DieWithError(char *errorMessage)
> {
> perror(errorMessage);
> exit(1);
> }
>
>
> int main(int argc, char *argv[])
> {
> int sock; /* Socket descriptor */
> struct sockaddr_in echoServAddr;/* Echo server address */
> unsigned short echoServPort; /* Echo server port */
> char *servIP; /* Server IP address (dotted quad) */
> char *echoString; /* String to send to echo server */
> char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */
> unsigned int echoStringLen; /* Length of string to echo */
> int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv() and
> total
> bytes read */
> ssize_t nr;
> struct sctp_initmsg sim;
> struct sctp_sndrcvinfo *sinfo;
> struct msghdr msg[1];
> struct cmsghdr *cmsg;
> struct iovec iov[1];
> char cbuf[sizeof(*cmsg) + sizeof(*sinfo) + sizeof(*echoString)];
> char *testbuf;
>
> /* Test for correct number of arguments */
> if ((argc < 3) || (argc > 4))
> {
> fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo
> Port>]\n",
> argv[0]);
> exit(1);
> }
>
> servIP = argv[1]; /* First arg: server IP address (dotted quad) */
>
> echoString = argv[2]; /* Second arg: string to echo */
>
> if (argc == 4)
> echoServPort = atoi(argv[3]); /* Use given port, if any */
> else
> /* 7 is the well-known port for the echo service */
> echoServPort = 7;
>
> printf("\nCreating socket... ");
> /* Create a reliable, stream socket using TCP */
> if ((sock = ext_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0)
> {
> DieWithError("socket() failed");
> exit(1);
> }
> printf("Socket created.\n\n");
>
> (&sim)->sinit_num_ostreams = OUTSTREAM;
> (&sim)->sinit_max_instreams = INSTREAM;
> (&sim)->sinit_max_attempts = 3;
> (&sim)->sinit_max_init_timeo = 30;
>
>
>
> /* Setting socket options */
> if (ext_setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, &sim,
> sizeof(sim)) <
> 0)
> {
> DieWithError("setsockopt() failed");
> exit(1);
> }
>
>
> memset(msg, 0, sizeof(*msg));
> msg->msg_control = cbuf;
> msg->msg_controllen = sizeof(struct cmsghdr) + sizeof(struct
> sctp_sndrcvinfo);
> msg->msg_flags = 0;
>
> (&iov[0])->iov_base = echoString; /*testbuf;*/
> (&iov[0])->iov_len = strlen(echoString); /*nr;*/
>
> msg->msg_iov = &iov;
> msg->msg_iovlen = 1;
>
> cmsg = (struct cmsghdr *)cbuf;
> sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);
>
> cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct
> sctp_sndrcvinfo);
> cmsg->cmsg_level = IPPROTO_SCTP;
> cmsg->cmsg_type = SCTP_INITMSG;
>
> sinfo->sinfo_assoc_id = 0;
> sinfo->sinfo_stream = 1; /* streamNumber */
> sinfo->sinfo_flags = 0;
> sinfo->sinfo_ppid = 0; /* ppid */
> sinfo->sinfo_context = (uint32_t)NULL;
> sinfo->sinfo_timetolive = (unsigned int)-1;
>
> /* Construct the server address structure */
> /* Zero out structure */
> memset(&echoServAddr, 0, sizeof(echoServAddr));
>
> echoServAddr.sin_family = AF_INET; /* Internet address family */
>
> /* Server IP address */
> echoServAddr.sin_addr.s_addr = inet_addr(servIP);
>
> echoServAddr.sin_port = htons(echoServPort); /* Server port */
>
> printf("Connecting to server at %s:%u ... ", servIP, echoServPort);
> /* Establish the connection to the echo server */
> if (ext_connect(sock, (struct sockaddr *) &echoServAddr,
> sizeof(echoServAddr)) < 0)
> DieWithError("connect() failed");
> printf("Connected.\n\n");
>
> echoStringLen = strlen(echoString); /* Determine input length */
>
> printf("Sending message \"%s\" to server... ", echoString);
> /* Send the string to the server */
> if (ext_sendmsg(sock, msg, 0))
> DieWithError("send() sent a diff. num. of bytes than
> expected");
> printf("Message sent.\n\n");
>
> /* Receive the same string back from the server */
> totalBytesRcvd = 0;
>
> printf("Receiving echo from server... ");
> printf("Received: "); /* Setup to print the echoed string */
>
> while (totalBytesRcvd < echoStringLen)
> {
> /* Receive up to the buffer size (minus 1 to leave space for a
> null terminator) bytes from the sender */
> if ((bytesRcvd = ext_recvmsg(sock, msg, 0)) <=
> 0)/*echoBuffer, RCVBUFSIZE
> - 1, 0)) <= 0)*/
> DieWithError("recv() failed or conn. closed
> prematurely");
> totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
>
> echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */
>
> printf(echoBuffer); /* Print the echo buffer */
> }
>
> printf("\n\n"); /* Print a final linefeed */
>
> ext_close(sock);
>
> exit(0);
> }
> *********************************************************************
>
>
> ----Original Message Follows----
> From: Thomas Dreibholz
> <dreibh AT irmgard.exp-math.uni-essen.de>
> To: "Oon Heok Kee"
> <oonheokkee78 AT hotmail.com>
> CC:
> discussion AT sctp.de
> Subject: Re: [SCTP-Discussion] Sending by which stream?
> Date: Sun, 1 Sep 2002 11:53:50 +0200
>
> On Freitag, 30. August 2002 15:13, Oon Heok Kee wrote:
> > Hi,
> >
> > Suppose a client computer is initialised with 3 out and 2 incoming
> > streams, and the server with 2 out and 3 incoming streams. When the
>
> client
>
> > sends an INIT packet with sinfo_stream=1, should the Stream ID for the
> > first data packet be shown as 0 or 1? Or does it ever change? Because I
> > distinctively set the sinfo_stream value in struct sndrcvinfo to 1, but
>
> no
>
> > matter what, the data packet is always sent via stream ID 0. Anyone
> > experienced this before? Thanks a million!! :)
>
> Please send me your program's source code. Then, I can check it.
>
>
> Best regards


Best regards
- --
=======================================================================
Dipl.-Inform. Thomas Dreibholz

University of Essen, Room ES210
Inst. for Experimental Mathematics Ellernstraße 29
Computer Networking Technology Group D-45326 Essen/Germany
- -----------------------------------------------------------------------
E-Mail:
dreibh AT exp-math.uni-essen.de
Homepage: http://www.exp-math.uni-essen.de/~dreibh
=======================================================================
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE9cyUD32BbsHYPLWURAo2HAJ43VsQPhuEDR5hwC8vfGdHgCY0M7QCfZf6M
1BkJeP3mr5sAtguNqW0HrqU=
=maFQ
-----END PGP SIGNATURE-----
/* Echo Client Example */

/* SCTP client */

/* Compile this file with "gcc -o sctp_client sctp_client.c -Wall -lsctpsocket -lsctp -lglib -lstdc++ -lpthread". */

#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <sys/types.h>
#include <sys/time.h>
#include <ext_socket.h>
#include <net/route.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sctp.h>

#define RCVBUFSIZE 16 /* Size of receive buffer */
#define OUTSTREAM 3 /* Number of out-bound streams */
#define INSTREAM 2 /* Number of in-bound streams */


void DieWithError(char *errorMessage)
{
   perror(errorMessage);
   exit(1);
}


int main(int argc, char *argv[])
{
   int sock; /* Socket descriptor */
   struct sockaddr_in echoServAddr;/* Echo server address */
   unsigned short echoServPort; /* Echo server port */
   char *servIP; /* Server IP address (dotted quad) */
   char *echoString; /* String to send to echo server */
   char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */
   unsigned int echoStringLen; /* Length of string to echo */
   int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv() and total bytes read */
   struct sctp_initmsg sim;
   struct sctp_sndrcvinfo *sinfo;
   struct msghdr msg[1];
   struct cmsghdr *cmsg;
   struct iovec iov[1];
   char cbuf[sizeof(*cmsg) + sizeof(*sinfo) + sizeof(*echoString)];
   struct sctp_event_subscribe events;

   /* Test for correct number of arguments */
   if ((argc < 3) || (argc > 4)) {
      fprintf(stderr, "Usage: %s <Server IP> <Echo Word> [<Echo Port>]\n",argv[0]);
      exit(1);
   }

   servIP = argv[1]; /* First arg: server IP address (dotted quad) */

   echoString = argv[2]; /* Second arg: string to echo */

   if (argc == 4)
      echoServPort = atoi(argv[3]); /* Use given port, if any */
   else
      /* 7 is the well-known port for the echo service */
      echoServPort = 7;

   printf("\nCreating socket... ");
   /* Create a reliable, stream socket using TCP */
   if ((sock = ext_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0)
   {
      DieWithError("socket() failed");
   }
   printf("Socket created.\n\n");

   (&sim)->sinit_num_ostreams = OUTSTREAM;
   (&sim)->sinit_max_instreams = INSTREAM;
   (&sim)->sinit_max_attempts = 3;
   (&sim)->sinit_max_init_timeo = 30;



   /* Setting socket options */
   if (ext_setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, &sim, sizeof(sim)) < 0)
   {
      DieWithError("setsockopt() failed");
   }

   memset((char*)&events,0,sizeof(events));
   events.sctp_data_io_event = 1;
   if (ext_setsockopt(sock, IPPROTO_SCTP, SCTP_SET_EVENTS, &events, sizeof(events)) < 0) {
      DieWithError("setsockopt() failed");
   }

   memset(msg, 0, sizeof(*msg));
   msg->msg_control = cbuf;
   msg->msg_controllen = sizeof(struct cmsghdr) + sizeof(struct sctp_sndrcvinfo);
   msg->msg_flags = 0;

   (&iov[0])->iov_base = echoString; /*testbuf;*/
   (&iov[0])->iov_len = strlen(echoString); /*nr;*/

   msg->msg_iov = (struct iovec*)&iov;
   msg->msg_iovlen = 1;

   cmsg = (struct cmsghdr *)cbuf;
   sinfo = (struct sctp_sndrcvinfo *)(cmsg + 1);

   cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct sctp_sndrcvinfo);
   cmsg->cmsg_level = IPPROTO_SCTP;
   cmsg->cmsg_type = SCTP_SNDRCV;

   sinfo->sinfo_assoc_id = 0;
   sinfo->sinfo_stream = 1; /* streamNumber */
   sinfo->sinfo_flags = 0;
   sinfo->sinfo_ppid = 0x12345678; /* ppid */
   sinfo->sinfo_context = (uint32_t)NULL;
   sinfo->sinfo_timetolive = (unsigned int)-1;

   /* Construct the server address structure */
   /* Zero out structure */
   memset(&echoServAddr, 0, sizeof(echoServAddr));

   echoServAddr.sin_family = AF_INET; /* Internet address family */

   /* Server IP address */
   echoServAddr.sin_addr.s_addr = inet_addr(servIP);

   echoServAddr.sin_port = htons(echoServPort); /* Server port */

   printf("Connecting to server at %s:%u ... ", servIP, echoServPort);
   /* Establish the connection to the echo server */
   if (ext_connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
      DieWithError("connect() failed");
   printf("Connected.\n\n");

   echoStringLen = strlen(echoString); /* Determine input length */

   printf("Sending message \"%s\" to server... ", echoString);
   /* Send the string to the server */
   if (ext_sendmsg(sock, msg, 0) < 0)
      DieWithError("send() failed!");
   printf("Message sent.\n\n");

   /* Receive the same string back from the server */
   totalBytesRcvd = 0;


   (&iov[0])->iov_base = echoBuffer;
   (&iov[0])->iov_len  = sizeof(echoBuffer);
   msg->msg_iov = (struct iovec*)&iov;
   msg->msg_iovlen = 1;
   msg->msg_control = cbuf;
   msg->msg_controllen = sizeof(cbuf);
   msg->msg_flags = 0;
   msg->msg_name = NULL;
   msg->msg_namelen = 0;


   printf("Receiving echo from server... ");
   printf("Received: "); /* Setup to print the echoed string */

   while (totalBytesRcvd < echoStringLen)
   {
      /* Receive up to the buffer size (minus 1 to leave space for a null terminator) bytes from the sender */
      if ((bytesRcvd = ext_recvmsg(sock, msg, 0)) <= 0) /*echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)*/
         DieWithError("recv() failed or conn. closed prematurely");
         totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */

         echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */

         printf(echoBuffer); /* Print the echo buffer */

         if(msg->msg_controllen > 0) {
            cmsg = CMSG_FIRSTHDR(msg);
            if((cmsg != NULL) && (cmsg->cmsg_level == IPPROTO_SCTP) && (cmsg->cmsg_type == SCTP_SNDRCV)) {
               sinfo = (struct sctp_sndrcvinfo*)CMSG_DATA(cmsg);
               printf("Stream ID:   %d\n",sinfo->sinfo_stream);
               printf("Protocol ID: %08x\n",sinfo->sinfo_ppid);
            }
         }
      }

   printf("\n\n"); /* Print a final linefeed */

   ext_close(sock);

   usleep(100000);
   exit(0);
}



Archive powered by MHonArc 2.6.19+.

Top of page