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

Previous | Contents

Example 4-12 IO$_WRITEVBLK Function (MACRO-32 Programming)

            .title write
            .ident  /01/
    ;
    ; Write a vectored buffer
    ;

            $inetsymdef                     ; INET symbols

    dev:    .ascid  /ucx$device:/                   ; INET device name
    channel:        .word   0               ; INET channel
    iostatus:       .quad   0               ; I/O status block
    ;
    ; INET Socket address definition of the remote host
    ;
    Ret_adr:
            .word   INET$C_AF_INET          ; INET family
            .word   5002                    ; Port number
                                            ; Remote host IP address
            .byte   128,20,20               ; Network/subnetwork number
            .byte   156                     ; Remote Host number
            .blkb   8
    Ret_len=.-Ret_adr
    leng:   .long   0              ; Return length of Remote IP address
    ;
    ; INET Socket address definition of the local host
    ;
    Local_adr:
            .word   INET$C_AF_INET          ; INET family
            .word   5001                    ; Port number
                                            ; Local host IP address
            .byte   128,20,20               ; Network/subnetwork number
            .byte   10                      ; Local Host number
            .blkb   8
    par11:  .word   INET$C_UDP              ; UDP/IP  protocol
            .word   INET_PROTYP$C_DGRAM     ; Datagram type of socket
    ;
    ; Item_list_2 descriptor for the Remote IP address
    ;
    par12:  .long   ret_len                 ; Length
            .address ret_adr                ; Buffer address
    ;
    ; Item_list_2 descriptor for the Local IP address
    ;
    par13:  .long   ret_len                 ; Length
            .address local_adr              ; Address
    ;
    ; I/O Buffer
    ;
    buffer:
            .blkb   512
    buflen=.-buffer

            .entry   start,^m<>
            .
            .
            .
    ;
    ; Perform a QIOW write operation
    ;
    write:
            $qiow_s efn=#31,-               ; Event flag
                    chan=channel, -         ; Channel
                    func=#io$_writevblk,-   ; I/O function
                    iosb= iostatus,-        ; I/O status
                    p1=buffer,-             ; I/O Buffer address
                    p2=#buflen,-            ; I/O Buffer length
                    p3=#par12               ; Address of Descriptor
                                            ; of buffer of the remote
                                            ; Host IP address
            blbc    r0,exit                 ; Branch if error
            movzwl  iostatus,r0             ;
            blbc    r0,exit                 ;
            $dassgn_s       chan=Channel    ; Deassign the socket device
    exit:
            ret                             ; Exit
            .end start

