OpenVMS Source Code Demos
TCPIP$TCP_CLIENT_QIO
#pragma module tcpip$tcp_client_qio \
"V100.2"
//============================================================================================
// title : tcpip$tcp_client_qio_100.c
// author : Neil Rieck ( https://neilrieck.net )
// (c) copyright 1999,2014 by Neil Rieck
// : Waterloo, Ontario, Canada.
// created : 2014-07-31
// notes : 1. This program began as a cleanup of "TCPIP$EXAMPLES:tcpip$tcp_client_qio.c"
// in 1999 but numerous bug fixes and additional functionality make it my own.
// 2. stack programming on VMS and OpenVMS can be done by "Sockets API" (easier)
// or "VMS System Services" (harder; a lot like building an Interociter)
// 3. this program employs sys$qiow (qio wait = synchronous)
// 4. sys$qio (asynchronous) provides even more control (demo coming soon)
// OS : OpenVMS (Alpha or Itanium) or VMS on VAX
// Stack : TCP/IP Services V5.0 or higher (but should work with any stack)
// References : HP TCP/IP Services for OpenVMS
// Sockets API and System Services Programming (manual: BA548-90002)
// compile : $ cc/prefix=all tcpip$tcp_client_qio_100.c
// link : $ link tcpip$tcp_client_qio_100
// history :
// ver who when what
// --- --- ------ ----------------------------------------------------------------------------
// 100 NSR 140731 1. original effort (prior to move from Alpha to Itanium)
// NSR 140801 2. changed port to 80 then added code to retrieve a webpage.
//============================================================================================
//
// include the usual stuff
//
#include <descrip.h> // define OpenVMS descriptors
#include <efndef.h> // define 'EFN$C_ENF' event flag
#include <in.h> // define internet related constants,
#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
//
// named constants
//
#define TCPBUFSIZ 8192 // buffer size
#define USRBUFSIZ 512 // user input buffer size
#define SERV_PORTNUM 80 // server port number (80=http)
//
// structure definitions
//
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 itemlst_2 { // item-list 2 descriptor/element
unsigned short length; // length
unsigned short type; // parameter type
void *address; // address of item list
};
struct sockchar { // socket characteristics buffer
unsigned short prot; // protocol
unsigned char type; // type
unsigned char af; // address format
};
//
// forward references
//
void get_serv_addr( void * ); // get server host address
//================================================================================
// <<< client main >>>
//
// This example implements a typical TCP IPv4 client using VMS system services:
//
// 1) create a socket:
//
// sys$assign() and sys$qiow(IO$_SETMODE)
//
// 2) initiate a connection:
//
// sys$qiow(IO$_ACCESS)
//
// 3) transfer data:
//
// sys$qiow(IO$_WRITEVBLK)
// sys$qiow(IO$_READVBLK)
//
// 4) shutdown a socket:
//
// sys$qiow(IO$_DEACCESS|IO$M_SHUTDOWN)
//
// 5) close and delete a socket:
//
// sys$qiow(IO$_DEACCESS) and sys$dassgn()
//
//===============================================================================
int main( void ) {
struct iosb iosb; // i/o status block
unsigned int status; // system service return status
char buf[TCPBUFSIZ]; // client data buffer
long buflen = sizeof( buf ); // length of client data buffer
long bytes_w; //
long bytes_r; //
long bytes_r_total; //
long read_count; //
unsigned short conn_channel; // connect inet device i/o channel
struct sockchar conn_sockchar; // connect socket char buffer
struct sockaddr_in serv_addr; // server socket address structure
struct itemlst_2 serv_itemlst; // server item-list 2 descriptor
$DESCRIPTOR( inet_device, "TCPIP$DEVICE:" ); // string descriptor with logical
// name of internet pseudodevice
//
// init connection socket characteristics buffer
//
conn_sockchar.prot = TCPIP$C_TCP; // protocol: TCP
conn_sockchar.type = TCPIP$C_STREAM; //
conn_sockchar.af = TCPIP$C_AF_INET; // IPv4
//
// init server's item-list descriptor
//
memset( &serv_itemlst, 0, sizeof(serv_itemlst) ); // initialize
serv_itemlst.length = sizeof( serv_addr ); //
serv_itemlst.address = &serv_addr; //
//
// init server's socket address structure
//
printf("\n%s%d\n", "-i-this program will connect to a website on port ",SERV_PORTNUM);
memset( &serv_addr, 0, sizeof(serv_addr) ); // initizalize
serv_addr.sin_family = TCPIP$C_AF_INET; // IPv4
serv_addr.sin_port = htons( SERV_PORTNUM ); //
get_serv_addr( &serv_addr.sin_addr ); // prompt user for address (xlate dns -> ip4)
//
// assign device socket
//
printf("-i-creating socket (assign)\n"); // tell the user what's going on
status = sys$assign( &inet_device, // device name
&conn_channel, // i/o channel
0, // access mode
0 // not used
);
if ( !(status & STS$M_SUCCESS) ) {
printf( "-e-Failed to assign i/o channel to TCPIP device\n" );
exit( status );
}
//
// create connection socket
//
printf("-i-creating socket (qiow)\n"); // tell the user what's going on
status = sys$qiow( EFN$C_ENF, // event flag
conn_channel, // i/o channel
IO$_SETMODE, // i/o function code
&iosb, // i/o status block
0, // ast service routine
0, // ast parameter
&conn_sockchar, // p1 - socket char buffer
0, // p2
0, // p3
0, // p4
0, // p5
0 // p6
);
//
if ( status & STS$M_SUCCESS ) // if the qio was sucessful
status = iosb.status; // then we would rather test the operational result
//
if ( !(status & STS$M_SUCCESS) ) {
printf( "-e-Failed to create socket\n" );
exit( status );
}
//
// connect to specified host and port number
//
printf( "-i-connecting to host: %s, port: %d\n",
inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
//
status = sys$qiow( EFN$C_ENF, // event flag
conn_channel, // i/o channel
IO$_ACCESS, // i/o function code
&iosb, // i/o status block
0, // ast service routine
0, // ast parameter
0, // p1
0, // p2
&serv_itemlst, // p3 - remote socket name
0, // p4
0, // p5
0 // p6
);
if ( status & STS$M_SUCCESS ) // if the qio was sucessful
status = iosb.status; // then we would rather test the operational result
if ( !(status & STS$M_SUCCESS) ) {
printf( "-e-Failed to connect to server\n" );
exit( status );
}
//
// connection established with a server;
// now attempt to write on this connection
//
sprintf(buf,"%s","GET / HTTP/1.0\n\n"); // we want to retrieve a web page
bytes_w = strlen(buf); //
printf("-i-Sending (qiow): %s\n", buf ); // tell the user what's going on
status = sys$qiow( EFN$C_ENF, // event flag
conn_channel, // i/o channel
IO$_WRITEVBLK, // i/o function code
&iosb, // i/o status block
0, // ast service routine
0, // ast parameter
buf, // p1 - buffer address
bytes_w, // p2 - buffer length
0, // p3
0, // p4
0, // p5
0 // p6
);
if ( status & STS$M_SUCCESS ) // if the qio was sucessful
status = iosb.status; // then we would rather test the operational result
//
if ( !(status & STS$M_SUCCESS) ) {
printf( "-e-Failed to write data to server connection\n" );
exit( status );
}
//
// connection established with a server;
// now attempt to read on this connection
//
read_count = 0; //
bytes_r_total = 0; //
while (TRUE) { //
read_count++; //
printf("-i-Receive (qiow) Count %d\n",read_count); // tell the user what's going on
status = sys$qiow( EFN$C_ENF, // event flag
conn_channel, // i/o channel
IO$_READVBLK, // i/o function code
&iosb, // i/o status block
0, // ast service routine
0, // ast parameter
buf, // p1 - buffer address
TCPBUFSIZ, // p2 - buffer size
0, // p3
0, // p4
0, // p5
0 // p6
);
if ( status & STS$M_SUCCESS ) // if we queue okay
status = iosb.status; // then we would rather test the operational result
//
if ( !(status & STS$M_SUCCESS) ) {
printf( "-w-Failed to read data from server connection\n" );
// exit( status ); // exit program (rather extreme)
break; // exit while
}else{
bytes_r = iosb.bytcnt; // fetch number of bytes just read
buf[bytes_r] = '\0'; // quick hack to ensure the print buf works properly
printf("-------------------------\n"); //
printf("-i-Received:\n%s\n", buf ); // output client's data buffer
bytes_r_total =+ bytes_r; //
}
}
printf("-i-Total Received Bytes: %ld\n", bytes_r_total );
//
// shutdown connection socket
//
printf("-i-shutdown connection socket\n");
status = sys$qiow( EFN$C_ENF, // event flag
conn_channel, // i/o channel
IO$_DEACCESS|IO$M_SHUTDOWN, // i/o function code
&iosb, // i/o status block
0, // ast service routine
0, // ast parameter
0, // p1
0, // p2
0, // p3
TCPIP$C_DSC_ALL, // p4 - discard all packets
0, // p5
0 // p6
);
if ( status & STS$M_SUCCESS )
status = iosb.status;
if ( !(status & STS$M_SUCCESS) ) {
printf( "Failed to shutdown server connection\n" );
exit( status );
}
//
// close connection socket
//
printf("-i-close connection socket\n");
status = sys$qiow( EFN$C_ENF, // event flag
conn_channel, // i/o channel
IO$_DEACCESS, // i/o function code
&iosb, // i/o status block
0, // ast service routine
0, // ast parameter
0, // p1
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 close socket\n" );
exit( status );
}
//
// deassign device socket
//
printf("-i-deassign device socket\n");
status = sys$dassgn( conn_channel );
if ( !(status & STS$M_SUCCESS) ) {
printf( "Failed to deassign i/o channel to TCPIP device\n" );
exit( status );
}
exit( EXIT_SUCCESS );
}
//==================================================================================
// Get Server Host Address
//
// This function gets the server host's address from the user and then
// stores it in the server's socket address structure. Note that the
// user can specify a server host by using either an IPv4 address in
// dotted-decimal notation (e.g. 16.20.10.126) or a host domain name
// (e.g. serverhost.hp.com).
//
// Enter "ctrl/z" to terminate program execution.
//==================================================================================
void get_serv_addr( void *addrptr ) {
char buf[USRBUFSIZ];
struct in_addr val;
struct hostent *host;
while ( TRUE ) {
printf( "-?-Enter remote host: " );
if ( fgets(buf, sizeof(buf), stdin) == NULL ) {
printf( "-e-Failed to read user input\n" );
exit( EXIT_FAILURE ); // kill whole program
}
buf[strlen(buf)-1] = 0;
val.s_addr = inet_addr( buf );
if ( val.s_addr != INADDR_NONE ) {
memcpy( addrptr, &val, sizeof(struct in_addr) );
break;
}
if ( (host = gethostbyname(buf)) ) {
memcpy( addrptr, host->h_addr, sizeof(struct in_addr) );
break;
}
}
}
/* -------------------------------------------------------------------------------------
DIGITAL TCP/IP Services for OpenVMS System Services and C Socket Programming
Table 2-2 TCP Client Calling Sequence and Related Routines
Task C Socket Routine OpenVMS System Service Routine
------------------------------- ----------------------- --------------------------------
Create a device socket socket() $ASSIGN
$QIO(IO$_SETMODE)
Bind socket name bind() $QIO(IO$_SETMODE)
Connect to server connect() $QIO(IO$_ACCESS)
Exchange data read() $QIO(IO$_READVBLK)
recv() ''
recvmsg() ''
write() $QIO(IO$_WRITEVBLK)
send() ''
sendmsg() ''
Shut down the socket (optional) shutdown() $QIO(IO$_DEACCESS|IO$M_SHUTDOWN)
Close and delete the socket close() $QIO(IO$_DEACCESS)
$DASSGN
========================================================================================
DIGITAL TCP/IP Services for OpenVMS System Services and C Socket Programming
Table 2-1 TCP Server Calling Sequence and Related Routines
Task C Socket Routine OpenVMS System Service Routine
------------------------------- ----------------------- --------------------------------
Create a device socket socket() $ASSIGN
$QIO(IO$_SETMODE)
Bind socket name bind() $QIO(IO$_SETMODE)
Define listener device socket listen() $QIO(IO$_SETMODE)
Accept connection request accept() $QIO(IO$_ACCESS)
Exchange data read() $QIO(IO$_READVBLK)
recv() ''
recvmsg() ''
write() $QIO(IO$_WRITEVBLK)
send() ''
sendmsg() ''
Shut down the socket (optional) shutdown() $QIO(IO$_DEACCESS|IO$M_SHUTDOWN)
Close and delete the socket close() $QIO(IO$_DEACCESS)
$DASSGN
========================================================================================
------------------------------------------------------------------------------------- */