DIGITAL TCP/IP Services for OpenVMS
System Services and C Socket Programming


Previous Contents Index

2.8.2 Getting Device Socket Information with a C Socket Interface

You can use any of the following C Socket routines to get device socket information:

Example 2-14 shows a TCP server using the getsockopt(), getpeername() and, getsockname() routines to get device socket information.

Example 2-14 Obtaining Device Socket Information by Using C Socket Programming

/* This program accepts a connection on TCP port 1234, sends the string, 
   "Hello, world!", and immediately closes the connection and terminates. */ 
 
#if defined(__VMS) || defined(VMS) 
#include <types.h> 
#include <in.h> 
#include <socket.h> 
#include <unixio.h> 
#include <string.h> 
#else 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <unistd.h> 
#include <string.h> 
#endif 
 
#define PORTNUM 1234 
 
main() { 
 struct sockaddr_in lcladdr, name; 
 int r, s, namelen = sizeof(name), one = 1; 
 char *message = "Hello, world!\r\n"; 
        memset( &lcladdr, 0, sizeof(lcladdr)); 
 
 lcladdr.sin_family = AF_INET; 
 lcladdr.sin_addr.s_addr = INADDR_ANY; 
 lcladdr.sin_port = htons(PORTNUM); 
 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket"); 
 if (setsockopt(s,(1)
                       SOL_SOCKET,   (2)
                       SO_REUSEADDR, (3)
                       &one,         (4)       
                       sizeof(one))) (5)
              perror("setsockopt"); 
 if (bind(s, &lcladdr, sizeof(lcladdr))) perror("bind"); 
 if (listen(s, 1)) perror("listen"); 
 if ((r = accept(s, 0, 0)) < 0) perror("accept"); 
 if (getsockname(r,(6)
&name,(7)&namelen(8)))perror("getsockname"); 
 else printf("Local address:  %s\tport: %d\n", 
      inet_ntoa(name.sin_addr.s_addr), 
      ntohs(name.sin_port)); 
 if (getpeername(r,(9) &name,(10)
&namelen))(11) perror("getpeername"); 
 else printf("Remote address: %s\tport: %d\n", 
      inet_ntoa(name.sin_addr.s_addr), 
      ntohs(name.sin_port)); 
 if (send(r, message, strlen(message), 0) != strlen(message)) 
  perror("send"); 
 if (close(r)) perror("close"); 
 if (close(s)) perror("close"); 
} 

  1. s is the socket descriptor created in a previous call to the socket() routine.
  2. SOL_SOCKET sets the options at the socket level.
  3. SO_RESUSEADDR specifies that local addresses can be reused.
  4. &one points to the buffer that contains the parameters of the SO_REUSEADDR option.
  5. sizeof(one) indicates the size of the one buffer.
  6. r specifies the remote socket descriptor.
  7. &name points to the buffer in which the routine returns the socket name.
  8. &namelen specifies the length of the buffer to which name points.
  9. r is the remote socket descriptor.
  10. &name points to the buffer in which the routine returns the peer name.
  11. &namelen specifies the length of the buffer to which name points.

2.9 Reading Data

TCP/IP allows the application to read data after it performs the following:

2.9.1 Reading Data with OpenVMS System Services

The $QIO IO$_READVBLK function transfers data received from the internet host (kept in system dynamic memory) into the address space of the user's process. After the read operation completes, the data in dynamic memory is discarded.

Example 2-15 shows a TCP/IP server using the IO$_READVBLK function to read data into a single I/O buffer.

Example 2-15 Reading Data Using OpenVMS System Services

 
/* 
** 
**  Attempt to receive data from the server. 
**  Use the function code of IO$_READVBLK, passing the address of the 
**  buffer to P1 and the maximum size of the buffer to P2. 
** 
*/ 
    printf("\n    Attempt to receive data from the server.\n" ); 
 
    memset( IOBuff, 'Z', MaxBuff ); 
    sysSrvSts = sys$qiow( 0,              /* efn.v | 0 */ 
                          IOChannel,      /* chan.v */ 
                          IO$_READVBLK,   /* func.v */ 
                          &iosb,          /* iosb.r | 0 */ 
                          0, 0,           /* astadr, astprm: UNUSED */ 
                          IOBuff,         /* p1.r IO buffer  */ 
                          MaxBuff,        /* p2.v IO buffer  size */ 
                          0,              /* p3 UNUSED */ 
                          0,              /* p4.v IO options flag */ 
                          0, 0            /* p5, p6 UNUSED */   ); 
    if((( sysSrvSts & 1  ) != 1 ) || /* Validate system service status. */ 
       ((  iosb.cond_value & 1  ) != 1))  /* Validate the IO status. */ 
        { 
        cleanup( IOChannel ); 
        errorExit( sysSrvSts, iosb.cond_value ); 
        } 
    else 
        if( iosb.count == 0 ) 
            printf( "    FAILED receiving data, no connection.\n" ); 
        else 
            printf( "    SUCCEEDED in to receiving: '%s'\n", IOBuff ); 
                     