Example 4-13 IO$_WRITEVBLK Function --- Vectored (C Programming)

    #module write_vecio
    /*
    **++
    **
    ** This example does vectored buffers write
    **
    **--
    */

    /*
    **  INCLUDE FILES
    */

    #include <descrip.h>
    #include <ucx$inetdef.h>     /* INET symbol definitions */
    #include <iodef.h>

    /*
    **
    */

    struct bvec              /* Structure definition for vec buf */
            {
              int lenth ;
              char *b_adrs ;
            } ;

    struct sockaddr {            /* Structure definition for socket adrs */
            short inet_family ;
            short inet_port ;
            char adrs[4] ;
            char blkb[8] ;
           } ;

    struct itlst {
            int lgth ;
            struct sockaddr *hst ;
             } ;

    main()

    {
         int status ;            /* For return status */
         short channel ;         /* INET channel */
         short sck_parm[2] ;     /* Socket creation parameter */
         int iosb [2] ;          /* I/O status block           */
         char buf_1[12],buf_2[12],buf_3[12],buf_4[12] ;
         struct sockaddr remote_host ; /* Socket adrs definition for rhst */
         struct sockaddr local_host ; /* Socket adrs definition for lhst */
         struct itlst lhst_adrs ;
         struct itlst rhst_adrs ;

         struct bvec buf_vec[5] =
              {
                 {12, &buf_1 },
                 {12, &buf_2 },
                 {12, &buf_3 },
                 {12, &buf_4 },
                 {0, 0 }
              } ;

    /* Descriptor for Inet device name */

            struct dsc$descriptor dev =
                { 3, DSC$K_CLASS_S, DSC$K_DTYPE_T, "UCX$DEVICE:"} ;

    /* Descriptor for vectored buffer */

            struct dsc$descriptor buf_d =
                { 0, DSC$K_CLASS_S, DSC$K_DTYPE_T, 0} ;

    /* Initialize the parameters */

            sck_parm[0] = INET$C_UDP ;     /* UDP/IP protocol */
            sck_parm[1] = INET_PROTYP$C_DGRAM ; /* Datagram type of socket */

    /* Itlst for local IP address */

            lhst_adrs.lgth = sizeof(local_host);
            lhst_adrs.hst = &local_host ;

            rhst_adrs.lgth = sizeof(remote_host) ;
            rhst_adrs.hst = &remote_host ;

            buf_d.dsc$a_pointer = buf_vec;
            buf_d.dsc$w_length = sizeof (bvec) ;

    /* Initialize socket address for remote host */

           remote_host.inet_family = INET$C_AF_INET;/* INET family */
           remote_host.inet_port = 0 ;          /* Port number */
           remote_host.adrs[0] = 128 ;          /* Network/subnetwork*/
           remote_host.adrs[1] = 45 ;           /*  number */
           remote_host.adrs[2] = 45 ;
           remote_host.adrs[3] = 175 ;          /* Host number */
           remote_host.blkb[0] = 0 ;
           remote_host.blkb[1] = 0 ;
           remote_host.blkb[2] = 0 ;
           remote_host.blkb[3] = 0 ;
           remote_host.blkb[4] = 0 ;
           remote_host.blkb[5] = 0 ;
           remote_host.blkb[6] = 0 ;
           remote_host.blkb[7] = 0 ;

    /* Initialize socket address for local host */

           local_host.inet_family = INET$C_AF_INET ;/* INET family */
           local_host.inet_port = 0 ;          /* Port number */
           local_host.adrs[0] = 128 ;          /* Network/subnetwork*/
           local_host.adrs[1] = 45 ;           /*  number */
           local_host.adrs[2] = 45 ;
           local_host.adrs[3] = 186 ;          /* Host number */
           local_host.blkb[0] = 0 ;
           local_host.blkb[1] = 0 ;
           local_host.blkb[2] = 0 ;
           local_host.blkb[3] = 0 ;
           local_host.blkb[4] = 0 ;
           local_host.blkb[5] = 0 ;
           local_host.blkb[6] = 0 ;
           local_host.blkb[7] = 0 ;
    /*
    ** Assign a channel to INET device
    */

            status = SYS$ASSIGN( &dev,
                                 &channel,
                                 0,
                                 0) ;
          if ((status & 1) == 0) {
              printf("Failed to assign channel to INET device \n") ;
              return(status) ;
               }

    /*
    ** Create and bind the device socket to local host
    */

            status = SYS$QIOW( 31,          /* Event flag */
                               channel,    /* Channel number */
                               IO$_SETMODE, /* I/O function */
                               iosb,        /* I/O status block */
                               0,
                               0,
                               &sck_parm, /* P1 Socket creation parameter */
                               0,
                               &lhst_adrs, /* P3 Socket bind parameter */
                               0,0,0) ;
            if ((status & 1) == 0) {
                printf("Failed to create and bind the device socket \n") ;
                return(status) ;
           }
    /*
    ** Perform the QIO write operation
    */
            status = SYS$QIOW( 31,          /* Event flag */
                               channel,    /* Channel number */
                               IO$_WRITEVBLK,/* I/O function */
                      iosb,                 /* I/O status block */
                      0,
                      0,
                      0,
                      0,
                      &rhst_adrs,          /* P3 Remote host adrs desc */
                      0,
                      &buf_d,              /* P5 Vectored buffer desc */
                      0) ;
            if ((status & 1) == 0) {
                printf("Failed to write to socket \n") ;
                return(status) ;
            }
    /*
    ** Deassign the INET dev channel
    */
            SYS$DASSGN (channel);

            return(status) ;
    }

