# Compaq TCP/IP Services for OpenVMS
Sockets API and System Services Programming

Previous | Contents | Index

1. `r` specifies the remote socket descriptor connected to the local socket as a result of a call to the `socket()` function.
2. `oob_message` is the buffer containing the OOB data.
3. `strlen(oob_message)` specifies the length, in bytes, of the buffer containing the out-of-band data.
4. `MSG_OOB` is the flag that indicates the data will be sent out of band.

## 2.14.2 Writing OOB Data (System Services)

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

Example 2-23 Writing OOB Data (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, TCPIP$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              */
                              TCPIP$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.15 Sending Datagrams (UDP Protocol)

An application that uses UDP can send a datagram to a remote host, send broadcast datagrams to multiple remote hosts, or send multicast datagrams to members of a group.

With broadcasting, you send datagrams in one operation to multiple remote hosts on the specified subnetwork. With multicasting, you send datagrams in one operation to all hosts that are members of a particular group. The member hosts can be located on the local network or on remote networks, as long as the routers are configured to support multicasting.

## 2.15.1 Sending Datagrams (System Services)

You can use either of the following methods to send datagrams:

- To send datagrams from the local host to one remote host, use the $QIO system service with the IO$_ACCESS function modifier. This allows you to specify the remote socket name once, and then to use the IO$_WRITEVBLK function to send each datagram without specifying the socket name again.
- To send datagrams from the local host to several remote hosts, use the $QIO system service with the IO$_WRITEVBLK function modifier, and specify the remote socket name in the p3 argument field.

## 2.15.2 Sending Broadcast Datagrams (Sockets API)

You can broadcast datagrams by calling the `sendto()` function.

## 2.15.3 Sending Broadcast Datagrams (System Services)

To broadcast datagrams, use a $QIO system service command with the IO$_WRITEVBLK function.

Before issuing broadcast messages, the application must issue the IO$_SETMODE function. This sets the broadcast option in the socket. The process must have a system UIC, and a SYSPRV, BYPASS, or OPER privilege to issue broadcast messages. However, the system manager can disable privilege checking with the management command SET PROTOCOL UDP /BROADCAST. For more information, refer to the Compaq TCP/IP Services for OpenVMS Management guide.

## 2.15.4 Sending Multicast Datagrams

To send IP multicast datagrams, specify the IP destination address in the range of 224.0.0.0 to 239.255.255.255 using the $QIO(IO$_WRITEVBLK) system service function or the `sendto()` Sockets API function. Make sure you include the IN.H header file.

The system maps the specified IP destination address to the appropriate Ethernet or FDDI multicast address before it transmits the datagram.

You can control multicast options by specifying the following arguments to the `setsockopt()` system call, as appropriate:

- IP_MULTICAST_TTL (Sockets API)
  TCPIP$C_IP_MULTICAST_TTL (OpenVMS system services)
  Time to live (TTL). Takes an integer value between 0 and 255.

  Value | Result
  --- | ---
  0 | Restricts distribution to applications running on the local host.
  1 | Forwards the multicast datagram to hosts on the local subnet.
  1---255 | With a multicast router attached to the sending host's network, forwards multicast datagrams beyond the local subnet.
  | Multicast routers forward the datagram to known networks that have hosts belonging to the specified multicast group. The TTL value is decremented by each multicast router in the path. When the TTL value reaches 0, the datagram is no longer forwarded.

  For example:

      u_char ttl;
      ttl=2;

      if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
               sizeof(ttl)) == -1)
       perror("setsockopt");

- IP_MULTICAST_IF (Sockets API)
  TCPIP$C_MULTICAST_IF (OpenVMS system services)
  Multicast interface. Specifies a network interface other than that specified by the route in the kernel routing table.
  Unless the application specifies that an alternate network interface is associated with the socket, the datagram addressed to an IP multicast destination is transmitted from the default network interface. The default interface is determined by the interface associated with the default route in the kernel routing table or by the interface associated with an explicit route, if one exists.
  For example:

      int sock;

      struct in_addr ifaddress;

      char *if_to_use = "16.141.64.251";
      .
      .
      .

        ifaddress.s_addr = inet_addr(if_to_use);

        if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &ifaddress,

                                    sizeof(ifaddress)) == -1)

           perror ("error from setsockopt IP_MULTICAST_IF");

        else

           printf ("new interface set for sending multicast datagrams\n");

