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


Previous Contents Index

2.4 Binding a Socket

To bind a socket, specify a local interface address and local port number for the device socket.

If the application needs to receive incoming multicast or broadcast datagrams destined for a specific UDP port, see Section 2.10 for information about specifying the SO_REUSEPORT option when you bind the socket.

2.4.1 Binding Sockets with OpenVMS System Services

Use the IO$_SETMODE or IO$_SETCHAR function of the $QIO system service to bind a socket.

Note

The process must have a system user identification code (UIC), SYSPRV, BYPASS, or OPER privileges to bind port numbers 1 to 1023.

Example 2-5 shows a TCP/IP server using the IO$_SETMODE function to bind sockets.

Example 2-5 Binding Socket Using OpenVMS System Services

 
/* 
** 
** Bind the socket to a local address. 
** 
*/ 
    addrLength = sizeof( localAddr ); 
    memset( &localAddr, 0, sizeof( localAddr )); 
    localAddr.sin_family = AF_INET; 
    localAddr.sin_addr.s_addr = INADDR_ANY; 
    localAddr.sin_port = htons( SERVER_PORT ); 
 
/* 
** 
** Declare and populate a string descriptor, (struct dsc$descriptor_s), 
** as defined in <descrip.h>. 
** 
*/ 
    localAddrDSC.dsc$a_pointer = (char*)&localAddr; 
    localAddrDSC.dsc$w_length  = (long)addrLength; 
 
/* 
** 
**  Attempt to Bind the device socket to the local host address. 
**  Use the function code of IO$_SETMODE, passing the local 
**  address information as a descriptor to P3. 
** 
**  NOTE: The functionality of this call, to bind the socket, and the 
**  functionality of the sys$qiow call, to create the socket, could be 
**  combined into one call. 
** 
*/ 
    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,          /* p1, p2  UNUSED */ 
                          &localAddrDSC, /* p3.d Socket bind parameter */ 
                          0, 0, 0        /* p4, 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 ); 
        } 
 

2.4.2 Binding Sockets with the C Socket Interface

Example 2-6 shows an example of a TCP/IP server using the bind() routine to bind a socket name.

Example 2-6 Binding a Socket Using C Socket Programming

#include <types.h> 
#include <in.h> 
#include <socket.h> 
#include <unixio.h> 
#include <string.h> 
 
#define PORTNUM 1234 
   .
   .
   .
 
main() { 
 int r, s, i; 
 struct sockaddr_in lcladdr; 
 char *message = "Hello, world!\r\n"; 
 
 lcladdr.sin_family = AF_INET; 
 lcladdr.sin_addr.s_addr = INADDR_ANY; 
 lcladdr.sin_port = htons(PORTNUM); 
   .
   .
   .
 i = bind( s, 
  (struct sockaddr *)&lcladdr,(1)
          sizeof(lcladdr));(2)
   .
   .
   .

In this example, the bind() routine specifies the socket descriptor previously created with a call to the socket() routine, as follows:

  1. lcladdr specifies the address of the sockaddr structure that assigns a name to the socket.
  2. sizeof(lcladdr) specifies the size of the sockaddr structure.

2.5 Making a Socket a Listener (TCP Server)

Only server programs that use TCP need to set a socket to be a listener. This allows the program to receive incoming connection requests. (TCP, as a stream protocol, requires a connection. UDP, a datagram protocl, does not.) To set a socket to listen for connection requests, specify the number of incoming requests that can wait to be queued for processing.

2.5.1 Listening to a Socket with OpenVMS System Services

Example 2-7 shows how to use the IO$_SETMODE function to set the socket to listen for requests.

Example 2-7 Setting the Socket to Listen Using OpenVMS System Services

 
#define SERVER_QLENGTH 3 
 
/* 
** 
**  Attempt to inform the network driver that it should enqueue multiple 
**  simultaneous incoming connection requests. 
**  Use the function code IO$_SETMODE, passing the desired queue 
**  length by value to P4.  Should the queue of connection requests waiting to 
**  be accepted be at the specified limit, new connection requests are 
**  automatically rejected by the network driver. 
** 
*/ 
    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,        /* p1, p2, p3 UNUSED */ 
                          SERVER_QLENGTH, /* p4.v Queue length */ 
                          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 ); 
        } 

Note

Although you can issue separate $QIO calls for socket create, bind, and listen operations, you can also perform these operations with one $QIO call. Note that socket name means the same as socket address, and it represents the association of host address and port information.

2.5.2 Listening to a Socket with a C Socket Interface

Example 2-8 shows a TCP/IP server using the bind() routine to set the socket to listen for requests.

Example 2-8 Setting the Socket to Listen Using C Socket Programming

#include <types.h> 
#include <in.h> 
#include <socket.h> 
#include <unixio.h> 
#include <string.h> 
 
#define PORTNUM 1234 
 