Example 4-14 IO$_WRITEVBLK Function (C Programming)

    #module write_io
    /*
    **++
    **
    ** This example does writes to INET device
    **
    **--
    */

    /*
    **  INCLUDE FILES
    */

    #include <descrip.h>
    #include <ucx$inetdef.h>   /* INET symbol definitions */
    #include <iodef.h>

    struct sockaddr {          /* Structure definition for socket adrs */
            short inet_family ;
            short inet_port ;
            char adrs[4] ;
            char blkb[8] ;
           } ;

    struct itlst {
         int lgth ;
         struct sockaddr *hst ;
          } ;
    main()

    {
         int status ;            /* For return status */
         short channel           /* INET channel */
         short sck_parm[2] ;     /* Socket creation parameter */
         int iosb [2] ;          /* I/O status block           */
         struct sockaddr local_host ; /* Socket adrs definition for lhst */
         struct itlst lhst_adrs ;
         char buf[128] ;
         int buflen = 128 ;

    /* Descriptor for Inet device name */

            struct dsc$descriptor dev =
                { 3, DSC$K_CLASS_S, DSC$K_DTYPE_T, "UCX$DEVICE:"} ;

    /* Initialize the parameters */

            sck_parm[0] = INET$C_UDP ;     /* UDP/IP protocol */
            sck_parm[1] = INET_PROTYP$C_DGRAM ; /* Datagram type of socket */

    /* Itlst for local IP address */

            lhst_adrs.lgth = sizeof(local_host);
            lhst_adrs.hst = &local_host ;
    /*
    ** Assign a channel to INET device
    */

            status = SYS$ASSIGN( &dev,
                                 &channel,
                                 0,
                                 0) ;
          if ((status & 1) == 0) {
             printf("Failed to assign channel to INET device \n") ;
             return(status) ;
              }
    /* Initialize socket address for local host */

           local_host.inet_family = INET$C_AF_INET ;/* INET family */
           local_host.inet_port = 0 ;               /* Port number */
           local_host.adrs[0] = 128 ;               /* Network/subnetwork*/
           local_host.adrs[1] = 45 ;                /*  number */
           local_host.adrs[2] = 45 ;
           local_host.adrs[3] = 216 ;               /* Host number */
           local_host.blkb[0] = 0 ;
           local_host.blkb[1] = 0 ;
           local_host.blkb[2] = 0 ;
           local_host.blkb[3] = 0 ;
           local_host.blkb[4] = 0 ;
           local_host.blkb[5] = 0 ;
           local_host.blkb[6] = 0 ;
           local_host.blkb[7] = 0 ;
    /*
    ** Create and bind the device socket to local host
    */

         status = SYS$QIOW( 31,          /* Event flag */
                            channel,    /* Channel number */
                            IO$_SETMODE, /* I/O function */
                            iosb,        /* I/O status block */
                            0,
                            0,
                            &sck_parm,   /* P1 Socket creation parameter */
                            0,
                            &lhst_adrs,  /* P3 Socket bind parameter */
                            0,0,0) ;
            if ((status & 1) == 0) {
                printf("Failed to create and bind the device socket \n") ;
                return(status) ;
              }
    /*
    ** Perform the QIO write operation
    */

         status = SYS$QIOW( 0,          /* Event flag */
                            channel,    /* Channel number */
                            IO$_WRITEVBLK,/* I/O function */
                            iosb,       /* I/O status block */
                            0,
                            0,
                            buf,          /* P1 buffer */
                            buflen,0,0,0,0);/* P2 buffer length */
            if ((status & 1) == 0) {
                printf("Failed to write to INET device \n") ;
                return(status) ;
         }
    /*
    ** Deassign the INET dev channel
    */
            SYS$DASSGN (channel);

            return(status) ;

    }

