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

Previous | Contents

## 2.7.2 Accepting a Connection Using a C Socket Interface

Example 2-12 shows how to use the accept() routine.

Example 2-12 Accepting a Connection Request Using C Socket Programming

            /*
             * Accept connection from socket 2:
             * accepted connection will be on socket 3
             */
            namelength = sizeof (sock2_name);
            sock_3 = accept (sock_2,(1)
        & sock2_name,(2)
        & namelength);(3)
            if (sock_3 == -1)
                    {
                    perror ("accept");
                    cleanup( 2, sock_2, sock_3);
                    }

In this example of an accept() routine:

1. sock_2 is the socket descriptor returned by a call to the socket() routine. This socket is bound to an address with the bind() routine and set up to listen for connections with the listen() routine.
2. sock2_name is a result parameter that is filled in with the address of the connecting entity.
3. namelength initially contains the size of the structure specified by the sock2_name argument. On return of the accept() routine, the argument contains the actual length, in bytes, of the structure that the communications layer fills in.

# 2.8 Obtaining Device Socket Information

Obtaining device socket information is useful if your program has management functions or if you have a complex program that uses multiple connections you need to track.

## 2.8.1 Getting Device Socket Information with OpenVMS System Services

To obtain information about the parts of a device socket, use the following OpenVMS system services:

- $GETDVI --- to get internet pseudodevice information
- $QIO with IO$_SENSEMODE --- to get socket information

When using the $GETDVI system service, use the channel number (not UCX$DEVICE:) as an input parameter to $GETDVIW to obtain the correct unit number and characteristics of an internet pseudodevice. For information on $GETDVI and its parameters, refer to the OpenVMS Programming Concepts Manual and the OpenVMS System Services Reference Manual.

Example 2-13 shows an example of a TCP/IP client using the IO$_SENSEMODE function to get a local socket name.

Example 2-13 Obtaining Device Socket Information by Using OpenVMS System Services

    /*
    **
    ** This is a table listing some of the valid combinations of level to optname
    **
    **   level: +---------------------+-------------------------+----------------+
    **          | SOL_SOCKET          | UCX$C_TCP               | UCX$C_RAW_IP   |
    ** optname: +.....................+.........................+................+
    **          | UCX$C_RCVBUF        | UCX$C_USELOOPBACK       | UCX$C_IP_TTL   |
    **          | UCX$C_SNDBUF        | UCX$C_TCP_NODELAY       | UCX$C_IP_TOS   |
    **          | UCX$C_NO_RCV_CHKSUM | UCX$C_TCP_PROBE_IDLE    |                |
    **          | UCX$C_NO_SND_CHKSUM | UCX$C_TCP_DROP_IDLE     |                |
    **          | UCX$C_NO_CHKSUM     | UCX$C_FULL_DUPLEX_CLOSE |                |
    **          | UCX$C_KEEPALIVE     |                         |                |
    **          | UCX$C_REUSEADDR     |                         |                |
    **          +---------------------+-------------------------+----------------+
    **
    */

        setSockOptType  setSockOpt;        /* Struct used to set socket options */
        iLSockOptType   setSockOptItemList;/* Item List of setSockOpt(s) */
        int             setSockOneOption = 1;

    /*
    **
    ** Set and validate option name and level.
    **
    */
        setSockOpt.length                 = sizeof( setSockOneOption );
        setSockOpt.code                   = UCX$M_REUSEADDR;
        setSockOpt.optBuffAddr            = (char*)&setSockOneOption;
        setSockOptItemList.length         =  sizeof(  setSockOptType  );
        setSockOptItemList.optStructAddr  = (char*) &setSockOpt;

        setSockOptItemList.code = UCX$C_SOCKOPT;

    /*
    **
    ** Attempt to set options on the socket.
    **
    */
        sysSrvSts = sys$qiow( 0,                   /* efn.v | 0 */
                              IOChannel,           /* chan.v */
                              IO$_SETMODE,         /* func.v */
                              &iosb,               /* iosb.r | 0 */
                              0, 0,                /* astadr, astprm: UNUSED */
                              0, 0, 0, 0,          /* p1, p2, p3, p4 UNUSED */
                              &setSockOptItemList, /* p5.r options item list */
                              0                    /* p6 UNUSED */   );

        if((( sysSrvSts & 1  ) != 1 ) || /* Validate the system service status. */
           ((  iosb.cond_value & 1  ) != 1))  /* Validate the IO status. */
            {
            cleanup( IOChannel );
            errorExit( sysSrvSts, iosb.cond_value );
            }

## 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:

- getpeername()
- getsockname()
- getsockopt()

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";

     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");
    }