main() { 
 int r, s, i; 
 struct sockaddr_in lcladdr; 
 char *message = "Hello, world!\r\n"; 
        memset( &lcladdr, 0, sizeof(lcladdr)); 
 lcladdr.sin_family = AF_INET; 
 lcladdr.sin_addr.s_addr = INADDR_ANY; 
 lcladdr.sin_port = htons(PORTNUM); 
   .
   .
   .
 i = listen(s,(1) 1);(2)

In this example of a listen() routine:

  1. s is the socket descriptor previously defined by a call to the socket() routine.
  2. 1 specifies that only one pending connection can be queued at any given time. The maximum number of connections allowed is 5.

2.6 Initiating a Connection with a TCP Client

You can initiate a connection through a TCP client using either a stream socket or datagram. However, you must follow the guidelines listed below:

2.6.1 Initiating a Connection with OpenVMS System Services

To initiate a connection to a remote host, issue the $QIO system service with the IO$_ACCESS function and the p3 argument. The p3 argument of the IO$_ACCESS function is the address of an item_list_2 descriptor that contains the remote socket name.

Example 2-9 shows an example of a TCP/IP client using the IO_$ACCESS function to initiate a connection.

The internet address received by the program identifies the remote host. To map the internet address to the host name, use a $QIO system service with the IO$_ACPCONTROL function (see Chapter 4).

Example 2-9 Initiating a Connection Using OpenVMS System Services

 
 
/* 
** 
**  Get the remote server host name from the user and set up the remote 
**  address structure. 
** 
*/ 
    memset( &remoteAddr, 0, sizeof( remoteAddr )); 
    remoteAddr.sin_family = AF_INET; 
    remoteAddr.sin_port = htons( SERVER_PORT_NUMBER ); 
 
    /* Continue to prompt the user for a valid server host name. */ 
    memset( IOBuff, 0, MaxBuff ); 
    printf( "\n    Enter the host name where the server is running : " ); 
    scanf( "%s", IOBuff ); 
    while( (hostentptr = gethostbyname( IOBuff )) == (struct hostent*)NULL ) 
        { 
        printf( "    Host %s could not be found.\n", IOBuff ); 
        memset( IOBuff, 0, MaxBuff ); 
        printf( "\n    Enter the host name where the server is running : " ); 
        scanf( "%s", IOBuff ); 
        } 
 
    remoteInAddr.s_addr = *(int*)(hostentptr->h_addr); 
    addrStr = (char*)inet_ntoa( remoteInAddr ); 
    printf( "\n    connecting to: %s   %s\n", hostentptr->h_name, 
            addrStr )); 
 
    remoteAddr.sin_addr = *((struct in_addr*)hostentptr->h_addr ); 
    remoteAddrDSC.dsc$a_pointer = (char*)&remoteAddr; 
    remoteAddrDSC.dsc$w_length  = sizeof( remoteAddr ); 
 