- IP_MULTICAST_LOOP (Sockets API)
  TCPIP$C_MULTICAST_LOOP (OpenVMS system services)
  Disables loopback of local delivery. If a multicast datagram is sent to a group of which the sending host is a member, a copy of the datagram is looped back by the IP layer for local delivery (default). To disable loopback delivery, specify the loop value as 0.
  For example:

      u_char loop=0;
      if (setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop
               sizeof(loop)) == -1)
       perror("setsockopt");

  To enable loopback delivery, specify a `loop` value of 1. For improved performance, Compaq recommends that you disable the default unless the host must receive copies of the datagrams.

# 2.16 Using the Berkeley Internet Name Domain Service

The Berkeley Internet Name Domain (BIND) service is a host name and address lookup service for the Internet. If BIND is enabled on your system, you can make a call to the BIND resolver to obtain host names and addresses.

Typically, you make a call to the BIND resolver either before you bind a socket or before you make a connection to a socket. You can also use this service to translate either the local or remote host name to an address before making a connection.

## 2.16.1 BIND Lookups (Sockets API)

If the BIND resolver is enabled on your system and the host name is not found in the local database, you can use either of the following functions to search the BIND database:

- `gethostbyaddr()` gets a host record from the local host or BIND database when given the host address.
- `gethostbyname()` gets a host record from the local host or BIND database when given the host name.

The host record contains both name and address information.

Example 2-24 shows how to use the `gethostname()` , `gethostbyname()` , and `gethostbyaddr()` functions to find a local host name and address.

Example 2-24 BIND Lookup (Sockets API)

    #include <in.h>                     /* define internet related constants,   */
                                        /* functions, and structures            */
    #include <inet.h>                   /* define network address info          */
    #include <netdb.h>                  /* define network database library info */
    #include <stdio.h>                  /* define standard i/o functions        */
    #include <stdlib.h>                 /* define standard library functions    */

    int main( void )
    {
        char host[1024];
        struct in_addr addr;
        struct hostent *hptr;
        /*
         * get name of local host
         */
        if ( (gethostname(host, sizeof(host))) < 0 )  (1)
            {
            perror( "Failed to get host's local name" );
            exit( EXIT_FAILURE );
            }

        printf( "Local hostname: %s\n", host );

        /*
         * lookup local host record by name
         */

        if ( !(hptr = gethostbyname(host)) )   (2)
            {
            perror( "Failed to find record for local host" );
            exit( EXIT_FAILURE );
            }

        addr.s_addr = *(int *) hptr->h_addr;
        printf( "Official hostname: %s  address: %s\n",
                hptr->h_name, inet_ntoa(addr) );

        /*
         * lookup local host record by address
         */

        hptr = gethostbyaddr( &addr.s_addr, sizeof(addr.s_addr), AF_INET );  (3)
        if ( !hptr )
            {
            perror( "Failed to find record for local host" );
            exit( EXIT_FAILURE );
            }

        printf( "Back-translated hostname: %s\n", hptr->h_name );

        exit( EXIT_SUCCESS );
    }

In this example, the following functions and arguments were used to find a local host name and address:

1. `gethostname()` gets the local host name.
   `host` is the address of the buffer that receives the host name.
   `sizeof(host)` is the size of the buffer that receives the host name.
2. `gethostbyname()` looks for the host record that has the specified name.
   On successful return of the `gethostbyname()` function, `hptr` receives the address of a `hostent` structure containing the host name, alias names, host address type, length of address (4 or 16), and an array of IPv4 addresses of the host being sought.
3. `gethostbyaddr()` looks for the host record that has the specified address.
   `addr.s_addr` specifies the address of the host being sought. It points to a series of bytes in network order, not to an ASCII string.
   `sizeof(addr.s_addr)` specifies the number of bytes in the address to which the first argument points.
   `AF_INET` points to the supported address family.

## 2.16.2 BIND Lookups (System Services)

If BIND is enabled on your system, the IO$_ACPCONTROL function searches the BIND database for the host name if it does not find the name in the local host database. The p1 argument allows you to specify the `gethostbyaddr()` or `gethostbyname()` network ACP subfunctions to control how the function searches the database.

