Wael Showair
Wael Showair

Reputation: 3102

UDP Sockets on Linux; send successfully but unable to receive large buffer

I have two machines, that I would like both of them to communicate using sockets under C programming language.

I have developed two samples to represent both sides but I noticed that I can send data successfully if they are smaller than certain number.

The size that I have tested but does not work is sending & receiving 2048 bytes , on contrary, for other smaller sizes such as 258 Bytes, 1KByte it works fine.

After doing some investigations, I found out that, the sending operation has no errors while for the reception, I did not get any thing at all.

I have checked the sending and receiving buffer sizes on both machines and I guess they are sufficient.

Here are the first side of my code:

/* UDP client in the internet domain */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#define BUFF_SIZE               1800
#define MOBIPASS_L2_IP_ADDRESS  "192.168.13.53"
#define MOBIPASS_L2_PORT_NUM    12001

#define BRIDGE_IP_ADDRESS       "192.168.13.30"
#define BRIDGE_PORT_NUM         12000

#define RESTRICT_SRC_DST_NUM        1
#define TEN_MSEC                    10000

void error(const char *);
void adjustSockParam (int sockFD);

int main(int argc, char *argv[])
{
#if RESTRICT_SRC_DST_NUM

    int bridge_sock_fd = -1, n =-1;
    struct sockaddr_in server_mobipass, client_bridge;
    char buffer[BUFF_SIZE];
    char* choice = NULL;
    size_t size = 1;

    /* create socket descriptor at client machine*/
    bridge_sock_fd= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (bridge_sock_fd < 0) error("socket");

    /* *********************************************************
     * prepare source information of the socket file descriptor
     * *********************************************************
     */
    client_bridge.sin_family = AF_INET;
    client_bridge.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS) ;
    client_bridge.sin_port = htons(BRIDGE_PORT_NUM);
    if( bind( bridge_sock_fd, (struct sockaddr *) &client_bridge, sizeof ( client_bridge ) ) < 0 )
    {
        error( "bind" );
    }


    /* *********************************************************
     * prepare destination information of the socket file descriptor
     * *********************************************************
     */
    server_mobipass.sin_family = AF_INET;
    server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
    server_mobipass.sin_port = htons(MOBIPASS_L2_PORT_NUM);
    if( connect( bridge_sock_fd, (struct sockaddr *) &server_mobipass, sizeof ( server_mobipass ) ) < 0 ) {
        error("connect");
    }

    adjustSockParam(bridge_sock_fd);
    do
    {
        printf("sending traffic?[y/n]\n");
        getline(&choice,&size,stdin);
        if(*choice=='n')
            break;

        strncpy( buffer,
                    "Hello Mobipass, this is bridge :)\n",
                    sizeof(buffer));
        n = send( bridge_sock_fd, buffer, sizeof(buffer), MSG_CONFIRM  );
        if( n < 0 )
        {
            error( "send" );
        }

        assert(n == sizeof(buffer));

        usleep(TEN_MSEC);
        /*memset(buffer,0 , sizeof(buffer));

        if( recv( bridge_sock_fd, buffer, sizeof(buffer), 0 ) < 0 )
        {
            error( "recv" );
        }
        else
        {
            printf("Msg received from mobipass is:\n%s",buffer);
        }*/


    }while(*choice == 'y' || *choice == 'Y');

    close( bridge_sock_fd );

#else
   int tx_sock, n, rx_sock;
   unsigned int srv_length;
   struct sockaddr_in server_mobipass, from, server_bridge;
   char buffer[256];

   /* create socket descriptor at client machine*/
   tx_sock= socket(AF_INET, SOCK_DGRAM, 0);
   if (tx_sock < 0) error("socket");

   srv_length=sizeof(struct sockaddr_in);

   /*prepare server (peer entity) of UDP connection*/
   server_mobipass.sin_family = AF_INET;
   server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
   server_mobipass.sin_port = htons(MOBIPASS_L2_PORT_NUM);

   printf("Please enter the message: ");
   bzero(buffer,256);
   fgets(buffer,255,stdin);

   n=sendto(tx_sock,buffer,
            strlen(buffer),0,(const struct sockaddr *)&server_mobipass,srv_length);
   if (n < 0) error("Sendto");

   rx_sock= socket(AF_INET, SOCK_DGRAM, 0);
   if (rx_sock < 0) error("socket");

   server_bridge.sin_family =  AF_INET;
   server_bridge.sin_addr.s_addr = inet_addr(BRIDGE_IP_ADDRESS);
   server_bridge.sin_port = htons(BRIDGE_PORT_NUM);
   if (bind(rx_sock,(struct sockaddr *)&server_bridge,srv_length)<0)
          error("binding");

   n = recvfrom(rx_sock,buffer,256,0,(struct sockaddr *)&from, &srv_length);
   if (n < 0) error("recvfrom");

   /*print to stdout what have been received*/
   write(1,"Got an ack: ",12);
   write(1,buffer,n);





   /* close sockets */
   close(rx_sock);
   close(tx_sock);

