TCP/IP - Sockets appear to be restricted to maximum 65,535 byte transfers

From: Roy Omond (Roy.Omond_at_BlueBubble.UK.Com)
Date: 03/07/05


Date: Mon, 07 Mar 2005 15:51:56 +0000

Gentle colleagues,

this is becoming a bit of a showstopper for me:

A very simple pair of programs (Server and Client) are setup
to transfer a quantity of data via a TCP Socket. The background
to this is actually in trying to get this to work in UCX v3.3 ECO 3,
whereas it worked flawlessly (and as per the documentation) in
vanilla UCX v3.3 (without ECO), running under VAX VMS 6.2.

The problem is easily demonstrated on VMS 7.3-2 (Alpha) with
TCP/IP Services v5.4 ECO 4, as well as all the versions after
UCX v3.3 ECO 3 and above (both VAX and Alpha).

The Server process establishes a socket, listens for an accept on the
socket (which the Client sends), and sends an amount of data down the
socket to the client. That's it. It works fine with data up to and
including 65,535 bytes. Beyond this, it returns an error
("%system-f-ivbuflen, invalid buffer length").
I can find no mention in the documentation "TCP/IP Sockets API
and System Services Programming" of any such restriction on the
amount of data to transfer.

Here are the 2 small programs:

--- cut here ---

$ create client.c
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "sys/ioctl.h"
#include <netdb.h>
/*
struct hostent
*VGetHostByName(char *name)
{
         struct hostent *h;
         int i;

         if (name == NULL)
         {
           return(NULL);
         }
         sethostent( 1 );

         while ((h = gethostent()) != NULL)
             {
                 if (strcmp(name,h->h_name) == 0) {
                         endhostent();
                         return(h);
                 }
                 i = 0;
                 while (h->h_aliases[i] != NULL) {
                         if (strcmp(name,h->h_aliases[i]) == 0) {
                                 endhostent();
                                 return(h);
                         }
                         i++;
                 }
         }
         endhostent();
         return( NULL );
}*/

main (int argc, char ** argv)
{
         int sock;
         int byte_count;
         int bcount;
         char data[1000000];
         int sendbuf;
         int len;

         static struct hostent *mh,master_host;
         static struct sockaddr_in sin;

         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
         {
                 perror ("Create Socket:");
                 printf ("errno in CreateSock is %d\n", errno);
                 return(-1);
         }

         if (argc > 1)
         {
                 printf ("Connecting to host %s\n", argv[1]);
                 mh = GetHostByName(argv[1]);
                 if (mh == NULL)
                 {
                         perror ("GetHostByName:");
                         printf ("Can't get host name %s\n", argv[1]);
                         close(sock);
                         return (-1);
                 }
         }
         else
         {
                 printf ("Need a host name\n");
                 return (-1);
         }

         master_host = *mh;

         sin.sin_family = master_host.h_addrtype;
         sin.sin_port = 50000;
         memcpy(&sin.sin_addr, master_host.h_addr, master_host.h_length);

         if (connect(sock, &sin, sizeof(struct sockaddr_in)) == -1)
         {
                 perror ("Connect:");
                 return (-1);
         }

         len = sizeof(sendbuf);
         if (getsockopt(sock,SOL_SOCKET,SO_SNDBUF,&sendbuf,&len) < 0)
         {
                 perror("getsockopt SO_SNDBUF");
         }
         printf("Send buffer %d bytes\n",sendbuf);

         while (1)
         {
                 ioctl(sock, FIONREAD, &bcount);

                 if (bcount > 0)
                 {
                  int cnt = 0;
      if ((bcount = read (sock, (char *)&byte_count,sizeof(int))) == -1)
                     {
                        perror ("Read data size");
                        return (-1);
                     }
printf ("Read %d bytes, count is %d\n", bcount, byte_count);

                         bcount = 0;
                         while (cnt < byte_count)
                         {
          if ((bcount = read (sock, data, byte_count - cnt)) == -1)
                             {
                                     perror ("Read data");
                                     return (-1);
                             }
                             printf ("Read %d\n", bcount);
                             cnt += bcount;
                         }
                         printf ("Read %d bytes total\n", cnt);
                         break;
                 }
         }
}

$ create server.c
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ucx$inetdef.h>

