/* ******************************************************************************* ** FILE: TCPdriver_client.C -- example program demonstrating usage of ** network programming library using TCPDRIVER $QIO's. ** ** PRODUCT: TCPware for VMS ** ** VERSION: V5.6 ** ** Copyright (c) 2001, 2002 by ** Process Software LLC ** Framingham, Massachusetts ** ** Copyright (c) 1997-1999 by ** Process Software Corporation ** Framingham, Massachusetts ** ** This software is furnished under a license for use on a ** single computer system and may be copied only with the ** inclusion of the above copyright notice. This software, or ** any other copies thereof, may not be provided or otherwise ** made available to any other person except for use on such ** system and to one who agrees to these license terms. Title ** to and ownership of the software shall at all times remain ** in Process Software LLC's name. ** ** The information in this document is subject to change ** without notice and should not be construed as a commitment ** by Process Software LLC. Process Software LLC assumes no ** responsibility for any errors that ** may appear in this document. ** ** ** ABSTRACT: ** ** TCPdriver_server.c and TCPdriver_client.c are a pair of example programs ** illustrating the use of stream sockets via VMS's SYS$QIO system service ** calls to the TCpdriver. ** ** ** ** CLIENT SEQUENCE OF OPERATIONS: ** 1. Assign an I/O channel to TCP0: $ASSIGN; ** 2. Open connection: $QIO(IO$_SETMODE|IO$M_CTRL|IO$M_STARTUP); ** 3. Exchange data: $QIO(IO$_WRITEVBLK), $QIO(IO$_READVBLK); ** 4. Close connection: $QIO(IO$_SETMODE|IO$M_CTRL|IO$M_SHUTDOWN); ** 5. Perform additional read until peer returns SS$_VCCLOSED status ** 6. Deassign the channel: $DASSGN; ** ** ** BUILDING EXECUTABLES: ** ** 1. on VAX : ** with VAXC: ** $ CC TCPDRIVER_CLIENT.C ** $ LINK TCPDRIVER_CLIENT, TCPWARE:UCX$IPC/LIB, SYS$INPUT/OPTIONS ** SYS$SHARE:VAXCRTL/SHARE ** ** Alternatively TCpware's socket library can be used: ** $ LINK TCPDRIVER_CLIENT, SYS$INPUT/OPTIONS ** SYS$SHARE:TCPWARE_SOCKLIB_SHR/SHARE ** SYS$SHARE:VAXCRTL/SHARE ** ** with DECC: ** $ CC/DECC/PREFIX_LIBRARY_ENTRIES=ALL TCPDRIVER_CLIENT.C ** $ LINK TCPDRIVER_CLIENT ** ** 2. on ALPHA: ** $ CC/PREFIX_LIBRARY_ENTRIES=ALL TCPDRIVER_CLIENT.C ** $ LINK TCPDRIVER_CLIENT ** ******************************************************************************* ** REQUEST: If you have comments, please send them to "support@process.com" ******************************************************************************* */ #include /* Standard C i/o */ #include #include #include /* VAX/VMS System services */ #include /* for STS$M_SUCCESS */ #include /* Descriptors */ #include /* VAX/VMS i/o definitions */ #include #include #include /* ** Macros to check VMS success/failure status */ #define SUCCESS(status) (status & STS$M_SUCCESS) #define FAILURE(status) (!(status & STS$M_SUCCESS)) /* ** Service information */ #define SERVER_PORT 65000 #define SERVICE "test_echo" #define PROTO "tcp" /* ** Values for boolean variables */ #define FALSE 0 #define TRUE 1 #if defined(__DECC) || defined(__DECCXX) #pragma __member_alignment __save #pragma __nomember_alignment #endif /* ** I/O status block */ struct IOSB_struct { short unsigned status; short unsigned byte_count; long dev_data; }; /* ** Extended characteristics buffer structure, i.e. ecb structure */ struct ecb_struct { short para_id; long para_val; }; #if defined(__DECC) || defined(__DECCXX) #pragma __member_alignment __restore #endif /* ** Net header needed since TCP function may not transmit entire message. ** If using this, it needs to be in both server and client. */ struct net_msg_hdr_struct { long msg_len; long seq_num; /* useful incase of resends */ }; /* ** function prototypes */ long sys$assign( struct dsc$descriptor_s *, unsigned short *, unsigned long, struct dsc$descriptor_s *); long sys$qiow( ); /* no prototyping due to varying P1 - P6 */ long sys$dassgn( unsigned short); main() { unsigned short channel; /* TCP channel number */ unsigned short port; /* TCP port number */ int status; /* For return status */ int io_OK; /* boolean $qio status */ int count; /* count of read operation */ int got_host; int bytes_left; char buffer[1024]; char *c_P; long int servaddr; struct hostent *hostent_P; struct servent *servent_P; struct IOSB_struct iosb; struct ecb_struct ecb[2]; struct dsc$descriptor ecb_dsc; /* extended char buffer descriptor */ struct net_msg_hdr_struct *net_msg_hdr_P; char server_name[80]; /* String descriptor for the TCP0 device */ static $DESCRIPTOR( TCP0_dev, "TCP0"); /* Assign a channel to TCP0 to clone a new device */ status = sys$assign( &TCP0_dev, &channel, 0, 0); if (FAILURE( status) ) { printf("Failed to assign channel to device TCP0.\n"); exit(status); } /* ** Get server port number for named serice. ** If unknown ( == 0 or = -1), use default define. */ if ( (int)(servent_P = getservbyname( SERVICE, PROTO)) > 0) port = servent_P->s_port; else port = SERVER_PORT; printf("Will connect to server port #: %d\n", port); /* Query user for server name and get corresponding internet address. */ got_host = FALSE; while (got_host == FALSE) { printf("Enter name of remote host (e.g. localhost) : "); gets( server_name); if ((hostent_P = gethostbyname(server_name)) == NULL) { printf("Error, gethostbyname failed\n"); } else { got_host = TRUE; memcpy((char *)&servaddr, hostent_P->h_addr, hostent_P->h_length); } } /* ** Active open connection by client: ** Setup extended characteristics buffer (see documentation on ** IO$SETMODE | IO$M_CTRL). ** Issue $QIO to open connection (see documentation on ** IO$SETMODE | IO$M_CTRL | IO$M_STARTUP ). */ ecb[0].para_id = 2; /* setup peer internet address */ ecb[0].para_val = servaddr; ecb[1].para_id = 3; /* setup peer port number */ ecb[1].para_val = port; ecb_dsc.dsc$w_length = sizeof(ecb); ecb_dsc.dsc$b_dtype = 0; ecb_dsc.dsc$b_class = 0; ecb_dsc.dsc$a_pointer = (char *)&ecb; status = sys$qiow( 0, channel, (IO$_SETMODE|IO$M_CTRL|IO$M_STARTUP), &iosb, 0, 0, 0, /* P1 */ &ecb_dsc, /* P2: extended char buffer */ 0,0,0,0); if ( SUCCESS( status) ) status = iosb.status; if ( FAILURE( status) ) { printf("Connect failed\n"); exit(status); } /* ** Keep getting input string, sending it to the server and reading the ** server's reply, till EOF is input. */ net_msg_hdr_P = (struct net_msg_hdr_struct *)&buffer; for (io_OK = TRUE, net_msg_hdr_P->seq_num = 1; io_OK; net_msg_hdr_P->seq_num++) { /* ** Prepare message to send: ** Setup message (Replace with your application function.) ** Add application header w/ message length. ** Calculate total length to send. */ c_P = &buffer[0] + sizeof(* net_msg_hdr_P); printf("Input string to echo:\n"); if ( gets( c_P) == NULL) io_OK = FALSE; net_msg_hdr_P->msg_len = strlen( buffer + sizeof(* net_msg_hdr_P) ); bytes_left = net_msg_hdr_P->msg_len + sizeof(* net_msg_hdr_P); /* ** Send message: ** Keep writing till full message is sent, including header. */ for (c_P = &buffer[0]; io_OK && bytes_left > 0; bytes_left -= iosb.byte_count, c_P += iosb.byte_count) { status = sys$qiow( 0, channel, IO$_WRITEVBLK, &iosb, 0, 0, c_P, /* P1: buffer address */ bytes_left, /* P2: buffer size in bytes */ 0,0,0,0); /* P6: optional timeout */ if ( SUCCESS( status) ) status = iosb.status; if ( FAILURE( status) ) { printf("Error sending message. Status = %x\n", status ); io_OK = FALSE; } } /* break out of this loop if bad IO */ if (! io_OK) break; /* ** Receive message: ** Read to find total message length. */ status = sys$qiow( 0, channel, IO$_READVBLK, &iosb, 0, 0, net_msg_hdr_P, /* P1: buffer address */ sizeof( *net_msg_hdr_P), /* P2: max bytes to be written to buf */ 0,0,0,0); if ( SUCCESS( status) ) status = iosb.status; if ( FAILURE( status) | iosb.byte_count < sizeof( *net_msg_hdr_P) ) { printf("Error reading net_msg_hdr. IOSB byte_count = %d\n", iosb.byte_count); break; } /* ** Receive message: ** Keep reading till client closes connection. ** of the TCP connection. */ for (c_P = &buffer[0] + sizeof( *net_msg_hdr_P), bytes_left = net_msg_hdr_P->msg_len; io_OK == TRUE && bytes_left > 0; bytes_left -= iosb.byte_count, c_P += iosb.byte_count) { status = sys$qiow( 0, channel, IO$_READVBLK, &iosb, 0, 0, c_P, /* P1: buffer address */ bytes_left, /* P2: max bytes to write to buf */ 0,0,0,0); if ( SUCCESS( status) ) status = iosb.status; /* If status & IOSB OK, print message received in this read */ if ( SUCCESS( status) ) { *(c_P + iosb.byte_count) = '\0'; /* terminate for printf() */ printf("Read %02d characters:\n%s\n\n", iosb.byte_count, c_P); } else { io_OK = FALSE; if (status == SS$_VCCLOSED) printf("Server closed connection.\n"); else printf("Error reading message.\n"); break; } /* Output returned message */ if (! io_OK) { c_P = &buffer[0] + sizeof( *net_msg_hdr_P); *(c_P + net_msg_hdr_P->msg_len) = '\0'; printf( "Echoed string: %s\n"); } } } /* Close connection. Then the client simply exits. */ status = sys$qiow( 0, channel, (IO$_SETMODE|IO$M_CTRL|IO$M_SHUTDOWN), &iosb, 0,0, 0,0,0,0,0,0); if ( SUCCESS( status) ) status = iosb.status; if ( FAILURE( status) ) { if (status == SS$_VCCLOSED) printf("Server closed connection.\n"); else printf("Error closing connection.\n"); } /* Deassign the channel */ status = sys$dassgn( channel); }