.title TCPIP$TCP_CLIENT_QIO - Example TCP IPv4 Client .ident /V5.4-00/ ; ; © Copyright 1976, 2003 Hewlett-Packard Development Company, L.P. ; ; Confidential computer software. Valid license from HP and/or its ; subsidiaries required for possession, use, or copying. ; ; Consistent with FAR 12.211 and 12.212, Commercial Computer Software, ; Computer Software Documentation, and Technical Data for Commercial ; Items are licensed to the U.S. Government under vendor's standard ; commercial license. ; ; Neither HP nor any of its subsidiaries shall be liable for technical ; or editorial errors or omissions contained herein. The information ; in this document is provided "as is" without warranty of any kind ; and is subject to change without notice. The warranties for HP ; products are set forth in the express limited warranty statements ; accompanying such products. Nothing herein should be construed as ; constituting an additional warranty. ; ; ++ ; FACILITY: ; ; EXAMPLES ; ; ABSTRACT: ; ; This is an example of a TCP/IP IPv4 client using OpenVMS ; QIO system services from MACRO-32 to handle network I/O ; operations. ; ; Refer to 'Build, Configuration, and Run Instructions' for ; details on how to build, configure, and run this program. ; ; ENVIRONMENT: ; ; OpenVMS Alpha/VAX V7.1 ; TCP/IP Services V5.0 or higher ; ; AUTHOR: ; ; TCPIP Development Group, CREATION DATE: 23-May-1989 ; ; -- .sbttl Build, Configuration, and Run Instructions ; ++ ; BUILD INSTRUCTIONS: ; ; To build this example program use commands of the form, ; ; on OpenVMS ALPHA: ; ; $ librarian/create/macro TCPIP$INETDEF.MLB SYS$LIBRARY:TCPIP$INETDEF.MAR ; $ macro/migration TCPIP$TCP_CLIENT_QIO.MAR + TCPIP$INETDEF.MLB/library ; $ link TCPIP$TCP_CLIENT_QIO ; ; on OpenVMS VAX: ; ; $ librarian/create/macro TCPIP$INETDEF.MLB SYS$LIBRARY:TCPIP$INETDEF.MAR ; $ macro TCPIP$TCP_CLIENT_QIO.MAR + TCPIP$INETDEF.MLB/library ; $ link TCPIP$TCP_CLIENT_QIO ; ; ; CONFIGURATION INSTRUCTIONS: ; ; No special configuration required. ; ; ; RUN INSTRUCTIONS: ; ; To run this example program: ; ; 1) Start the client's server program as shown below: ; ; $ run tcpip$tcp_server_qio ; Waiting for a client connection on port: m ; ; 2) After the server program blocks, start this client program, ; entering the server host as shown below: ; ; $ run tcpip$tcp_client_qio ; Enter remote host: ; ; Note: You can specify a server host by using either an IPv4 ; address in dotted-decimal notation (e.g. 16.20.10.56) ; or a host domain name (e.g. serverhost.hp.com). ; ; 3) The client program then displays server connection information ; and server data as shown below: ; ; Initiated connection to host: a.b.c.d, port: n ; Data received: Hello, world! ; ; You can enter "ctrl/z" at any user prompt to terminate program ; execution. ; ; -- .sbttl Module Declarations ; ; INCLUDE FILES: ; ; 'starlet' library symbol definitions $efndef ; define 'EFN$C_ENF' event flag ; 'tcpip$inetdef' library symbol definitions $hostentdef ; define hostent structure $inetsymdef ; define ipv4 related constants $sockaddrindef ; define ipv4 socket address structure ; ; EQUATED SYMBOLS: ; inaddr_none = -1 ; invalid address return status code ; for decc$inet_addr socket routine serv_portnum = 12345 ; server port number ; ; LOCAL STORAGE: ; .psect data,noexe ; ; miscellaneous data structures ; buffer: .blkb 512 ; i/o buffer buffer_len = .-buffer ; length of i/o buffer (in bytes) fao_buffer: .blkb 128 ; fao string buffer fao_buffer_len = .-fao_buffer ; length of fao buffer (in bytes) fao_desc: .quad 0 ; fao string descriptor getline_desc: .quad 0 ; user input string descriptor ; ; network i/o related structures ; conn_channel: .word 0 ; connection inet device i/o channel conn_sockchar: ; connection socket characteristics ; buffer with following fields: .word tcpip$c_tcp ; protocol .byte tcpip$c_stream ; socket type .byte tcpip$c_af_inet ; address format inet_device: ; string descriptor of logical .ascid /TCPIP$DEVICE:/ ; name of internet pseudodevice iosb: .quad 0 ; i/o status block ; ; server related structures ; serv_addr: ; server socket address structure ; with following fields: .word tcpip$c_af_inet ; server address format (ipv4) .word 0 ; server port number ; (in network byte order) .long 0 ; server ipv4 address ; (in network byte order) .byte 0[sin$s_zero] ; not used - must be zero serv_itemlst: ; server item-list 2 descriptor ; with following fields: .word sin$s_sockaddrin ; length .word 0 ; parameter type .address serv_addr ; server ipv4 address structure serv_port: .long serv_portnum ; server port no. (in host byte order) ; ; fao, error, and user prompt string storage ; fao$t_clientdata: .ascid \Data received: !AZ\ fao$t_serverconn: .ascid \Initiated connection to host: !AZ, port: !UW\ msg$t_assignerr: .ascid \Failed to assign i/o channel to TCPIP device\ msg$t_closerr: .ascid \Failed to close socket\ msg$t_connerr: .ascid \Failed to connect to server\ msg$t_dassgnerr: .ascid \Failed to deassign i/o channel to TCPIP device\ msg$t_inputerr: .ascid \Failed to read user input\ msg$t_readerr: .ascid \Failed to read data from server connection\ msg$t_shuterr: .ascid \Failed to shutdown server connection\ msg$t_sockerr: .ascid \Failed to create socket\ prm$t_servaddr: .ascid \Enter remote host: \ .sbttl Client Main ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This is the client's main-line code. It handles all the tasks of the ; client including: socket creation, initiating server connections, ; reading server connection data, and terminating server connections. ; ; This example program implements a typical TCP IPv4 client using QIO ; system services to handle network i/o operations as shown below: ; ; 1) To create a socket: ; ; sys$assign() and sys$qiow(IO$_SETMODE) ; ; 2) To accept a connection request: ; ; sys$qiow(IO$_ACCESS) ; ; 3) To transfer data: ; ; sys$qiow(IO$_READVBLK) ; ; 4) To shutdown a socket: ; ; sys$qiow(IO$_DEACCESS|IO$M_SHUTDOWN) ; ; 5) To close and delete a socket: ; ; sys$qiow(IO$_DEACCESS) and sys$dassgn() ; ; CALLING SEQUENCE: ; ; This routine is invoked by the DCL "RUN" command. ; ; INPUT PARAMETERS: ; ; ** None ** ; ; IMPLICIT INPUTS: ; ; buffer - i/o buffer ; conn_channel - connection inet device i/o channel ; conn_sockchar - connection socket characteristics buffer ; inet_device - inet device logical name ; iosb - i/o status block ; serv_addr - server socket address structure ; serv_itemlst - server item-list 2 descriptor ; serv_port - server port number ; ; OUTPUT PARAMETERS: ; ; r0 - completion status ; ; IMPLICIT OUTPUTS: ; ; ** None ** ; ; ROUTINE VALUE: ; ; ss$_normal - program completed successfully ; ss$_connecfail - connection abnormally terminated ; ss$_noiochan - no available i/o channel ; ss$_unreachable - remote host unreachable ; ; SIDE EFFECTS: ; ; ** None ** ; ; -- .psect $code,exe .entry start,^m<> ; ; convert server port no. to network-byte order ; and store in server's socket address structure ; pushl serv_port ; pass server port calls #1,g^decc$htons ; get server port in network-byte order movab serv_addr,r1 ; get base of socket address structure movw r0,sin$w_port(r1) ; store server port ; ; get server host address from user ; pushab serv_addr ; pass server socket address structure calls #1,get_servaddr ; ask user for server host address ; ; assign device socket ; $assign_s - ; devnam = inet_device, - ; inet device logical name chan = conn_channel ; inet device i/o channel blbs r0,create ; if lbs, assigned device socket pushaq msg$t_assignerr ; error occurred - inform user of calls #1,put_errmsg ; device socket error brw exit ; before returning to caller ; ; create connection socket ; create: $qiow_s efn = #efn$c_enf, - ; event flag chan = conn_channel, - ; i/o channel func = #io$_setmode, - ; i/o function code iosb = iosb, - ; i/o status block p1 = conn_sockchar ; p1 - socket characteristics buffer blbc r0,10$ ; if lbc, error creating socket blbs iosb,connect ; if lbs, created connection socket movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_sockerr ; error occurred - inform user of calls #1,put_errmsg ; connection socket creation error brw exit ; before returning to caller ; ; connect to a specified host and port number ; connect: pushab serv_addr ; pass server's socket address structure calls #1,put_serverconn ; output server's connection information $qiow_s efn = #efn$c_enf, - ; event flag chan = conn_channel, - ; i/o channel func = #io$_access, - ; i/o function code iosb = iosb, - ; i/o status block p3 = #serv_itemlst ; p3 - remote socket name blbc r0,10$ ; if lbc, error establishing connection blbs iosb,read ; if lbs, established server connection movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_connerr ; error occurred - inform user of calls #1,put_errmsg ; server connect error brw exit ; before returning to caller ; ; connection established with a client; ; now attempt to read on this connection ; read: $qiow_s efn = #efn$c_enf, - ; event flag chan = conn_channel,- ; i/o channel func = #io$_readvblk, - ; i/o function code iosb = iosb, - ; i/o status block p1 = buffer, - ; p1 - buffer address p2 = #buffer_len ; p2 - buffer length blbc r0,10$ ; if lbc, error reading from server blbs iosb,20$ ; if lbs, read from server completed movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_readerr ; error occurred - inform user of calls #1,put_errmsg ; server connection read error brw exit ; before returning to caller 20$: pushab buffer ; pass client's data buffer calls #1,put_clientdata ; output client's data buffer ; ; shutdown connection socket ; shutdown: $qiow_s efn = #efn$c_enf, - ; event flag chan = conn_channel, - ; i/o channel func = #,- - ; i/o function code iosb = iosb, - ; i/o status block p4 = #tcpip$c_dsc_all ; discard all packets blbc r0,10$ ; if lbc, connection shutdown failed blbs iosb,close ; if lbs, connection shutdown completed movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_shuterr ; error occurred - inform user of calls #1,put_errmsg ; connection shutdown error brw exit ; before returning to caller ; ; close connection socket ; close: $qiow_s efn = #efn$c_enf, - ; event flag chan = conn_channel,- ; i/o channel func = #io$_deaccess, - ; i/o function code iosb = iosb ; i/o status block blbc r0,10$ ; if lbc, close on socket failed blbs iosb,deassign ; if lbs, connection socket closed movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_closerr ; error occurred - inform user of calls #1,put_errmsg ; connection socket close error brw exit ; before returning to caller ; ; deassign device socket ; deassign: $dassgn_s - ; deassign device socket chan = conn_channel ; blbs r0,10$ ; if lbs, device socket released pushaq msg$t_dassgnerr ; otherwise, error occurred calls #1,put_errmsg ; inform user of deassign error brw exit ; before returning to caller ; ; return with success/error status ; 10$: movzbl #ss$_normal,r0 ; set success status exit: ret ; return to caller .sbttl Get Server Host Address ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine prompts the user and reads from sys$input the server's ; host address and 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. ; ; CALLING SEQUENCE: ; ; calls #1,get_servaddr ; ; INPUT PARAMETERS: ; ; 4(ap) - address of server's socket address structure ; ; IMPLICIT INPUTS: ; ; prm$t_servaddr - user prompt to get server's address ; ; OUTPUT PARAMETERS: ; ; ** None ** ; ; IMPLICIT OUTPUTS: ; ; buffer - i/o buffer ; getline_desc - user input string descriptor ; ; ROUTINE VALUE: ; ; ** None ** ; ; SIDE EFFECTS: ; ; 1. Contents of processor registers r0 & r1 are modified ; ; 2. Program execution is terminated if unable to read user's input ; ; -- .entry get_servaddr,^m 10$: movaq getline_desc,r2 ; get base of input string descriptor movzwl #buffer_len,(r2) ; set length of input string buffer movab buffer, - ; set address of input string buffer dsc$a_pointer(r2) ; ; ; prompt and read user's address input ; pushaw (r2) ; pass 'resultant-length' argument pushaq prm$t_servaddr ; pass 'prompt-string' argument pushaq (r2) ; pass 'resultant-string' argument calls #3,g^lib$get_input ; get server address from sys$input blbs r0,20$ ; if lbs, successfully read user input pushaq msg$t_inputerr ; error occurred - inform user of calls #1,put_errmsg ; input line error before $exit_s r0 ; terminating program execution 20$: movzwl (r2),r3 ; get length of user input string addl2 dsc$a_pointer(r2),r3 ; compute end of user input string clrb (r3) ; zero terminate user input string ; ; attempt to convert address string to a ipv4 address ; pushl dsc$a_pointer(r2) ; pass server address string calls #1,g^decc$inet_addr ; convert string to ipv4 address cmpl r0,#inaddr_none ; valid ipv4 address? bnequ 30$ ; if nequ, yes ; ; if user input string isn't a valid dotted-decimal address ; then search network database for a matching domain name ; pushl dsc$a_pointer(r2) ; pass server address string calls #1,g^decc$gethostbyname ; search for matching domain name tstl r0 ; find a matching domain name? beqlu 10$ ; if eqlu, no - user must try again movl host$l_h_addr(r0),r0 ; get 'h_addr_list' member of hostent movl (r0),r0 ; get pointer table entry movl (r0),r0 ; get ipv4 address entry ; ; store address in server's socket address structure ; 30$: movl 4(ap),r3 ; get base of socket address structure movl r0,sin$l_addr(r3) ; store user selected server address ret ; return to caller .sbttl Output Client Data ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine outputs to sys$output the client data buffer. ; ; CALLING SEQUENCE: ; ; calls #1,put_clientdata ; ; INPUT PARAMETERS: ; ; 4(ap) - address of client data buffer ; ; IMPLICIT INPUTS: ; ; fao$t_clientdata - control string to format client data buffer ; ; OUTPUT PARAMETERS: ; ; ** None ** ; ; IMPLICIT OUTPUTS: ; ; fao_buffer - fao string buffer ; fao_desc - fao string descriptor ; ; ROUTINE VALUE: ; ; ** None ** ; ; SIDE EFFECTS: ; ; Contents of processor registers r0 & r1 are modified ; ; -- .entry put_clientdata,^m movaq fao_desc,r2 ; get base of fao string descriptor movzwl #fao_buffer_len,(r2) ; set length of fao string buffer movab fao_buffer, - ; set address of fao string buffer dsc$a_pointer(r2) ; pushl 4(ap) ; pass base of client data buffer pushaq (r2) ; pass fao's 'outbuf' argument pushaw (r2) ; pass fao's 'outlen' argument pushaq fao$t_clientdata ; pass fao's 'ctrstr' argument calls #4,g^sys$fao ; format client data buffer for output pushaq (r2) ; pass descriptor of string to output calls #1,g^lib$put_output ; output client data to sys$output ret ; return to caller .sbttl Output Server Connection Info ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine outputs to sys$output the server host's connection info ; consisting of: ; ; a) server ipv4 address ; b) server port number ; ; CALLING SEQUENCE: ; ; calls #1,put_serverconn ; ; INPUT PARAMETERS: ; ; 4(ap) - address of server's ipv4 socket address structure ; ; IMPLICIT INPUTS: ; ; fao$t_serverconn - control string to format server connection info ; ; OUTPUT PARAMETERS: ; ; ** None ** ; ; IMPLICIT OUTPUTS: ; ; fao_buffer - fao string buffer ; fao_desc - fao string descriptor ; ; ROUTINE VALUE: ; ; ** None ** ; ; SIDE EFFECTS: ; ; Contents of processor registers r0 & r1 are modified ; ; -- .entry put_serverconn,^m movaq fao_desc,r2 ; get base of fao string descriptor movzwl #fao_buffer_len,(r2) ; set length of fao string buffer movab fao_buffer, - ; set address of fao string buffer dsc$a_pointer(r2) ; movl 4(ap),r3 ; get base of socket address structure movzwl sin$w_port(r3),-(sp) ; isolate server's port no. calls #1,g^decc$ntohs ; get port no. in host-byte order pushl r0 ; pass server's port no. pushl sin$l_addr(r3) ; isolate server's ipv4 address calls #1,g^decc$inet_ntoa ; convert ipv4 address to string pushl r0 ; pass server's ipv4 address string pushaq (r2) ; pass fao's 'outbuf' argument pushaw (r2) ; pass fao's 'outlen' argument pushaq fao$t_serverconn ; pass fao's 'ctrstr' argument calls #5,g^sys$fao ; format connection info for output pushaq (r2) ; pass descriptor of string to output calls #1,g^lib$put_output ; output connection info to sys$output ret ; return to caller .sbttl Output Error Message ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine outputs error messages to sys$output without modifying ; the contents of process register r0. ; ; CALLING SEQUENCE: ; ; calls #1,put_errmsg ; ; INPUT PARAMETERS: ; ; 4(ap) - address of error message string ; ; IMPLICIT INPUTS: ; ; ** None ** ; ; OUTPUT PARAMETERS: ; ; ** None ** ; ; IMPLICIT OUTPUTS: ; ; ** None ** ; ; ROUTINE VALUE: ; ; ** None ** ; ; SIDE EFFECTS: ; ; ** None ** ; ; -- .entry put_errmsg,^m<> pushl r0 ; save process register r0 pushl 4(ap) ; pass base of error message string calls #1,g^lib$put_output ; output error message to sys$output popl r0 ; restore processor register r0 ret ; return to caller .end start