int
writevv (int fd, struct iovec * iov, int iovcnt)
{
         int total_bytes = 0, bytes, i;

         for (i = 0; i < iovcnt; i++)
         {
                 bytes = write (fd, iov[i].iov_base, iov[i].iov_len);
                 if (bytes == -1)
                 {
                         perror ("write:");
                         return (-1);
                 }
                 else
                 {
                         total_bytes += bytes;
                 }
         }
         return (total_bytes);
}

main (int argc, char ** argv)
{

         int serv_sock = -1;
         int client_sock = -1;
         int len;

         int data_size = 1000;

         if (argc >= 2) data_size = atoi(argv[1]);

         if ((serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
         {
                 perror ("Create Socket:");
                 printf ("errno in CreateSock is %d\n", errno);
                 return(-1);
         }

         len=sizeof(data_size);

       if (setsockopt(serv_sock,SOL_SOCKET,SO_SNDBUF,&data_size,len) < 0)
         {
                 perror("setsockopt SO_SNDBUF");
         }

       if (setsockopt(serv_sock,SOL_SOCKET,SO_RCVBUF,&data_size,len) < 0)
         {
                 perror("setsockopt SO_RCVBUF");
         }
         printf("Send/Receive buffer %d bytes\n",data_size);

         {
                 static struct sockaddr_in sin;
                 sin.sin_family = htons(AF_INET);
                 sin.sin_port = 50000;
                 sin.sin_addr.s_addr = htonl(INADDR_ANY);

                 if (bind(serv_sock, &sin, sizeof(sin)) == -1)
                 {
                         printf("cannot bind socket to port");
                         perror ("Bind:");
                         return(-1);
                 }
         }

         if (listen(serv_sock, 20) == -1)
         {
                 printf("cannot set listen(s,20)");
                 perror ("Listen:");
                 return(-1);
         }

         if ((client_sock = accept(serv_sock, NULL, NULL)) > 0)
         {
                 struct iovec iov[2];
                 int count;
                 static char data[1000000];

                 if (data_size > 1000000) data_size = 1000000;
                 iov[0].iov_base = (char *) &data_size;
                 iov[0].iov_len = sizeof(int);
                 iov[1].iov_base = &data;
                 iov[1].iov_len = data_size;

                 if (writevv(client_sock,iov,2) == -1)
                 {
                         perror ("writev:");
                         return (-1);
                 }
                 sleep(10);
         }
}
$ server:=$u:[xxxx]server
$ client:=$u:[xxxx]client
$ spawn/nowait server 65536
$ client my-node-name

Any comments ? Any suggestions ? I thinks this, at worst, a
bug in the Socket implementation, or, at "best", a serious
omission in the documentation.

Note, as mentioned above, this worked fine in UCX v3.3, but
not in UCX v3.3 ECO 3 or later.

Many thanks in advance,

Roy Omond
Blue Bubble Ltd.



Relevant Pages

  • Re: [patch 01/03] USB: USB/IP: add common functions needed
    ... This adds the common functions needed by both the host and client side ... +int setnodelay(struct socket *socket) ... This header adds a lot of symbols which have fairly generic-sounding ...
    (Linux-Kernel)
  • [patch 01/03] USB: USB/IP: add common functions needed
    ... This adds the common functions needed by both the host and client side ... * GNU General Public License for more details. ... +static void usbip_dump_pipe(unsigned int p) ... +int setquickack(struct socket *socket) ...
    (Linux-Kernel)
  • Re: Wait on a server socket for 10 seconds
    ... I read the following code which open a server socket for client ... // Create socket for listening for client connection requests. ... int reliable_recvfrom(int fd, void *data, int size, int flags, ...
    (comp.unix.programmer)
  • Problem with synchronous Socket
    ... I need to implement a socket server. ... private int Read ... Polling 100ms"); ... just enough to give the client enough time to send more data. ...
    (microsoft.public.dotnet.framework)
  • [PATCH 0/5] [RFC] AF_RXRPC socket family implementation [try #3]
    ... These patches together supply secure client-side RxRPC connectivity as a Linux ... kernel socket family. ... presentation side is left to the client. ... Each connection goes to a particular "service". ...
    (Linux-Kernel)