You can also specify a list of read buffers by omitting the p1 and p2 arguments and passing the list of buffers as the p6 parameter. See Section 3.7 for more information.

2.9.2 Reading Data with a C Socket Interface

Example 2-16 shows an example of a TCP/IP server using the recv() routine to read data.

Example 2-16 Reading Data Using C Socket Programming

/* 
* 
*  INCLUDE FILES 
* 
*/ 
 
#if defined (_VMS || defined (VMS) 
#include  <errno.h> 
#include  <types.h> 
#include  <stdio.h> 
#include  <socket.h> 
#include  <in.h> 
#include  <netdb.h>  /* change hostent to comply with BSD 4.3 */ 
#include  <inet.h> 
#include  <tcpip$inetdef.h> /* INET symbol definitions */ 
 
   .
   .
   .
main(argc,argv) 
int argc; 
char **argv; 
{ 
 
        int     sock_2, sock_3;                 /* sockets */ 
        static  char    message[BUFSIZ]; 
static  struct  sockaddr_in sock2_name;         /* Address struct for socket2.*/ 
static  struct  sockaddr_in retsock2_name;      /* Address struct for socket2.*/ 
        struct  hostent         hostentstruct;  /* Storage for hostent data.  */ 
        struct  hostent         *hostentptr;    /* Pointer to hostent data.   */ 
        static  char            hostname[256];  /* Name of local host.        */ 
 int flag; 
 int retval;    /* helpful for debugging */ 
 int namelength;   
 
   .
   .
   .
 /* 
  * Receive message from client socket. 
  */ 
 
 retval = recv(sock_2,(1) message,(2) sizeof(message),(3) flag);(4)
 if (retval == -1) 
  { 
  perror ("receive"); 
  cleanup( 1, sock_3); 
  } 
 else 
  printf (" %s\n", message); 

  1. sock_2 is the socket descriptor previously defined by a call to the connect() routine.
  2. message points to the receive buffer where the data is placed.
  3. sizeof (message) is the size of the receive buffer.
  4. flag, when set to 0, indicates that out-of-band data is not being received.

2.10 Receiving IP Multicast Datagrams

Before a host can receive (read) IP multicast datagrams destined for a particular multicast group other than the all hosts group, the application must direct the host it is running on to become a member of that multicast group.

To join a group or drop membership from a group, specify the following options. Make sure you include the <netinet/in.h> header file.

To receive multicast datagrams sent to a specific UDP port, the receiving socket must have bound to that port using the $QIO(IO$_SETMODE) system service routine or the bind() C Socket routine. More than one process can receive UDP datagrams destined for the same port if the routine is preceded by a setsockopt() system call that specifies the SO_REUSEPORT option.

For example:


int setreuse = 1; 
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &setreuse, 
         sizeof(setreuse)) == -1) 
 perror("setsockopt"); 

When the SO_REUSEPORT option is set, every incoming multicast or broadcast UDP datagram destined for the shared port is delivered to all sockets bound to that port.

Delivery of IP multicast datagrams to SOCK_RAW sockets is determined by the protocol type of the destination.

2.11 Reading Out-of-Band Data (TCP)

Only stream-type (TCP/IP) sockets can receive out-of-band (OOB) data. Upon receiving a TCP/IP OOB character, TCP/IP Services stores a pointer in the received stream to the character that precedes the OOB character.

A read operation with a user buffer size larger than the size of the received stream up to the OOB character completes by returning to the user the received stream up to, but not including, the OOB character.

Poll the socket to determine if additional read operations are needed before getting all the characters from the stream preceding the OOB character.

2.11.1 Reading OOB Data with OpenVMS System Services

To receive OOB data from a remote process, issue the IO$_READVBLK function with the IO$M_INTERRUPT modifier.

To poll the socket, issue a $QIO command with the IO$_SENSEMODE function and the TCPIP$C_IOCTL subfunction that specifies the SIOCATMARK 'ioctl' parameter.

