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

Previous | Contents | Index

# 1.4 Compiling and Linking Compaq's C Language Programs

The examples in this manual were written using the Compaq C compiler. To compile and link your program, enter the following commands:

    $ CC MAIN.C/PREFIX=ALL
    $ LINK MAIN.OBJ

## 1.4.1 Compiling and Linking Programs Using BSD Version 4.4

To compile and link your Compaq C program using BSD Version 4.4, enter the following commands, where `filename` is the name of your program:

    $ CC/PREFIX=ALL/DEFINE=(_SOCKADDR_LEN) filename.C

    $ LINK/MAP filename

Instead of using the /DEFINE=(_SOCKADDR_LEN) option to the compile command, you can change your code to include the following #DEFINE preprocessor directive:

    #DEFINE   _SOCKADDR_LEN    1

This statement must appear before you include any of the following header files:

    #include <in.h>
    #include <netdb.h>
    #include <inet.h>

## 1.4.2 Compaq C Compilation Warnings

Certain parameters to the TCP/IP Services Sockets API functions require typecasting to avoid Compaq C compilation warnings. Typecasting is required because of parameter prototyping, which the Compaq C header (filename.H) files have in order to comply with ANSI standards. The Compaq Tru64 UNIX header files have different requirements because their Sockets API functions are not parameter prototyped.

# 1.5 Using 64-Bit Addresses (Alpha Only)

For applications that run on OpenVMS Alpha systems, input and output (I/O) operations can be performed directly to and from the P2 or S2 addressable space by means of the 64-bit friendly $QIO and $QIOW system services.

To write data to a remote host, use the $QIO(IO$_WRITEVBLK) function with either the p1 (input buffer) or p5 (input buffer list) parameter. The address you specify for the parameter can be a 64-bit value.

To read data from a remote host, use the $QIO(IO$_READVBLK) function with either the p1 (output buffer) or p6 (output buffer list) parameter. The address you specify for the parameter can be a 64-bit value.

MACRO-32 does not provide 64-bit macros for system services. For more information about MACRO-32 programming support and for 64-bit addressing in general, see the OpenVMS Alpha Guide to 64-Bit Addressing and VLM Features.

For more information about using the $QIO and $QIOW system services for 64-bit addressing, see Chapter 5 and Chapter 6.

# Chapter 2
Writing Network Applications

You can use either the Sockets API or OpenVMS system services to write TCP/IP applications that run on your corporate network. These applications consist of a series of system calls that perform tasks, such as creating a socket, performing host and IP address lookups, accepting and closing connections, and setting socket options. These system calls are direct entry points that client and server processes use to obtain services from the TCP/IP kernel software. System calls look and behave exactly like other procedural calls in that they take arguments and return one or more results, including a status value. These arguments can contain values or pointers to objects in the application program.

This chapter describes the communication process followed by client and server applications. This process reflects the sequence of system calls within the client and server programs (see Tables 2-1 through 2-4). The chapter also includes Sockets API and OpenVMS system services examples for each step in the communication process.

# 2.1 The Client/Server Communication Process

The most commonly used paradigm in constructing distributed applications is the client/server model. The requester, known as the client, sends a request to a server and waits for a response. The server is an application-level program that offers a service that can be reached over the network. Servers accept requests that arrive over the network, perform their service, and return the result to the client.

In addition to having a client and a server, the connection also has a mode of communication. This variable can be either connection-oriented or connectionless. When writing network applications, the developer uses the mode of communication required by the application-level service. Therefore, if the application-level service uses the connection-oriented mode of communication, the developer uses the virtual circuit or the Transmission Control Protocol (TCP) approach. If the application-level service uses the connectionless mode of communication, then the developer uses the datagram or the User Datagram Protocol (UDP) approach.

## 2.1.1 Using the TCP Protocol

Figure 2-1 shows the communication process for a TCP client/server application.

Figure 2-1 Client/Server Communication Process Using TCP

In this figure:

1. Server issues a call to create a listening socket.
2. Server and client create a socket.
3. Server and client bind socket. (This step is optional for a client.)
4. Server converts an unconnected socket into a passive socket (LISTEN state).
5. Server issues an `accept()` and process blocks waiting for a connection request.
6. Client sends a connection request.
7. Server accepts the connection; a new socket is created for communication with this client.
8. Server receives device information from the local host.
9. Data exchange takes place.
10. Client and server delete the socket.
11. Server deletes the listener socket when the service to the client is terminating.

For server applications that use the TCP protocol, Table 2-1 identifies the typical communication tasks, the applicable Sockets API function, and the equivalent OpenVMS system service.