The setsockopt() routine sets the options on a socket, as follows:

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 refused.
4. one points to the buffer that contains the parameters of the SO_REUSEADDR option.
5. (5) sizeof(one) indicates the size of the buffer to which one points.

The getsockname() routine returns the options set on a socket, as follows:

1. (6) r specifies the remote socket descriptor.
2. (7) name points to the buffer in which the routine returns the socket name.
3. (8) namelen specifies the length of the buffer to which name points.

The getpeername() routine returns the name of the peer connected to the specified remote socket descriptor, as follows:

1. r is the remote socket descriptor.
2. name points to the buffer in which the routine returns the peer name.
3. namelen specifies the length of the buffer to which name points.

# 2.9 Reading Data

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

- Create a device socket
- Bind a socket name to the device socket
- Establish a connection, if using TCP
- Specify a remote host, if using UDP (optional)

## 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
    *
    */

    #ifdef 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  <ucx$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 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, UCX 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.10.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 UCX$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:

- $QIO with IO$_READVBLK|IO$M_INTERRUPT
- IO$_READVBLK with the UCX$C_MSG_OOB flag set

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, UCX$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 */
                                  UCX$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.10.2 Reading OOB Data with a 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 1.
             */
            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.11 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.11.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 UCX$M_PEEK flag. This allows you to issue multiple read operations on the same data.

## 2.11.2 Peeking at Data with a 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];

       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 before removing it from the buffer.

# 2.12 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.12.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 specify the remote host address.

Example 2-20 Writing Data Using OpenVMS System Services

    /*
    **
    **  Attempt to send data to a previously established network connection.
    **  Use the function code of 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. See Section 3.6 for more information.

## 2.12.2 Writing Data with a C Socket Interface

Example 2-21 shows a TCP/IP client using the send() routine to transmit data.

Example 2-21 Writing Data Using C Socket Programming

    #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  <ucx$inetdef.h>     /* INET symbol definitions */
    #else
       .
       .
       .

    main(argc,argv)
    int  argc;
    char **argv;
    {

            int     sock_1;                      /* socket */
    static  char   message[] = "Hi there.";
    static    struct  sockaddr_in sock2_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  shut = FALSE;            /* flag to cleanup */

            /*
             * Send message to socket 2.
             */
            flag = 0;        /* maybe 0 or MSG_OOB */
            retval = send(sock_1,(1)
    message,(2) sizeof (message),(3) flag);(4)
            if (retval < 0)
                    {
                    perror ("oob_messsend");
                    shut = TRUE;
                    }

1. sock_1 specifies the socket that is connected to socket 2, which will receive the data.
2. message points to the send buffer where the data to be sent is placed.
3. sizeof (message) indicates the size of the send buffer.
4. flag, when set to 0, indicates that OOB data is not being sent.

# 2.13 Writing OOB Data (TCP)

If your application uses TCP, you can send OOB data to a remote process. At the remote process, the message is delivered to the user through the data receive, or out-of-band data receive mechanisms.

## 2.13.1 Writing OOB Data with OpenVMS System Services

To send out-of-band data to a remote process, issue a $QIO system service using the IO$_WRITEVBLK function with the IO$M_INTERRUPT modifier. Example 2-22 shows a TCP server using the MSG_OOB flag with the send() routine.

Example 2-22 Writing OOB Data Using OpenVMS System Services

    /*
    **
    **  Attempt to send Out Of Band data to a previously established network
    **  connection. Use the function code of IO$_WRITEVBLK, passing the address
    **  of the buffer to P1, and the OOB code, UCX$C_MSG_OOB, to P4.
    **
    */
        OOBBuff = 7;
        sysSrvSts = sys$qiow( 0,              /* efn.v | 0 */
                              IOChannel,      /* chan.v */
                              IO$_WRITEVBLK,  /* func.v */
                              &iosb,          /* iosb.r | 0 */
                              0, 0,           /* astadr, astprm: UNUSED */
                              &OOBBuff,       /* p1.r IO buffer  */
                              1,              /* p2.v IO buffer  size */
                              0,              /* p3 UNUSED */
                              UCX$C_MSG_OOB,  /* p4.v IO options flag */
                              0, 0            /* p5, p6 UNUSED */   );

        if((( sysSrvSts & 1  ) != 1 ) || /* Validate the 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 to send the OOB message, no connection.\n" );
            else
                printf( "    SUCCEEDED in sending the OOB message.\n" );

## 2.13.2 Writing OOB Data with a C Socket Interface

To send OOB data to a remote process, use the MSG_OOB flag with the send(), sendmsg(), and sendto() routines.

Previous | Next | Contents