# Chapter 5
Using DEC C Socket Routines

This chapter contains information to help you increase the portability of the internet application programs that you write for the DIGITAL TCP/IP Services for OpenVMS software.

For more information on writing socket programs, see the OpenVMS Run-Time Library (RTL) for DEC C Reference manual.

# 5.1 Internet Protocols

The IP (Internet Protocol) family is a collection of protocols on the Transport layer that use the internet address format. This section describes TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) sockets.

## 5.1.1 TCP Sockets

TCP provides reliable, flow-controlled, two-way transmission of data. TCP is a byte-stream protocol used to support the SOCK_STREAM abstraction. TCP uses the standard IP address format and provides a per-host collection of port addresses. Thus, each address consists of an internet address specifying the host and network, with a specific TCP port on the host identifying the peer entity.

Sockets using TCP are either active or passive. The following table lists the differences between these socket types.

Table 5-1 TCP Socket Type Descriptions
Socket Type | Description
--- | ---
Active sockets | Initiate connections to passive sockets. By default, TCP sockets are created active.
| Only active sockets can use the connect() call to initiate connections.
Passive sockets | To create a passive socket, use the listen() system call after binding the socket with the bind() system call.
| Only passive sockets can use the accept() call to accept incoming connections.
| Passive sockets may underspecify their location to match incoming connection requests from multiple networks. This technique, called wildcard addressing, allows a single server to provide service to clients on multiple networks.

### 5.1.1.1 Wildcard Addressing

Create a socket that listens to all hosts on any network, as follows:

1. Bind the internet address INADDR_ANY.
2. Specify the TCP port.
   If you do not specify the port, the system assigns a unique port, starting at port number 1024. Once connected, the socket's address is fixed by the peer entity's location. The address assigned to the socket is the address associated with the network interface through which packets from the peer are being transmitted and received. This address corresponds to the peer entity's network.

TCP supports one socket option set with the setsockopt() and tested with getsockopt. Under most circumstances, TCP sends data when it is presented. When outstanding data has not been acknowledged, TCP gathers small amounts of output and sends it in a single packet when an acknowledgment is received.

For a small number of clients, such as window systems that send a stream of mouse events that receive no replies, this packetization can cause significant delays. Therefore, TCP provides a Boolean option, TCP_NODELAY (from <netinet/tcp.h>), to defeat this algorithm. The option level for the setsockopt() call is the protocol number for TCP, available from getprotobyname().

## 5.1.2 UDP Sockets

UDP is a protocol that supports the SOCK_DGRAM abstraction for the internet protocol family. UDP sockets are connectionless and are normally used with the sendto() and recvfrom() calls. You can also use the connect() call to fix the destination for future packets (in which case, you can use the recv() or read() or write() system calls).

UDP address formats are identical to those used by TCP. In particular, UDP provides a port identifier in addition to the normal internet address format. Note that the UDP port space is separate from the TCP port space (for example, a UDP port cannot be connected to a TCP port). Also, you can send broadcast packets (assuming the underlying network supports this) by using a reserved broadcast address. This address is network-interface dependent. The SO_BROADCAST option must be set on the socket and the process must have a privileged UIC, or SYSPRV, BYPASS, or OPER privileges for broadcasting to succeed.

# 5.2 Calling a C Socket Routine from an AST State

Calls to various C Socket routines return information within a static area. The OpenVMS environment allows an asynchronous system trap (AST) routine to interrupt a C Socket routine during its execution. In addition, the ASTs of more privileged modes can interrupt ASTs of less privileged modes. Therefore, observe caution when calling a C Socket routine from an AST state while a similar C Socket routine is being called from a non-AST state or a less privileged access mode.