#endif /* RESTRICT_SRC_DST_NUM */
   return 0;
}

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

void adjustSockParam (int sockFD)
{

    int option_value;
    socklen_t option_len = sizeof(option_value);

    /** Adjust Send Buffer Size**/
    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Initial SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);

    /*option_value = 2048;
    if( setsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, option_len)< 0)
    {
        error("get Socket Option error:");
    }

    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Final SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);*/

    /** Adjust Receiver Buffer Size **/
    if( getsockopt(sockFD, SOL_SOCKET, SO_RCVBUF,
               &option_value, &option_len)< 0)
        {
            error("get Socket Option error:");
        }
        printf("Initial SO_RCVBUF: option_len = %d option_value = %d\n",option_len,option_value);
}

Here are the second side of my code:

#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <assert.h>

#define BUFF_SIZE               1800
#define MOBIPASS_L2_IP_ADDRESS  "192.168.13.53"
#define MOBIPASS_L2_PORT_NUM    12001

#define BRIDGE_IP_ADDRESS       "192.168.13.30"
#define BRIDGE_PORT_NUM         12000

#define DUMP                        0
#define ACT_AS_STRING               0
#define RESTRICT_SRC_DST_NUM        1
#define TEN_MSEC                    10000

#if DUMP
    #define DUMP_BUFFER(buf,len)                \
    {                                           \
        int i;                                  \
        for(i = 0; i < len; i++)                \
            printf("buf[%d] = 0x%x",i,buf[i]);  \
    }
#else
    #define DUMP_BUFFER(buf,len)        printf("received len=%d\n",len)
#endif

void adjustSockParam (int sockFD);
void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
#if RESTRICT_SRC_DST_NUM
    int mobipass_sock_fd = -1;
    struct sockaddr_in server_mobipass, client_bridge;
    char buffer[BUFF_SIZE];
    int recivedBytes=-1;

    printf("size of buffer = %d\n",sizeof(buffer));
    /* create socket descriptor at client machine*/
    mobipass_sock_fd= socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (mobipass_sock_fd < 0) error("socket");

    /* *********************************************************
     * prepare source information of the socket file descriptor
     * *********************************************************
     */
    client_bridge.sin_family = AF_INET;
    client_bridge.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS) ;
    client_bridge.sin_port = htons(MOBIPASS_L2_PORT_NUM);
    if( bind( mobipass_sock_fd, (struct sockaddr *) &client_bridge, sizeof ( client_bridge ) ) < 0 )
    {
        error( "bind" );
    }


    /* *********************************************************
     * prepare destination information of the socket file descriptor
     * *********************************************************
     */
    server_mobipass.sin_family = AF_INET;
    server_mobipass.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS) ;
    server_mobipass.sin_port = htons(BRIDGE_PORT_NUM);
    if( connect( mobipass_sock_fd, (struct sockaddr *) &server_mobipass, sizeof ( server_mobipass ) ) < 0 ) {
        error("connect");
    }

    adjustSockParam(mobipass_sock_fd);

    printf("waiting for message from bridge:\n");
    do{
        memset(buffer,0 , sizeof(buffer));
        recivedBytes = recv( mobipass_sock_fd, buffer, sizeof(buffer), 0 );
        if( recivedBytes  < 0 )
        {
            error( "recv" );
        }
        else
        {
            assert(recivedBytes == sizeof(buffer));
            DUMP_BUFFER(buffer,recivedBytes);
#if ACT_AS_STRING
            printf("Msg received from bridge is:\n%s",buffer);
#endif
        }
        usleep(TEN_MSEC);
#if ACT_AS_STRING
        strncpy( buffer,
                    "Hello Bridge, this is mobipass :)\n",
                    sizeof(buffer));
        if( send( mobipass_sock_fd, buffer, sizeof(buffer), 0 ) < 0 )
        {
            error( "send" );
        }
#endif
    }while(1);

    close( mobipass_sock_fd );

