.title TCPIP$TCP_SERVER_QIO - Example TCP IPv4 Server .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 server 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_SERVER_QIO.MAR + TCPIP$INETDEF.MLB/library ; $ link TCPIP$TCP_SERVER_QIO ; ; on OpenVMS VAX: ; ; $ librarian/create/macro TCPIP$INETDEF.MLB SYS$LIBRARY:TCPIP$INETDEF.MAR ; $ macro TCPIP$TCP_SERVER_QIO.MAR + TCPIP$INETDEF.MLB/library ; $ link TCPIP$TCP_SERVER_QIO ; ; ; CONFIGURATION INSTRUCTIONS: ; ; No special configuration required. ; ; ; RUN INSTRUCTIONS: ; ; To run this example program: ; ; 1) Start this 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 the 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 server program then displays client connection information ; and client data as shown below: ; ; Accepted connection from host: a.b.c.d, port: n ; Data sent: 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 $inetsymdef ; define ipv4 related constants $sockaddrindef ; define ipv4 socket address structure $socketoptdef ; define socket option constants ; ; EQUATED SYMBOLS: ; serv_backlog = 1 ; server backlog 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 ; ; network i/o related structures ; conn_channel: .word 0 ; connection inet device i/o channel inet_device: ; string descriptor of logical .ascid /TCPIP$DEVICE:/ ; name of internet pseudodevice iosb: .quad 0 ; i/o status block listen_channel: .word 0 ; listen inet device i/o channel listen_sockchar: ; listen socket characteristics buffer ; with following fields: .word tcpip$c_tcp ; protocol .byte tcpip$c_stream ; socket type .byte tcpip$c_af_inet ; address format ; ; client related structures ; client_addr: .blkb sin$s_sockaddrin ; client socket address structure client_itemlst: ; client item-list 3 descriptor ; with following fields: .word sin$s_sockaddrin ; length .word 0 ; parameter type .address client_addr ; client ipv4 address structure .address client_retlen ; address to return length of ; client socket address structure client_retlen: ; returned length of client socket .long 0 ; address structure ; ; 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 tcpip$c_inaddr_any ; server ipv4 address ; (accept connection on any interface) .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 tcpip$c_sock_name ; parameter type .address serv_addr ; server ipv4 address structure serv_port: .long serv_portnum ; server port no. (in host byte order) ; ; socket option related item-list descriptors/elements ; reuseaddr_val: .long 1 ; reuseaddr socket option value (on) reuseaddr_val_len = .-reuseaddr_val reuseaddr_itemlst: ; reuseaddr item-list 2 element ; with following fields: .word reuseaddr_val_len ; length .word tcpip$c_reuseaddr ; parameter type .address reuseaddr_val ; reuseaddr option value reuseaddr_itemlst_len = .-reuseaddr_itemlst sockopt_itemlst: ; socket option item-list 2 descriptor ; with following fields: .word reuseaddr_itemlst_len ; length .word tcpip$c_sockopt ; parameter type .address reuseaddr_itemlst ; reuseaddr item-list element ; ; fao and error string storage ; fao$t_clientconn: .ascid \Accepted connection from host: !AZ, port: !UW\ fao$t_pktdata: .ascid \Hello, world!!\ fao$t_serverconn: .ascid \Waiting for a client connection on port: !UW\ fao$t_serverdata: .ascid \Data sent: !AZ\ msg$t_assignerr: .ascid \Failed to assign i/o channel(s) to TCPIP device\ msg$t_binderr: .ascid \Failed to bind socket\ msg$t_closerr: .ascid \Failed to close socket\ msg$t_connerr: .ascid \Failed to accept client connection\ msg$t_dassgnerr: .ascid \Failed to deassign i/o channel(s) to TCPIP device\ msg$t_shuterr: .ascid \Failed to shutdown client connection\ msg$t_sockerr: .ascid \Failed to create socket\ msg$t_writerr: .ascid \Failed to write data to client connection\ .sbttl Server Main ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This is the server's main-line code. It handles all the tasks of the ; server including: socket creation, accepting and/or rejecting client ; connections, writing client connection data, and terminating client ; connections. ; ; This example program implements a typical TCP IPv4 server using QIO ; system services to handle network i/o operations as shown below: ; ; 1) To create a socket and set REUSEADDR option: ; ; sys$assign() and sys$qiow(IO$_SETMODE) ; ; 2) To bind internet address and port number to a socket: ; ; sys$qiow(IO$_SETMODE) ; ; 3) To accept a connection request: ; ; sys$qiow(IO$_ACCESS|IO$M_ACCEPT) ; ; 4) To transfer data: ; ; sys$qiow(IO$_WRITEVBLK) ; ; 5) To shutdown a socket: ; ; sys$qiow(IO$_DEACCESS|IO$M_SHUTDOWN) ; ; 6) 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 ; client_addr - client socket address structure ; client_itemlst - client item-list 3 descriptor ; conn_channel - connection inet device i/o channel ; inet_device - inet device logical name ; iosb - i/o status block ; listen_channel - listen inet device i/o channel ; listen_sockchar - listen socket characteristics buffer ; serv_addr - server socket address structure ; serv_itemlst - server item-list 2 descriptor ; serv_port - server port number ; sockopt_itemlst - socket option item-list 2 descriptor ; ; 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 ; ; assign listen device socket ; $assign_s - ; devnam = inet_device, - ; inet device logical name chan = listen_channel ; listen inet device i/o channel blbs r0,10$ ; if lbs, assigned listen device socket pushaq msg$t_assignerr ; error occurred - inform user of calls #1,put_errmsg ; listen device socket error brw exit ; before returning to caller ; ; assign connection device socket ; 10$: $assign_s - ; devnam = inet_device, - ; inet device logical name chan = conn_channel ; connection inet device i/o channel blbs r0,create ; if lbs, assigned connection device ; socket pushaq msg$t_assignerr ; error occurred - inform user of calls #1,put_errmsg ; connection device socket error brw exit ; before returning to caller ; ; create listen socket ; create: $qiow_s efn = #efn$c_enf, - ; event flag chan = listen_channel, - ; i/o channel func = #io$_setmode, - ; i/o function code iosb = iosb, - ; i/o status block p1 = listen_sockchar,- ; p1 - socket characteristics buffer p5 = #sockopt_itemlst ; p5 - socket options blbc r0,10$ ; if lbc, error creating listen socket blbs iosb,bind ; if lbs, created listen socket movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_sockerr ; error occurred - inform user of calls #1,put_errmsg ; listen socket creation error brw exit ; before returning to caller ; ; bind server's internet address and port number to ; listen socket; set socket as a passive socket ; bind: $qiow_s efn = #efn$c_enf, - ; event flag chan = listen_channel,- ; i/o channel func = #io$_setmode, - ; i/o function code iosb = iosb, - ; i/o status block p3 = #serv_itemlst, - ; p3 - local socket name p4 = #serv_backlog ; p4 - connection backlog blbc r0,10$ ; if lbc, error binding port to socket blbs iosb,accept ; if lbs, bound port to listen socket movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_binderr ; error occurred - inform user of calls #1,put_errmsg ; error binding port to listen socket brw exit ; before returning to caller ; ; accept a connection from a client ; accept: 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 = listen_channel, - ; i/o channel func = #,- - ; i/o function code iosb = iosb, - ; i/o status block p3 = #client_itemlst,- ; p3 - remote socket name p4 = #conn_channel ; p4 - i/o channel for new connection blbc r0,10$ ; if lbc, error establishing connection blbs iosb,20$ ; if lbs, established client connection movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_connerr ; error occurred - inform user of calls #1,put_errmsg ; client connect error brw exit ; before returning to caller 20$: pushab client_addr ; pass client's socket address structure calls #1,put_clientconn ; output client's connection information ; ; connection established with a server; ; now attempt to write on this connection ; write: pushab fao$t_pktdata ; pass string to format server data calls #1,format_serverdata ; format server data $qiow_s efn = #efn$c_enf, - ; event flag chan = conn_channel, - ; i/o channel func = #io$_writevblk,- ; 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 writing to client blbs iosb,20$ ; if lbs, write to client completed movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_writerr ; error occurred - inform user of calls #1,put_errmsg ; client connection write error brw exit ; before returning to caller 20$: pushab buffer ; pass server's data buffer calls #1,put_serverdata ; output server'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_connection ; 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_connection: $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 connection socket ; failed blbs iosb,close_listen ; 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 ; ; close listen socket ; close_listen: $qiow_s efn = #efn$c_enf, - ; event flag chan = listen_channel,- ; i/o channel func = #io$_deaccess, - ; i/o function code iosb = iosb ; i/o status block blbc r0,10$ ; if lbc, close on listen socket failed blbs iosb,deassign ; if lbs, listen socket closed movzwl iosb,r0 ; save i/o completion status 10$: pushaq msg$t_closerr ; error occurred - inform user of calls #1,put_errmsg ; listen socket close error brw exit ; before returning to caller ; ; deassign all device sockets ; deassign: $dassgn_s - ; deassign connection device socket chan = conn_channel ; blbs r0,10$ ; if lbs, connection 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 10$: $dassgn_s - ; deassign listen device socket chan = listen_channel ; blbs r0,20$ ; if lbs, listen 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 ; 20$: movzbl #ss$_normal,r0 ; set success status exit: ret ; return to caller .sbttl Format Server Data ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine formats the server's packet data buffer. ; ; CALLING SEQUENCE: ; ; calls #1,format_serverdata ; ; INPUT PARAMETERS: ; ; 4(ap) - address of control string to format server packet data buffer ; ; IMPLICIT INPUTS: ; ; ** None ** ; ; OUTPUT PARAMETERS: ; ; ** None ** ; ; IMPLICIT OUTPUTS: ; ; buffer - i/o buffer ; fao_desc - fao string descriptor ; ; ROUTINE VALUE: ; ; ** None ** ; ; SIDE EFFECTS: ; ; Contents of processor registers r0 & r1 are modified ; ; -- .entry format_serverdata,^m movaq fao_desc,r6 ; get base of fao string descriptor movzwl #buffer_len,(r6) ; set length of fao string buffer movab buffer, - ; set address of fao string buffer dsc$a_pointer(r6) ; movc5 #0,@dsc$a_pointer(r6),- ; set fao string buffer to all 0's #0, - ; (r6),@dsc$a_pointer(r6) ; pushaq (r6) ; pass fao's 'outbuf' argument pushaw (r6) ; pass fao's 'outlen' argument pushl 4(ap) ; pass fao's 'ctrstr' argument calls #3,g^sys$fao ; format server packet data for output ret ; return to caller .sbttl Output Client Connection Info ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine outputs to sys$output the client host's connection info ; consisting of: ; ; a) client ipv4 address ; b) client port number ; ; CALLING SEQUENCE: ; ; calls #1,put_clientconn ; ; INPUT PARAMETERS: ; ; 4(ap) - address of client's ipv4 socket address structure ; ; IMPLICIT INPUTS: ; ; fao$t_clientconn - control string to format client 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_clientconn,^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 client's port no. calls #1,g^decc$ntohs ; get port no. in host-byte order pushl r0 ; pass client's port no. pushl sin$l_addr(r3) ; isolate client's ipv4 address calls #1,g^decc$inet_ntoa ; convert ipv4 address to string pushl r0 ; pass client's ipv4 address string pushaq (r2) ; pass fao's 'outbuf' argument pushaw (r2) ; pass fao's 'outlen' argument pushaq fao$t_clientconn ; 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 Server Connection Info ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine outputs to sys$output the server host's connection info ; consisting of: ; ; a) 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_servconn - 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. pushaq (r2) ; pass fao's 'outbuf' argument pushaw (r2) ; pass fao's 'outlen' argument pushaq fao$t_serverconn ; pass fao's 'ctrstr' argument calls #4,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 Server Data ; ++ ; FUNCTIONAL DESCRIPTION: ; ; This routine outputs to sys$output the server data buffer. ; ; CALLING SEQUENCE: ; ; calls #1,put_serverdata ; ; INPUT PARAMETERS: ; ; 4(ap) - address of server data buffer ; ; IMPLICIT INPUTS: ; ; fao$t_serverdata - control string to format server 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_serverdata,^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 server data buffer pushaq (r2) ; pass fao's 'outbuf' argument pushaw (r2) ; pass fao's 'outlen' argument pushaq fao$t_serverdata ; pass fao's 'ctrstr' argument calls #4,g^sys$fao ; format server data buffer for output pushaq (r2) ; pass descriptor of string to output calls #1,g^lib$put_output ; output server data 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