Table 2-1 TCP Server Tasks and Related Functions
Task | Sockets API Function | OpenVMS System Service Function
--- | --- | ---
Create a socket | `socket()` | $ASSIGN $QIO(IO$_SETMODE) 1
Bind socket name | `bind()` | $QIO(IO$_SETMODE) 1
Define listener socket | `listen()` | $QIO(IO$_SETMODE) 1
Accept connection request | `accept()` | $QIO(IO$_ACCESS|IO$M_ACCEPT)
Exchange data | `read()` `recv()` `recvmsg()` | $QIO(IO$_READVBLK)
| `write()` `send()` `sendmsg()` | $QIO(IO$_WRITEVBLK)
Shut down the socket (optional) | `shutdown()` | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN)
Close and delete the socket | `close()` | $QIO(IO$_DEACCESS) $DASSGN

1The $QIO system service calls for creating a socket, binding a socket name, and defining a network pseudodevice as a listener are listed as three separate calls in this table. You can perform all three steps with one $QIO(IO$_SETMODE) call.

For a client application using the TCP protocol, Table 2-2 shows the tasks in the communication process, the applicable Sockets API functions, and the equivalent OpenVMS system service.

Table 2-2 TCP Client Calling Sequence and Related Functions
Task | Sockets API Function | OpenVMS System Service Function
--- | --- | ---
Create a socket | `socket()` | $ASSIGN $QIO(IO$_SETMODE) 1
Bind socket name | `bind()` | $QIO(IO$_SETMODE) 1
Connect to server | `connect()` | $QIO(IO$_ACCESS)
Exchange data | `read()` `recv()` `recvmsg()` | $QIO(IO$_READVBLK)
| `write()` `send()` `sendmsg()` | $QIO(IO$_WRITEVBLK)
Shut down the socket (optional) | `shutdown()` | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN)
Close and delete the socket | `close()` | $QIO(IO$_DEACCESS) $DASSGN

1The $QIO system service calls for creating a socket and binding a socket name are listed as two separate calls in this table. You can perform both steps with one $QIO(IO$_SETMODE) call.

## 2.1.2 Using the UDP Protocol

Figure 2-2 shows the steps in the communication process for a client/server application using the UDP protocol.

Figure 2-2 UDP Socket Communication Process

In this figure:

1. Server and client create a socket.
2. Server and client bind the socket name. (This step is optional for a client.)
3. Data exchange takes place.
4. Server and client delete the socket.

For server applications using the UDP protocol, Table 2-3 identifies the tasks in the communication process, the Sockets API functions, and the equivalent OpenVMS system service function.

Table 2-3 UDP Server Tasks and Related Functions
Task | Sockets API Function | OpenVMS System Service Function
--- | --- | ---
Create a socket | `socket()` | $ASSIGN $QIO(IO$_SETMODE) 1
Bind socket name | `bind()` | $QIO(IO$_SETMODE) 1
Exchange data | `read()` `recv()` `recvfrom()` `recvmsg()` | $QIO(IO$_READVBLK)
| `write()` `send()` `sendto()` `sendmsg()` | $QIO(IO$_WRITEVBLK)
Shut down the socket (optional) | `shutdown()` | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN)
Close and delete the socket | `close()` | $QIO(IO$_DEACCESS) $DASSGN

1The $QIO system service calls for creating a socket and binding a socket name are listed as two separate calls in this table. You can perform both steps with one $QIO(IO$_SETMODE) call.

For client applications using the UDP protocol, Table 2-4 describes the tasks in the communication process, the Sockets API function, and the equivalent OpenVMS system service.

Table 2-4 UDP Client Tasks and Related Functions
Task | Sockets API Function | OpenVMS System Service Function
--- | --- | ---
Create a socket | `socket()` | $ASSIGN $QIO(IO$_SETMODE) 1
Bind socket name (optional) | `bind()` | $QIO(IO$_SETMODE) 1
Specify a destination address for outgoing datagrams | `connect()` | $QIO(IO$_ACCESS)
Exchange data | `read()` `recv()` `recvfrom()` `recvmsg()` | $QIO(IO$_READVBLK)
| `write()` `send()` `sendto()` `sendmsg()` | $QIO(IO$_WRITEVBLK)
Shut down the socket (optional) | `shutdown()` | $QIO(IO$_DEACCESS|IO$M_SHUTDOWN)
Close and delete the socket | `close()` | $QIO(IO$_DEACCESS) $DASSGN

1The $QIO system service calls for creating a socket and binding a socket name are listed as two separate calls in this table. You can perform both of these steps with one $QIO(IO$_SETMODE) call.

# 2.2 Creating a Socket

For network communication to take place between two processes, each process requires an end point to establish a communication link between the two processes. This end point, called a socket, sends messages to and receives messages from the socket associated with the process at the other end of the communication link.

Sockets are created by issuing a call to the `socket()` function (Sockets API) or by the $ASSIGN and $QIO(IO$_SETMODE) routines (system service) specifying an address family, a protocol family, and a socket type.

If the socket creation is successful, the operation returns a small nonnegative integer value called a socket descriptor, or sockfd. From this point on, the application program uses the socket descriptor to reference the newly created socket.