If the SIOCATMARK returns a value of 0, issue additional read QIOs to read more data before reading the OOB character. If the SIOCATMARK returns a value of 1, the next read QIO returns the OOB character.

These functions are useful if a socket has the socket option OOBINLINE set. The OOB character is read with the characters in the stream (IO$_READVBLK), but not before the preceding characters. To determine whether or not the first character in the user buffer on the next read is an OOB, poll the socket.

To get a received OOB character for a socket with the socket option OOBINLINE clear, issue one of the following functions:

Example 2-17 shows how to use the IO$M_INTERRUPT modifier to read out-of-band data.

Example 2-17 Reading OOB Data Using OpenVMS System Services

/* 
**  Attempt to receive the OOB data from the client. 
**  Use the function code of IO$_READVBLK, passing the address of the 
**  input buffer to P1, and the OOB code, TCPIP$C_MSG_OOB, to P4. 
**  We support the sending and receiving of a one byte of OOB data. 
*/ 
        sysSrvSts = sys$qiow( 0,               /* efn.v | 0 */ 
                              IOChanClient,    /* chan.v */ 
                              IO$_READVBLK,    /* func.v */ 
                              &iosb,           /* iosb.r | 0 */ 
                              0, 0,            /* astadr, astprm: UNUSED */ 
                              &OOBBuff,        /* p1.r IO buffer  */ 
                              MaxBuff,         /* p2.v IO buffer  size */ 
                              0,               /* p3 UNUSED */ 
                              TCPIP$C_MSG_OOB, /* p4.v IO options flag */ 
                              0, 0             /* p5, p6 UNUSED */   ); 
 
        if((( sysSrvSts & 1  ) != 1 ) || /* Validate the system service. */ 
           ((  iosb.cond_value & 1  ) != 1))  /* Validate the IO status. */ 
            { 
            cleanup( IOChanClient ); 
            cleanup( IOChannel ); 
            errorExit( sysSrvSts, iosb.cond_value ); 
            } 
        else 
            if( iosb.count == 0 ) 
                printf( "    FAILED to receive the message, no connection.\n" ); 
            else 
                printf( "    SUCCEEDED in receiving '%d'\n", OOBBuff ); 

2.11.2 Reading OOB Data with the C Socket Interface

You can use the recv() socket routine with the MSG_OOB flag set to receive out-of-band data regardless of how many of the preceding characters in the stream you have received.

Example 2-18 shows an example of a TCP/IP server using the recv() routine to receive out-of-band data.

Example 2-18 Reading OOB Data Using C Socket Programming

#include <types.h> 
#include <in.h> 
#include <socket.h> 
#include <unixio.h> 
#include <string.h> 
 
#define PORTNUM 1234 
   .
   .
   .
        /* 
         * Accept connection from socket 2:             
         * accepted connection will be on socket 3 
         */ 
        namelength = sizeof (sock2_name); 
        sock_3 = accept (sock_2, &sock2_name, &namelength); 
        if (sock_3 == -1) 
                { 
                perror ("accept"); 
                cleanup( 2, sock_2, sock_3); 
                } 
 
        /* 
         * Receive message from socket 2. 
         */ 
        flag = MSG_OOB; 
        retval = recv(sock_3,(1)
        message,(2)sizeof(message),(3)flag);(4)
        if (retval == -1) 
                { 
                perror ("receive"); 
                cleanup( 2, sock_2, sock_3); 
                } 
        else 
                printf (" %s\n", message); 
 
 

  1. sock_3 specifies that OOB data is received from socket 2.
  2. message points to the read buffer where the data is placed.
  3. sizeof (message) indicates the size of the read buffer.
  4. flag, when set to MSG_OOB, indicates that OOB data is being received in the specified buffer.

2.12 Peeking at Queued Messages

You can issue a read operation to look at data in a socket receive queue without removing the data from the buffer. This is called peeking.

2.12.1 Peeking at Data with OpenVMS System Services

To peek at data next in the socket receive queue, issue the IO$_READVBLK function of the $QIO system service with the TCPIP$M_PEEK flag. This allows you to issue multiple read operations on the same data.

2.12.2 Peeking at Data with the C Socket Interface

Use the MSG_PEEK flag with the recv() routine to peek at data in the socket receive queue. Example 2-19 shows a TCP server using the recv() routine with the MSG_PEEK flag to peek at received data.

Example 2-19 Previewing Data Using C Socket Programming