#else
    int tx_sock, n, rx_sock;
    unsigned int srv_length;
    socklen_t fromlen;
    struct sockaddr_in server_mobipass, from, server_bridge;
    char buf[1024];


    rx_sock=socket(AF_INET, SOCK_DGRAM, 0);
    if (rx_sock < 0) error("Opening socket");
    else printf("Creating rx udp socket\n");

    srv_length = sizeof(server_mobipass);
    bzero(&server_mobipass,srv_length);

    server_mobipass.sin_family=AF_INET;
    server_mobipass.sin_addr.s_addr=inet_addr(MOBIPASS_L2_IP_ADDRESS);
    server_mobipass.sin_port=htons(MOBIPASS_L2_PORT_NUM);

    if (bind(rx_sock,(struct sockaddr *)&server_mobipass,srv_length)<0)
    error("binding");
    else
    printf("Binding a socket to a server IP address\n");
    fromlen = sizeof(struct sockaddr_in);

    tx_sock=socket(AF_INET, SOCK_DGRAM, 0);
    if (tx_sock < 0) error("Opening socket");
    else printf("Creating tx udp socket\n");

    server_bridge.sin_family=AF_INET;
    server_bridge.sin_addr.s_addr=inet_addr(BRIDGE_IP_ADDRESS);
    server_bridge.sin_port=htons(BRIDGE_PORT_NUM);

    while (1)
    {
    printf("waiting for a message from client side:\n");
    n = recvfrom(rx_sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
    if (n < 0) error("recvfrom");

    write(1,"Message received from eNB machince:\n",36);
    write(1,buf,n);

    n = sendto(tx_sock,"hello eNB, I am mobipass\n",27,
              0,(struct sockaddr *)&server_bridge,fromlen);
    if (n  < 0) error("sendto");
    }

#endif
    return 0;
 }

void adjustSockParam (int sockFD)
{

    int option_value;
    socklen_t option_len = sizeof(option_value);

    /** Adjust Send Buffer Size**/
    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Initial SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);

/*  option_value = 2048;
    if( setsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, option_len)< 0)
    {
        error("get Socket Option error:");
    }

    if( getsockopt(sockFD, SOL_SOCKET, SO_SNDBUF,
           &option_value, &option_len)< 0)
    {
        error("get Socket Option error:");
    }
    printf("Final SO_SNDBUF: option_len = %d option_value = %d\n",option_len,option_value);*/

    /** Adjust Receiver Buffer Size **/
    if( getsockopt(sockFD, SOL_SOCKET, SO_RCVBUF,
               &option_value, &option_len)< 0)
        {
            error("get Socket Option error:");
        }
        printf("Initial SO_RCVBUF: option_len = %d option_value = %d\n",option_len,option_value);
}

Here is the output on first side:

Initial SO_SNDBUF: option_len = 4 option_value = 112640
Initial SO_RCVBUF: option_len = 4 option_value = 112640
sending traffic?[y/n]
y
sending traffic?[y/n]
y

Here is the output on second side:

size of buffer = 1800
Initial SO_SNDBUF: option_len = 4 option_value = 1048576
Initial SO_RCVBUF: option_len = 4 option_value = 1048576
waiting for message from bridge:

I am not sure what I am doing wrong here. Do you any suggestions?

Upvotes: 2

Views: 1912

Answers (1)

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84239

While UDP datagram packet size could be up to 64K (16-bit data length field), the usual underlying data link technology - ethernet - has a frame size of 1500 bytes. Less at least 20 bytes for IP header, less 8 bytes of UDP header, that leaves only 1472 bytes for UDP payload that could be sent without IP fragmentation, which usually leads to issues like in your case where packets are just dropped somewhere.

Most UDP-based protocols restrict datagram size for exactly this reason.

Upvotes: 3

Related Questions