Example 2-25 shows how to use OpenVMS system services to find a host name and address.

Example 2-25 BIND Lookup (System Services)

    #include <descrip.h>                /* define OpenVMS descriptors           */
    #include <efndef.h>                 /* define 'EFN$C_ENF' event flag        */
    #include <in.h>                     /* define internet related constants,   */
                                        /* functions, and structures            */
    #include <inet.h>                   /* define network address info          */
    #include <iodef.h>                  /* define i/o function codes            */
    #include <netdb.h>                  /* define network database library info */
    #include <ssdef.h>                  /* define system service status codes   */
    #include <starlet.h>                /* define system service calls          */
    #include <stdio.h>                  /* define standard i/o functions        */
    #include <stdlib.h>                 /* define standard library functions    */
    #include <string.h>                 /* define string handling functions     */
    #include <stsdef.h>                 /* define condition value fields        */
    #include <tcpip$inetdef.h>          /* define tcp/ip network constants,     */
                                        /* structures, and functions            */

    struct iosb
        {                                   /* i/o status block                 */
        unsigned short status;              /* i/o completion status            */
        unsigned short bytcnt;              /* bytes transferred if read/write  */
        void *details;                      /* address of buffer or parameter   */
        };

    struct acpfunc
        {                                   /* acp subfunction                  */
        unsigned char code;                 /* subfunction code                 */
        unsigned char type;                 /* call code                        */
        unsigned short reserved;            /* reserved (must be zero)          */
        };

    int main( void )
    {
        char host[1024];
        char hostent[2048];
        struct in_addr addr;
        struct hostent *hptr;

        struct iosb iosb;                   /* i/o status block                 */
        unsigned int status;                /* system service return status     */
        unsigned short channel;             /* network device i/o channel       */

        struct acpfunc func_byaddr =        /* acp gethostbyaddr function code  */
            { INETACP_FUNC$C_GETHOSTBYADDR, INETACP$C_HOSTENT_OFFSET, 0 };

        struct acpfunc func_byname =        /* acp gethostbyname function code  */
            { INETACP_FUNC$C_GETHOSTBYNAME, INETACP$C_HOSTENT_OFFSET, 0 };

        struct dsc$descriptor p1_dsc =      /* acp function descriptor          */
            { 0, DSC$K_CLASS_S, DSC$K_DTYPE_T, 0 };

        struct dsc$descriptor p2_dsc =      /* acp p2 argument descriptor       */
            { 0, DSC$K_CLASS_S, DSC$K_DTYPE_T, 0 };

        struct dsc$descriptor p4_dsc =      /* acp p4 argument descriptor       */
            { 0, DSC$K_CLASS_S, DSC$K_DTYPE_T, 0 };

        $DESCRIPTOR( inet_device,           /* string descriptor with logical   */
                     "TCPIP$DEVICE:" );     /* name of network pseudodevice     */

        /*
         * get name of local host
         */

        if ( (gethostname(host, sizeof(host))) < 0 )
            {
            perror( "Failed to get host's local name" );
            exit( EXIT_FAILURE );
            }

        printf( "Local hostname: %s\n", host );
        /*
         * assign i/o channel to network device
         */

        status = sys$assign( &inet_device,      /* device name                  */
                             &channel,          /* i/o channel                  */
                             0,                 /* access mode                  */
                             0                  /* not used                     */
                           );

        if ( !(status & STS$M_SUCCESS) )
            {
            printf( "Failed to assign i/o channel\n" );
            exit( status );
            }

        /*
         * lookup local host record by name
         */

        p1_dsc.dsc$w_length  = sizeof(func_byname);
        p1_dsc.dsc$a_pointer = (char *) &func_byname;

        p2_dsc.dsc$w_length  = strlen( host );
        p2_dsc.dsc$a_pointer = host;

        p4_dsc.dsc$w_length  = sizeof(hostent);
        p4_dsc.dsc$a_pointer = hostent;

        status = sys$qiow( EFN$C_ENF,           /* event flag                   */
                           channel,             /* i/o channel                  */
                           IO$_ACPCONTROL,      /* i/o function code            */
                           &iosb,               /* i/o status block             */
                           0,                   /* ast service routine          */
                           0,                   /* ast parameter                */
                           &p1_dsc,             /* p1 - acp subfunction code    */
                           &p2_dsc,             /* p2 - hostname to lookup      */
                           &p4_dsc.dsc$w_length,/* p3 - return length address   */
                           &p4_dsc,             /* p4 - output buffer address   */
                           0,                   /* p5                           */
                           0                    /* p6                           */
                         );

        if ( status & STS$M_SUCCESS )
            status = iosb.status;

        if ( !(status & STS$M_SUCCESS) )
            {
            printf( "Failed to find record for local host\n" );
            exit( status );
            }
        hptr = (struct hostent *) hostent;
        hptr->h_name += (unsigned int) hptr;
        *(char **) &hptr->h_addr_list += (unsigned int) hptr;
        *(char **) hptr->h_addr_list  += (unsigned int) hptr;

        addr.s_addr = *(int *) hptr->h_addr;
        printf( "Official hostname: %s  address: %s\n",
                hptr->h_name, inet_ntoa(addr) );

        /*
         * lookup local host record by address
         */

        p1_dsc.dsc$w_length  = sizeof(func_byaddr);
        p1_dsc.dsc$a_pointer = (char *) &func_byaddr;

        p2_dsc.dsc$w_length  = strlen( inet_ntoa(addr) );
        p2_dsc.dsc$a_pointer = inet_ntoa( addr );

        p4_dsc.dsc$w_length  = sizeof(hostent);
        p4_dsc.dsc$a_pointer = hostent;

        status = sys$qiow( EFN$C_ENF,           /* event flag                   */
                           channel,             /* i/o channel                  */
                           IO$_ACPCONTROL,      /* i/o function code            */
                           &iosb,               /* i/o status block             */
                           0,                   /* ast service routine          */
                           0,                   /* ast parameter                */
                           &p1_dsc,             /* p1 - acp subfunction code    */
                           &p2_dsc,             /* p2 - ip address to lookup    */
                           &p4_dsc.dsc$w_length,/* p3 - return length address   */
                           &p4_dsc,             /* p4 - output buffer address   */
                           0,                   /* p5                           */
                           0                    /* p6                           */
                         );

        if ( status & STS$M_SUCCESS )
            status = iosb.status;

        if ( !(status & STS$M_SUCCESS) )
            {
            printf( "Failed to find record for local host\n" );
            exit( status );
            }

        hptr = (struct hostent *) hostent;
        hptr->h_name += (unsigned int) hptr;

        printf( "Back-translated hostname: %s\n", hptr->h_name );

        /*
         * deassign i/o channel to network device
         */

        status = sys$dassgn( channel );
        if ( !(status & STS$M_SUCCESS) )
            {
            printf( "Failed to deassign i/o channel\n" );
            exit( status );
            }

        exit( EXIT_SUCCESS );
    }

