8.4. The recvfrom() API call

Just as the sendto() API adds an address and port to the send() API, so does the recvfrom() API add an address and port to the recv() API.

Sometimes in a TCP socket, you don't bother to keep track of where the connection comes from. You don't need to. You don't care. With TCP, the API takes care of making sure your responses get where they need to go.

This is not true with UDP. Each datagram stands alone. You need to read in the address that a datagram came from so that you know who to respond to -- that is, if your application requires responses at all.

So, when you supply an address and length in the recvfrom API, it's to receive the address and port that the datagram originated with. You can use it to reply!

The IBM manual page for the recvfrom() API is found right about here: http://publib.boulder.ibm.com/pubs/html/as400/v4r5/ic2924/info/apis/recvfr.htm

And it tells us that the C-language prototype for the recvfrom() API looks like this:

              int recvfrom(int socket_descriptor,
                            char *buffer,
                            int buffer_length,
                            int flags,
                            struct sockaddr *from_address,
                            int *address_length);

Yes, it's just like recv(), except that they've added a socket address structure, and an address length. You'll see that the address length is passed by pointer -- this is because the length depends on what the sending program sends us, just like it did with the accept() API.

The RPG version of recvfrom() looks like this:

         D recvfrom        PR            10I 0 ExtProc('recvfrom')    
         D   sock_desc                   10I 0 Value                  
         D   buffer                        *   Value                  
         D   buffer_len                  10I 0 Value                  
         D   flags                       10I 0 Value                  
         D   fromaddr                      *   Value                  
         D   addrlength                  10I 0                        

You'll note that we're passing the address length parameter 'by address' instead of passing a pointer to an integer. This looks exactly the same to the API that receives the parameter, but allows the compiler to do some better validity checking.

Add this to your SOCKET_H member, please.

Here's how we call recvfrom:

         C                   eval      datalen = recvfrom(s: %addr(buf):    
         c                                %size(buf): 0: fromaddr: fromlen) 
         c                   if        datalen < 0                          
         c*** Error occurred, check errno!                                  
         c                   endif