/* 
** 
**  Attempt to connect the device socket to the local host address. 
**  Use the function code IO$_ACCESS, passing the remote 
**  address information as a descriptor to P3. 
** 
**  NOTE: The functionality of this calln to connect the socket, and 
**  the functionality of the sys$qiow call, to create the socket, 
**  could be combined into one call. 
** 
*/ 
    sysSrvSts = sys$qiow( 0,              /* efn.v | 0 */ 
                          IOChannel,      /* chan.v */ 
                          IO$_ACCESS,     /* func.v */ 
                          &iosb,          /* iosb.r | 0 */ 
                          0, 0,           /* astadr, astprm: UNUSED */ 
                          0, 0,           /* p1, p2 UNUSED */ 
                          &remoteAddrDSC, /* p3.d Socket connect parameter */ 
                          0, 0, 0         /* p4, 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 ); 
        } 
        cleanup( IOChannel ); 
        errorExit( sysSrvSts, iosb.cond_value ); 
        } 
 

2.6.2 Initiating a Connection with a C Socket Interface

To initiate a connection to a remote host, issue the connect() routine. Example 2-10 shows an example of a TCP/IP client using the connect() routine to initiate a connection to a remote server.

Example 2-10 Initiating a Connection Using C Socket Programming

   .
   .
   .
        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 */ 
   .
   .
   .
        /* 
         * Fill in the name & address structure for socket 2. 
         */ 
        sock2_name.sin_family = hostentstruct.h_addrtype; 
        sock2_name.sin_port = htons(atoi(argv[2])); 
        sock2_name.sin_addr = * ((struct in_addr *) hostentstruct.h_addr); 
 
 
 
 
        /* 
         * Connect socket 1 to sock2_name. 
         */ 
        retval = connect(sock_1, &sock2_name, sizeof (sock2_name)); 
        if (retval) 
                { 
                perror("connect"); 
                cleanup(shut, sock_1); 
                } 
 
 

2.7 Accepting a Connection with a TCP Server

Your server program must be able to accept incoming connection requests from client programs to successfully use TCP.

2.7.1 Accepting a Connection Using OpenVMS System Services

To accept a connection request, use the following procedure:

  1. Issue an $ASSIGN system service to create a channel for the new connection.
  2. Issue a $QIO system service using the IO$_ACCESS function with the IO$M_ACCEPT modifier.
    The p4 argument specifies the channel for I/O operations on the connection established in Step 1. If p3 specifies a valid output buffer, the $QIO routine returns the remote socket name.

    Note

    Specifying the IO$_ACCESS function is mandatory for TCP/IP. The IO$_ACCESS function uses the p4 argument only with the IO$M_ACCEPT modifier.

Example 2-11 shows a TCP server using the IO$_ACCESS function with the IO$M_ACCEPT modifier to accept incoming connection requests.

Example 2-11 Accepting an Incoming Connection Request Using OpenVMS System Services

/* 
** 
** Assign a new channel, for the new connection, to the network device, 
** "TCPIP$DEVICE:". 
** 
*/ 
        sysSrvSts = sys$assign( &devDSC,         /* devnam.d */ 
                                &IOChanClient,   /* chan.r */ 
                                0,               /* acmode.v | 0 */ 
                                0,               /* mbxnam.d | 0 */ 
                                0                /* flags.v | 0 */  ); 
        if(( sysSrvSts & 1  ) != 1 ) /* Validate the system service status. */ 
            { 
            cleanup( IOChanClient ); 
            cleanup( IOChannel ); 
            errorExit( sysSrvSts, iosb.cond_value ); 
            } 
        remoteAddrInfo.length    = (unsigned int)addrLength; 
        remoteAddrInfo.address   = (char*)&remoteAddr; 
        remoteAddrInfo.retLenPtr = (unsigned int*)&addrLength; 
/* 
** 
**  Attempt to complete the first connections on a queue of pending 
**  connections. 
**  Use the function codes of IO$_ACCESS ORed with IO$M_ACCEPT, passing the 
**  address of the remote address information to P3, and the address 
**  of the new channel to the client to P4. 
** 
**  This queue must have previously been established with a QIO using 
**  function IO$_SETMODE and a queue length passed to P4. 
** 
*/ 
        sysSrvSts = sys$qiow( 0,                /* efn.v | 0 */ 
                              IOChannel,        /* chan.v */ 
                              IO$_ACCESS | 
                                  IO$M_ACCEPT,  /* func.v */ 
                              &iosb,            /* iosb.r | 0 */ 
                              0, 0,             /* astadr, astprm: UNUSED */ 
                              0, 0,             /* p1, P2: UNUSED */ 
                              &remoteAddrInfo,  /* p3.r Remote IP address */ 
                              &IOChanClient,    /* p4.r connection Chan */ 
                              0, 0              /* p5, p6 UNUSED */   ); 
 
        if((( sysSrvSts & 1  ) != 1 ) || /* Validate system service status. */ 
           ((  iosb.cond_value & 1  ) != 1))  /* Validate the IO status. */ 
            { 
            cleanup( IOChanClient ); 
            cleanup( IOChannel ); 
            errorExit( sysSrvSts, iosb.cond_value ); 
            } 
        printf( "    SUCCEEDED in accepting a connections.\n" ); 
        printf( "    The client connection port number is %d\n", 
            htons( remoteAddr.sin_port )); 
        

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 is a value-result parameter that 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 filled.

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:

When using the $GETDVI system service, use the channel number (not TCPIP$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            | TCPIP$C_TCP               | TCPIP$C_RAW_IP | 
**    +-----------------------+---------------------------+----------------+ 
** optname: 
**    +.......................+...........................+................+ 
**    | TCPIP$C_RCVBUF        | TCPIP$C_USELOOPBACK       | TCPIP$C_IP_TTL | 
**    | TCPIP$C_SNDBUF        | TCPIP$C_TCP_NODELAY       | TCPIP$C_IP_TOS | 
**    | TCPIP$C_KEEPALIVE     | TCPIP$C_TCP_PROBE_IDLE    |                | 
**    | TCPIP$C_REUSEADDR     | TCPIP$C_TCP_DROP_IDLE     |                | 
**    |                       | TCPIP$C_FULL_DUPLEX_CLOSE |                | 
**    +-----------------------+---------------------------+----------------+ 
** 
*/ 
 
    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                   = TCPIP$M_REUSEADDR; 
    setSockOpt.optBuffAddr            = (char*)&setSockOneOption; 
    setSockOptItemList.length         =  sizeof(  setSockOptType  ); 
    setSockOptItemList.optStructAddr  = (char*) &setSockOpt; 
 
    setSockOptItemList.code = TCPIP$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 ); 
        } 
 


Previous Next Contents Index