/* This program accepts a connection on TCP port 1234, prompts for a 
   character to be entered, and uses the "peek" feature to determine 
   what character was chosen before actually reading it. */ 
 
#include <types.h> 
#include <in.h> 
#include <socket.h> 
#include <unixio.h> 
 
#define PORTNUM 1234 
 
main() { 
   struct sockaddr_in lcladdr; 
   int r, s; 
   char buffer[64]; 
   memset() 
   
   lcladdr.sin_family = AF_INET; 
   lcladdr.sin_addr.s_addr = INADDR_ANY; 
   lcladdr.sin_port = htons(PORTNUM); 
   
   if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket"); 
   if (bind(s, &lcladdr, sizeof(lcladdr))) perror("bind"); 
   if (listen(s, 1)) perror("listen"); 
   if ((r = accept(s, 0, 0)) < 0) perror("accept"); 
   sprintf(buffer, "Please pick a character:\r\n"); 
   if (send(r, buffer, strlen(buffer), 0) != strlen(buffer)) 
      perror("send"); 
   if (recv(r,(1) buffer,(2) 1,(3) 
MSG_PEEK)(4) != 1) perror("recv"); 
   sprintf(buffer, "Before receiving, I see you picked '%c'.\r\n", 
    buffer[0]); 
   if (send(r, buffer, strlen(buffer), 0) != strlen(buffer)) 
      perror("send"); 
   if (recv(r, buffer, 1, 0) != 1) perror("recv"); 
   sprintf(buffer, "Sure enough, I received '%c'.\r\n", buffer[0]); 
   if (send(r, buffer, strlen(buffer), 0) != strlen(buffer)) 
      perror("send"); 
   if (close(r)) perror("close"); 
   if (close(s)) perror("close"); 
} 
 

The recv() routine receives data from a connected socket and places it in a buffer, as follows:

  1. r is the socket descriptor created as a result of a call to the accept() routine.
  2. buffer points to the buffer into which received data is placed.
  3. 1 indicates the size of the buffer.
  4. MSG_PEEK is the flag that specifies the character entered is looked at without removing it from the buffer.

2.13 Writing Data

For programs that use TCP, data writing occurs after a client program initiates a connection and the server program accepts the connection. When using UDP, you also have the option of establishing a default peer address with a specific socket, but this is not required for data transfer.

2.13.1 Writing Data with OpenVMS System Services

The IO$_WRITEVBLK function of the $QIO system service copies data from the address space of the user's process to system dynamic memory and then transfers the data to an internet host or port.

Example 2-20 shows an example of a TCP client using the IO$_WRITEVBLK function to transmit a single data buffer. An IO$_ACCESS QIO was previously executed to establish the connection with the remote host.

Example 2-20 Writing Data Using OpenVMS System Services

/* 
** 
**  Attempt to send data to a previously established network connection. 
**  Use the function code IO$_WRITEVBLK, passing the address of the 
**  output buffer to P1, and the size of the message to P2. 
** 
*/ 
        sprintf( IOBuff, "The answer is %d", 42 ); 
 
        sysSrvSts = sys$qiow( 0,                   /* efn.v | 0 */ 
                              IOChanClient,        /* chan.v */ 
                              IO$_WRITEVBLK,       /* func.v */ 
                              &iosb,               /* iosb.r | 0 */ 
                              0, 0,                /* astadr, astprm: UNUSED */ 
                              IOBuff,              /* p1.r IO buffer  */ 
                              strlen( IOBuff )+ 1, /* p2.v IO buffer  size */ 
                              0,                   /* p3 UNUSED */ 
                              0,                   /* p4.v IO options flag */ 
                              0, 0                 /* p5, p6 UNUSED */   ); 
 
        if((( sysSrvSts & 1  ) != 1 ) || /* Validate system service. */ 
           ((  iosb.cond_value & 1  ) != 1))  /* Validate the IO status. */ 
            { 
            cleanup( IOChanClient /* chan.v */  ); 
            cleanup( IOChannel ); 
            errorExit( sysSrvSts, iosb.cond_value ); 
            } 
        else 
            if( iosb.count == 0 ) 
                printf( "    FAILED to send message, no connection.\n\n" ); 
            else 
                printf( "    SUCCEEDED in sending the message.\n\n" ); 
 

You can also specify a list of write buffers by omitting the p1 and p2 parameters, and instead passing the list of buffers as the p5 parameter. Note that when writing a list of buffers, the p5 parameter is used; when reading a list, the p6 parameter is used. For more information, see Section 3.6.


Previous Next Contents Index