In the TCP/IP Services implementation, this socket is also referred to as a device socket. A device socket is the pairing of an OpenVMS network device and a BSD-style socket. A device socket can be created implicitly when using the Sockets API or explicitly when using OpenVMS system services.

To displaying information about a device socket, use the TCP/IP management command SHOW DEVICE_SOCKET.

Perform the following steps to create a socket:

1. Assign a channel to the network device.
2. Create a socket.

The functions of the TCP/IP protocols are performed as I/O functions of the network device. When using the TCP/IP Services software, TCPIP$DEVICE: is the logical name for network devices.

When a channel is assigned to the TCPIP$DEVICE template network device, TCP/IP Services creates a new pseudodevice with a unique unit number and returns a channel number to use in subsequent operation requests with that device.

When the auxiliary server creates your application server process in response to incoming network traffic for a service with the `LISTEN` flag, it creates a device socket for your application server process. For your application to receive the device socket, assign a channel to SYS$NET, which is the logical name of a network pseudodevice, and perform an appropriate $QIO(IO$_SETMODE) operation. For examples of how to do this, see Appendix E. For a discussion of the auxiliary server, see the Compaq TCP/IP Services for OpenVMS Management manual.

## 2.2.1 Creating Sockets (Sockets API)

When using the Sockets API, create the socket with a call to the `socket()` function. Example 2-1 shows how to use the `socket()` function to create a TCP socket.

Example 2-1 Creating 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    */

    int main( void )
    {
        int sockfd;

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

        exit( EXIT_SUCCESS );
    }

1. This line creates the socket with the following arguments:
   - `AF_INET` is the address family that references the socket in IPv4 protocol format.
   - `SOCK_STREAM` specifies that the socket type is stream (TCP).
   - `0` specifies that the protocol type is IPPROTO_TCP (default).

## 2.2.2 Creating Sockets (System Services)

When you use OpenVMS system services, you make two calls to create the socket:

- $ASSIGN to assign a channel to the network device
- $QIO or $QIOW to create the socket
  The Queue I/O Request ($QIO) service completes asynchronously. It returns to the caller immediately after queuing the I/O request, without waiting for the I/O operation to complete.
  For synchronous completion, use the Queue I/O Request and Wait ($QIOW) service. The $QIOW service is identical to the $QIO service, except the $QIOW returns to the caller after the I/O operation completes.

When you make the $QIO or $QIOW call, use either the IO$_SETMODE or the IO$_SETCHAR I/O function. You generally create, bind, and set up sockets to listen with one $QIO call. The IO$_SETMODE and IO$_SETCHAR functions perform in an identical manner, where network software is concerned. However, you must have LOG_IO privilege to successfully use the IO$_SETMODE I/O function.

Example 2-2 shows how to use the $ASSIGN and $QIOW system services to create a TCP socket.

Example 2-2 Creating a Socket (System Services)

    #include <descrip.h>                /* define OpenVMS descriptors           */
    #include <efndef.h>                 /* define 'EFN$C_ENF' event flag        */
    #include <iodef.h>                  /* define i/o function codes            */
    #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 <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 sockchar
        {                                   /* socket characteristics           */
        unsigned short prot;                /* protocol                         */
        unsigned char type;                 /* type                             */
        unsigned char af;                   /* address format                   */
        };

    int main( void )
    {
        struct iosb iosb;                   /* i/o status block                 */
        unsigned int status;                /* system service return status     */
        unsigned short channel;             /* network device i/o channel       */
    (1)  struct sockchar sockchar;           /* socket characteristics buffer    */
        $DESCRIPTOR( inet_device,           /* string descriptor with logical   */
                     "TCPIP$DEVICE:" );     /* name of network pseudodevice     */

        /*
         * initialize socket characteristics
         */
    (2)
        sockchar.prot = TCPIP$C_TCP;
        sockchar.type = TCPIP$C_STREAM;
        sockchar.af   = TCPIP$C_AF_INET;

        /*
         * assign i/o channel to network device
         */
    (3)
        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 );
            }

        /*
         * create a socket
         */
    (4)
        status = sys$qiow( EFN$C_ENF,           /* event flag                   */
                           channel,             /* i/o channel                  */
                           IO$_SETMODE,         /* i/o function code            */
                           &iosb,               /* i/o status block             */
                           0,                   /* ast service routine          */
                           0,                   /* ast parameter                */
                           &sockchar,           /* p1 - socket characteristics  */
                           0,                   /* p2                           */
                           0,                   /* p3                           */
                           0,                   /* p4                           */
                           0,                   /* p5                           */
                           0                    /* p6                           */
                         );

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

        if ( !(status & STS$M_SUCCESS) )
            {
            printf( "Failed to create socket\n" );
            exit( status );
            }

        exit( EXIT_SUCCESS );
    }

Previous | Next | Contents | Index