The C Socket routines that use a static area are:

- gethostbyaddr()
- gethostbyname()
- getnetbyaddr()
- getnetbyname()
- getservbyname()
- getservbyport()
- getprotobyname()
- getprotobynumber()

# 5.3 Calling From KERNEL or EXEC Modes

Several C Socket routines access files in order to retrieve their information. You should not call these routines from either the KERNEL or EXEC modes when the ASTs are disabled. These C Socket routines are:

- gethostbyaddr()
- gethostbyname()
- getnetbyaddr()
- getnetbyname()
- getservbyname()
- getservbyport()
- getprotobyname()
- getprotobynumber()

# 5.4 Standard I/O

You cannot use standard I/O with sockets. The fdopen function does not support sockets.

# 5.5 Event Flags

C Socket routines can use event flags during their operation. To assign event flags, use the library routine LIB$GET_EF. The flags are released when the routine no longer needs them.

# 5.6 Suppressing DEC C Compilation Warnings

Certain parameters to the DIGITAL TCP/IP Services for OpenVMS C Socket routines require typecasting to suppress DEC C compilation warnings. Typecasting is required because of parameter prototyping, which the DEC C header (.h) files have in order to comply with ANSI standards. The DIGITAL UNIX header files have different requirements because their C Socket routines are not parameter prototyped.

# 5.7 Header Files

You can include header files on a OpenVMS system without using angle brackets:

#include types

This form of the #include preprocessor directive is possible on OpenVMS systems because all header files are located in a text library in SYS$LIBRARY. On DIGITAL UNIX systems, you must specify header files with angle brackets (< >) or double quotes (" ") and subdirectories that locate a header file.

For example, to include the header file types.h, you would use the following form of the #include directive:

    #include <sys/types.h>

# 5.8 DEC C Structures

This section describes the structures you can use when writing internet applications for OpenVMS software.

## 5.8.1 hostent Structure

The hostent structure, defined in the <netdb.h> header file, specifies or obtains a host name, a list of aliases associated with the network, and the network's number as specified in an internet address from the hosts database. An entry in the hosts database is created with the following command:

    UCX> SET HOST xxxx

The DIGITAL TCP/IP for OpenVMS Services Management book contains a description of the hosts database.

The hostent structure is defined as follows:

    struct  hostent {
            char    *h_name;(1)        /* official name of host */
            char    **h_aliases;(2)    /* alias list */
            int     h_addrtype;(3)     /* host address type */
            int     h_length;(4)       /* length of address */
            char    **h_addr_list;(5)  /* list of addresses from name server */
    #define h_addr  h_addr_list[0](6)  /* address, for backward compatibility */
    };

The members of the hostent structure are:

1. h_name is a pointer to a null-terminated character string that is the official name of the host.
2. h_aliases is a null-terminated array of alternate names for the host.
3. h_addrtype is the type of address being returned. Currently, this is AF_INET.
4. h_length is the length, in bytes, of the address.
5. (5) h_addr_list is a pointer to a list of pointers to the network addresses for the host. Each host address is represented by a series of bytes in network order. They are not ASCII strings.
6. (6) h_addr is defined as the first address in the h_addr_list. This is used for backward compatibility.

## 5.8.2 in_addr Structure

The in_addr structure, defined in the <in.h> header file, specifies or obtains an internet address. The address format can be any of the supported internet address notation formats. See the DIGITAL TCP/IP for OpenVMS Services Management book for information on internet address notation.

The in_addr structure is defined as follows:

    struct in_addr {
           union {
                    struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
                    struct { u_short s_w1,s_w2; } S_un_w;
                    u_long S_addr;
    }      S_un;
    #define s_addr  S_un.S_addr     /* can be used for most tcp & ip code */
    #define s_host  S_un.S_un_b.s_b2        /* host on imp */
    #define s_net   S_un.S_un_b.s_b1        /* network */
    #define s_imp   S_un.S_un_w.s_w2        /* imp */
    #define s_impno S_un.S_un_b.s_b4        /* imp # */
    #define s_lh    S_un.S_un_b.s_b3        /* logical host */
    };

