#pragma module ADC_NETIO "ADC_NETIO-1-D" #define __MODULE__ "ADC_NETIO" /* **++ ** FACILITY: StarLet ADC server for OpenVMS ** ** MODULE DESCRIPTION: ** ** This module covers network I/O functionality. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 14-JUL-2009 ** ** DESIGN ISSUES: ** ** MODIFICATION HISTORY: ** 4-OCT-2009 RRL Removed Send buffer size setup. ** ** {@tbs@}... **-- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "macros.h" typedef unsigned int (*ast_routine_t)(void *astprm); $DESCRIPTOR(dsc_ucxdev,"UCX$DEVICE"); $DESCRIPTOR(dsc_tcpipdev,"TCPIP$DEVICE"); const unsigned rbfsz=512,one=1; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Open a passive socket and listening for incomming TCP-connection request. ** ** FORMAL PARAMETERS: ** ** netchan: A returned network channel ** port: A local port number, 0 - assume default port number ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int netio_start ( unsigned * netchan, unsigned short port ) { int status; const struct { short proto; char type; char domain; } sck_parm = {TCPIP$C_TCP,TCPIP$C_STREAM,TCPIP$C_AF_INET}; iosb iosb; struct sockaddr_in home; const ile2 lhst_adrs = {sizeof(struct sockaddr_in),TCPIP$C_SOCK_NAME,&home}, sock_opt[]={{sizeof(one),TCPIP$C_REUSEADDR,&one}, {sizeof(rbfsz),TCPIP$C_RCVBUF,&rbfsz}, {sizeof(one),TCPIP$C_KEEPALIVE,&one}}, options = {sizeof(sock_opt),TCPIP$C_SOCKOPT,&sock_opt}; /* ** Open a network device */ if ( !(1 & (status = sys$assign(&dsc_ucxdev,netchan,0,0))) ) { if ( status != SS$_NOSUCHDEV ) return status; if ( !(1 & (status = sys$assign( &dsc_tcpipdev,netchan,0,0))) ) return status; } /* ** Create connection socket */ if ( !(1 & (status = sys$qiow(EFN$C_ENF,*netchan,IO$_SETMODE,&iosb,0,0, &sck_parm,0,0,0,&options,0))) || !(iosb.iosb$w_status & 1) ) { sys$dassgn (*netchan); return (1 & status)?iosb.iosb$w_status:status; } /* ** Initialize structure for creating main listening sockets */ memset(&home,0,sizeof(struct sockaddr_in)); home.sin_port = htons(port); home.sin_family = INET$C_AF_INET; home.sin_addr.s_addr = TCPIP$C_INADDR_ANY; /* ** Start waiting incomming connection request */ if ( !(1 & (status = sys$qiow(EFN$C_ENF,*netchan,IO$_SETMODE,&iosb,0,0, 0,0,&lhst_adrs,5,0,0))) || !(iosb.iosb$w_status & 1) ) return (1 & status)?iosb.iosb$w_status:status; return status; } int netio_accept ( unsigned netchan, unsigned * chan, struct in_addr * addr, unsigned short *port ) { unsigned status, nchan = 0; unsigned short retlen = 0; iosb iosb; struct sockaddr_in rhost; ile3 rhost_item = {sizeof(struct sockaddr_in),0,&rhost,&retlen}; memset(&rhost,0,sizeof(struct sockaddr_in)); /* ** Create a socket for new connection */ if ( !(1 & (status = sys$assign(&dsc_ucxdev,&nchan,0,0))) ) { if ( status != SS$_NOSUCHDEV ) return status; if ( !(1 & (status = sys$assign(&dsc_tcpipdev,chan,0,0))) ) return status; } /* ** Accept client connection */ if ( !(1 & (status = sys$qiow(EFN$C_ENF,netchan,IO$_ACCESS|IO$M_ACCEPT,&iosb,0,0, 0,0,&rhost_item,&nchan,0,0))) || !(iosb.iosb$w_status & 1) ) { sys$dassgn (nchan); return (1 & status)?iosb.iosb$w_status:status; } *addr = rhost.sin_addr; *port = ntohs(rhost.sin_port); *chan = nchan; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Close a network I/O channel. ** ** FORMAL PARAMETERS: ** ** chan: A network I/O channel returned by netio_accept() ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int netio_close ( unsigned chan ) { iosb iosb; sys$qiow(EFN$C_ENF,chan,IO$_DEACCESS|IO$M_SHUTDOWN, &iosb, 0, 0, 0, 0, 0, TCPIP$C_DSC_ALL,0, 0); sys$qiow(EFN$C_ENF,chan,IO$_DEACCESS, &iosb, 0, 0, 0, 0, 0, 0, 0, 0); return sys$dassgn (chan); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Canceling all queued and processed request due of expiration timer. ** ** FORMAL PARAMETERS: ** ** reqidt: pointer to a network channel ** ** RETURN VALUE: ** ** None ** ** SIDE EFFECTS: ** ** Cancel _all_ request for the given I/O channel. **-- */ static void timer_ast ( unsigned *reqidt ) { sys$cantim(reqidt,0); sys$cancel(*reqidt); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Read a data from the specified network channel with timeout to a specified buffer. ** ** FORMAL PARAMETERS: ** ** chan: a channel number, given from netio_open() or netio_conn() ** buf: a buffer to receiving data ** retlen: a length of a received data in the buffer ** ** iotmo: a timeout of network I/O, VMS Delta time ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int netio_readln ( unsigned chan, unsigned char * buf, unsigned short bufsz, unsigned short *bufl, ast_routine_t astrtn, void * astprm ) { int status; iosb iosb; if ( !bufsz ) return SS$_ENDOFFILE; /* ** Is there data in the buffer ? */ for (;;buf++) { status = sys$qiow (EFN$C_ENF,chan,IO$_READVBLK | IO$M_NOWAIT,&iosb,0,0, buf,1,0,0,0,0); status = (1 & status)?iosb.iosb$w_status:status; /* ** If we got a command line with terminator ** return success */ if ( (1 & status) && iosb.iosb$w_bcnt ) { *bufl += iosb.iosb$w_bcnt; if ( *(buf + (--iosb.iosb$w_bcnt) ) == 0x0A ) { buf[--(*bufl)] = '\0'; return SS$_ENDOFFILE; } } else if ( !(1 & status) && (status != SS$_SUSPENDED) ) return status; else break; } status = sys$qio (EFN$C_ENF,chan,IO$_SETMODE|IO$M_READATTN,&iosb,0,0, astrtn,astprm,0,0,0,0); return (1 & status)?iosb.iosb$w_status:status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Write a data to a given network channel. ** ** FORMAL PARAMETERS: ** ** chan: a channel number, given from netio_open() or netio_conn() ** buf: a buffer witj data to send ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int netio_write ( unsigned chan, struct dsc$descriptor *buf ) { int status; iosb iosb; struct {unsigned l; char *a;} bvec[] = { {buf->dsc$w_length,buf->dsc$a_pointer},{1,"\n"}}; struct dsc$descriptor buf_d = { 0, DSC$K_CLASS_S, DSC$K_DTYPE_T, 0} ; /* ** Setup the buffer descriptor */ buf_d.dsc$a_pointer = (char *) &bvec; buf_d.dsc$w_length = sizeof(bvec); status = sys$qiow (EFN$C_ENF,chan,IO$_WRITEVBLK,&iosb,0,0, 0,0,0,0,&buf_d,0); return (1 & status)?iosb.iosb$w_status:status; }