# 2.17 Closing and Deleting a Socket

Closing a socket means that the program can no longer transmit data. Depending on how you close the socket, the program can receive data until the peer program also closes the socket.

When a remote system closes a socket, notification is not immediate, and another thread can erroneously attempt to use the socket.

If you send data to a closed socket, you might not receive an appropriate error message. Set the TCPIP$FULL_DUPLEX_CLOSE socket option if you want to have your application notified of an error when it sends data on a socket that has already been closed by the peer.

When you delete a socket, all pending messages queued for transmission are sent to the receiving socket before closing the connection.

## 2.17.1 Closing and Deleting (Sockets API)

Example 2-26 shows a TCP application using the `close()` function to close and delete a socket.

Example 2-26 Closing and Deleting a Socket (Sockets API)

    #include <socket.h>                 /* define BSD socket api                */
    #include <stdio.h>                  /* define standard i/o functions        */
    #include <stdlib.h>                 /* define standard library functions    */
    #include <unixio.h>                 /* define unix i/o                      */

    int main( void )
    {
        int sockfd;

        /*
         * create a socket
         */

        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
            {
            perror( "Failed to create socket" );
            exit( EXIT_FAILURE );
            }

        /*
         * close socket
         */

        if ( close(sockfd) < 0 )  (1)
            {
            perror( "Failed to close socket" );
            exit( EXIT_FAILURE );
            }

        exit( EXIT_SUCCESS );
    }

(1) The `sockfd` argument for the `close()` function closes the socket and deletes the socket descriptor previously defined by the `socket()` function.

Previous | Next | Contents | Index