This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: FreeBSD problem with UDP sockets


On Wed, Aug 11, 2004 at 08:10:46PM -0700, David Brennan wrote:
> I am currently having a problem with FreeBSD sockets.
> Setup: i386-pc 82559, latest snapshot from snapshot service.
> 
> Background: Our application uses a UDP communication protocol over 2
> sockets. Each one is a validated half duplex channel. That is the
> sendSocket will receive acknowledgments of previous sends and recvSocket
> will send acknowledgments of previous receives.
> Implementation: I open two (UDP) sockets (sendSocket, and recvSocket).
> I then do a select on either port. Once I receive a packet, I query each
> socket to see if FD_ISSET. When I send a packet (from extenal host) to 
> the second socket checked (recvSocket), the first socket returns with 
> FD_ISSET, then my code goes into a blocking recvfrom and hangs since no 
> data was actually on that socket..
> 
> Here are code snippets showing how the sockets are created, selected,
> then received. This code has worked fine in pSOS and VxWorks, so I don't
> think there is a fundamental problem here, unless there is some secret
> to eCos implementation of BSD sockets.
> 
> Any help would be greatly appreciated.
> 
> David Brennan
> 
> // Two sockets are created (sendSocket, recvSocket):
> 
>    //  Create the socket
>    socketM = socket(AF_INET, SOCK_DGRAM, 0);
> 
>    if (socketM < 0)
>    {
>        FATALSYS(("Cannot create socket"));
>    }
> 
>    sockAddrInT localAddr((inAddrT((ULong) INADDR_ANY)), localPortI);
> 
>    //  Bind the socket to local address and port number
>    int err = bind(socketM, &localAddr, sizeof(sockaddr_in));
>    if( err < 0 )
>    {
>        str32T addrS;
>        FATALSYS(("Can't bind socket to local IP port %s:%d",
>                  localAddr.AddrStr(addrS.CharP()),
>                  localPortI
>                ));
>    }
> 

So the above code creates socketM. Fine.
> 
> // Sockets are waited on for receive data (infinite wait):
> 
>    fd_set readMask;
> 
>    FD_ZERO(&readMask);
>    pAssert(InRange(sendSocket, 0, FD_SETSIZE-1));           // Limit to
> keep FD_SET from writing out of readfds
>    pAssert(InRange(recvSocket, 0, FD_SETSIZE-1));           // Limit to
> keep FD_SET from writing out of readfds
>    FD_SET(sendSocket, &readMask);
>    FD_SET(recvSocket, &readMask);
> 
>    //  Use select to wait for input from either the send or receive
> sockets
>    long err = select(FD_SETSIZE, &readMask, NULL, NULL, NULL);

Here you are using sendSocket and recvSocket which we have not seen
created. If we get passed select we know that one of these two sockets
has data on them.

 
>    if( err < 0 )
>    {
>        FATALSYS(("select()=%d ", err));
>        return( 0 );
>    }
> 
> // Once select() returns successfully, check each socket (sendSocket,
> recvSocket) for data:
> 
>    // Set of socket/file descriptors
>    fd_set readfds;
> 
>    // Clear all socket selections from the read file descriptor set
>    FD_ZERO(&readfds);
> 
>    // Select only this socket in the read file descriptor set
>    // Limit to keep FD_SET from writing out of readfds
>    pAssert(InOrderedRange(socketM, 0, FD_SETSIZE-1));
>    FD_SET(socketM, &readfds);
> 
>    // Create a wait timeout
>    timeval waitTime;
>    waitTime.tv_sec = 0L;
>    waitTime.tv_usec = 0;
> 
>    // Use select on this socket to determine if there is pending read data
>    int result = select(FD_SETSIZE,
>                        &readfds,
>                        NULL,
>                        NULL,
>                        &waitTime
>                       );

Now we are back to socketM.

What is not clear for me is the relationship between sendSocket,
recvSocket and socketM. 

>    if( result < 0 )
>    {
>        FATALSYS(("Error in: select(%d)", socketM));
>    }
> 
>    int isSet = FD_ISSET(socketM, &readfds);

Here is your problem. With passing {0,0} for waitTime, you are doing a
poll. If there is nothing to receive on the socket, select will return
0, but it is not updating the readfds. Read the code in
packages/io/fileio/current/src/select.cxx.

This might be an eCos bug. It might not be as well.  The Posix
standard at not 100% clear on this issue when i read
it. http://www.opengroup.org/onlinepubs/009695399/toc.htm

    On failure, the objects pointed to by the readfds, writefds, and
    errorfds arguments shall not be modified. If the timeout interval
    expires without the specified condition being true for any of the
    specified file descriptors, the objects pointed to by the readfds,
    writefds, and errorfds arguments shall have all bits set to 0.

When you have passed a timeout of {0,0} you are doing a poll. So the
timeout has not expired. However, we are not returning an error code
so it could also be said we are not in the failure case either.

To make your code work with eCos, check to see if the return value is
> 0. 


> 
>    if( isSet != 0 )
>    {
>        respPktT respPkt;
>        sockAddrInT sendersAddr;
> 
>        recvfrom( socketM,
>                  (char *) (&respPkt),
>                  sizeof(respPkt),
>                  0,                      // flags
>                  (sockaddr *) (&sendersAddr),
>                  (socklen_t) sizeof(sendersAddr)
>                )
>    }


        Andrew

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]