## 5.8.3 iovec Structure

On DECnet/OSI for DIGITAL UNIX systems, the iovec structure is defined in the <uio.h> header file. On OpenVMS systems, it is defined in the <socket.h> header file.

The iovec structure describes one scatter/gather buffer. Multiple scatter/gather buffer descriptors are stored as an array of iovec elements.

The iovec structure is defined as follows:

    struct iovec {
           char *iov_base;(1)
           int  iov_len;(2)
    }

The members of the iovec structure are:

1. iov_base is a pointer to a buffer.
2. iov_len contains the size of the buffer to which iov_base points.

## 5.8.4 linger Structure

The linger structure, defined in the <socket.h> header file, specifies the setting or resetting of the socket option for the time interval that the socket lingers for data. The linger structure is supported only by STREAM type sockets.

The linger structure is defined as follows:

    struct  linger {
            int     l_onoff;(1)       /* option on/off */
            int     l_linger;(2)      /* linger time */
    };

The members of the linger structure are:

1. l_onoff=1 sets the linger or l_onoff=0 resets the linger.
2. l_linger is the number of seconds to linger (the default is 120, or 2 minutes).

## 5.8.5 msghdr Structure

The msghdr structure, defined in the <socket.h> header file, specifies the buffer parameter of recvmsg and sendmsg. It allows you to specify an array of scatter/gather buffers. The recvmsg parameter scatters the data to several user receive buffers. The msghdr structure gathers data from several user transmit buffers before being transmitted.

The msghdr structure is defined as follows:

    struct msghdr {
           char     *msg_name;(1)       /* optional address */
           int      msg_namelen;(2)     /* size of address */
           struct   iov *msg_iov;(3)    /* scatter/gather array */
           int      msg_iovlen;(4)      /* # elements in msg_iov */
           char     *msg_accrights;(5)  /* access rights sent/received */
           int      msg_accrightslen;(6)
    };

The members of the msghdr structure are:

1. msg_name is the address of the destination socket if the socket is unconnected. If no address is required, you can set this field to null.
2. msg_namelen is the length of the message name field.
3. msg_iov is an array of I/O buffer pointers of the iovec structure form. See Section 5.8.3 for a description of the iovec structure.
4. msg_iovlen is the number of buffers in the msg_iov array.
5. (5) msg_accrights points to a buffer containing access rights sent with the message.
6. (6) msg_accrightslen is the length of the msg_accrights buffer.

## 5.8.6 netent Structure

The netent structure, defined in the <netdb.h> header file, specifies or obtains a network name, a list of aliases associated with the network, and the network's number specified as an internet address from the network database. An entry in the network database is created with the following command:

    UCX> SET NETWORK xxxx

The DIGITAL TCP/IP for OpenVMS Services Management book contains a description of the network database.

The netent structure is defined as follows:

    struct  netent {
            char    *n_name;(1)       /* official name of net */
            char    **n_aliases;(2)   /* alias list */
            int     n_addrtype;(3)    /* net address type */
            long    n_net;(4)         /* net number */
    };

The members of the netent structure are:

1. n_name is the official network name.
2. n_aliases is a null-terminated list of pointers to alternate names for the network.
3. n_addrtype is the type of the network number returned. Currently this type is always AF_INET.
4. n_net is the network number, returned in host byte order.

## 5.8.7 sockaddr Structure

The sockaddr structure, defined in the <socket.h> header file, specifies a general address family.

The sockaddr structure is defined as follows:

       struct sockaddr {
               u_short sa_family;(1)  /* address family */
               char sa_data[14];(2)   /* up to 14 bytes of direct address */
    };

Previous | Next | Contents