#pragma module NNTP_NETIO "NNTP_NETIO-1-A" /* **++ ** FACILITY: NNTP Server for OpenVMS ** ** MODULE DESCRIPTION: ** ** This module contains upper-level routines to performs a NNTP ** oriented I/O operations. The low-level network I/O use the MadGoat NETLIB API. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: ??-???-1996 ** ** MODIFICATION HISTORY: ** ** {@tbs@}... **-- */ /* ** ** INCLUDE FILES ** */ #include "nntp.h" #include "netlib_dir:netlibdef.h" /* ** ** Some constants ** */ unsigned int shuttype = NETLIB_K_SHUTDOWN_BOTH, which = NETLIB_K_LOOKUP_DNS, adrsize = sizeof(struct INADDRDEF), sinsize = sizeof(struct SINDEF); /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Read one line from TCP socket. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** bufp: a buffer to save gottent line ** bufl: a legth of data in the buffer ** TimeOut: a timeout for reading operation ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int net_read_line ( void *chan, char *bufp, ushort *bufl, int *TimeOut ) { struct dsc$descriptor buf_dsc; /* ** Set-up the buffer descriptor */ INIT_SDESC(buf_dsc,*bufl,bufp); *bufl = 0; /* ** Call network read operation */ return netlib_readline (&chan,&buf_dsc,bufl,0,TimeOut,0,0,0); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Read multiple lines (NNTP message) from TCP socket to buffer. If message ** exceed the given buffer size then skip this message by reading to terminator. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** bufp: a buffer to save gottent line ** bufl: a legth of data in the buffer ** TimeOut: a timeout for reading operation ** ** RETURN VALUE: ** ** nonzero - VMS condition code ** zero - message is too big, is skipped ** **-- */ int net_read_mline ( void *chan, char *bufp, ushort *bufl, int *TimeOut ) { int status; ushort totlen = 0, flag,idx0 = 0; struct dsc$descriptor buf_dsc,trm_dsc,tmp_dsc; struct NETLIBIOSBDEF iosb; /* ** Set-up descriptors */ INIT_SDESC(trm_dsc,5,NNTP_EOM); INIT_SDESC(buf_dsc,*bufl,bufp); /* ** Switch from line-by-line to stream mode reading */ flag = NETLIB_M_FLUSH; status = netlib_readline (&chan,&buf_dsc,&totlen,&flag,TimeOut,&iosb,0,0); /* ** Check for . terminator */ if ( totlen >= 5 ) { INIT_SDESC(tmp_dsc,totlen,bufp); if ( idx0 = str$position(&tmp_dsc,&trm_dsc) ) { *bufl = idx0; return (SS$_NORMAL); } } flag = 0; while (1) { do { INIT_SDESC(buf_dsc,(*bufl)-totlen,bufp+totlen); if ( !(1 & (status = netlib_read (&chan,&buf_dsc,0,0,0,TimeOut,&iosb,0,0))) ) return status; if ( !(buf_dsc.dsc$w_length = iosb.iosb_w_count) ) continue; totlen +=iosb.iosb_w_count; /* ** Check for . terminator */ if ( totlen >= 5 ) { INIT_SDESC(tmp_dsc,totlen,bufp); if ( idx0 = str$position(&tmp_dsc,&trm_dsc) ) { *bufl = idx0; return ( flag?SS$_INSFMEM:SS$_NORMAL); } } } while ( totlen < *bufl ); /* ** A message is bigger the buffer size, skip this message */ INIT_SDESC(buf_dsc,*bufl,bufp); flag = 5; str$copy_r(&buf_dsc,&flag,bufp+totlen-flag); if (!$VMS_STATUS_SUCCESS(status)) return status; totlen = flag; flag++; } return 0; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Close a TCP connection. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** ** RETURN VALUE: ** ** None. **-- */ void net_close (void *chan) { int status; if ( chan ) { netlib_shutdown(&chan,&shuttype,0,0,0); netlib_close(&chan); }; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Open a TCP connection to remote NNTP server. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** suck_host_name: a remote host IP name ** suck_host_len: a length of the remote host name ** port: TCP port number ** ** RETURN VALUE: ** ** VMS condition code **-- */ int net_connect_out ( void *chan, char *suck_host_name, ushort suck_host_len, ushort port ) { int status; struct dsc$descriptor dsc; struct SINDEF remsin; unsigned int remlen; /* ** Set-up host name descriptor */ INIT_SDESC(dsc, suck_host_len, suck_host_name); /* ** Create a socket (network context) */ if ( !(1 & (status = netlib_socket(chan))) ) return status; /* ** Open a TCP connection */ return netlib_connect_by_name(chan, &dsc, &port); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Create a listen TCP socket at specified TCP port. Depending from ** input parameters accept an incoming connection. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** port: TCP port number ** ipadr: an IP address of a remote host ** ipadrlen: a length of the IP address of the remote host ** ipname: an IP name (if resolved) of the remote host ** ipnamelen: a length of the IP name of the remote host ** ** RETURN VALUE: ** ** VMS condition code **-- */ int net_connect_inc ( void *chan, ushort port, char *ipadr, ushort *ipadrlen, char *ipname, ushort *ipnamelen ) { int status; struct SINDEF remsin,locsin; unsigned int remlen,sinlen; static void *network_listener = NULL; struct dsc$descriptor adrdsc; if ( !network_listener ) { /* ** Initialize passive socket */ memset(&locsin, 0, sinsize); port = (port?port:NNTP_TCPPORT); locsin.sin_w_port = netlib_hton_word(&port); if ( !(1 & (status = netlib_socket(&network_listener))) ) return status; if ( !(1 & (status = netlib_bind(&network_listener, &locsin, &sinsize))) ) return status; if ( !(1 & (status = netlib_listen(&network_listener))) ) return status; } /* ** Wait incomming conection request */ if ( !(1 & (status = netlib_accept(&network_listener, chan, &remsin, &sinsize, &sinlen,0, 0, 0))) ) return status; /* ** Get IP address and IP name of remote host */ INIT_SDESC(adrdsc, *ipnamelen, ipname); *ipnamelen = 0; if ( (1 & (status = netlib_address_to_name(chan,&which,&remsin.sin_x_addr,&adrsize, &adrdsc,&adrdsc.dsc$w_length,0,0,0))) ) { str$upcase(&adrdsc,&adrdsc); *ipnamelen = adrdsc.dsc$w_length; } SET_SDESC(adrdsc, *ipadrlen, ipadr); *ipadrlen = 0; if ( (1 & (status = netlib_addrtostr(&remsin.sin_x_addr,&adrdsc,&adrdsc.dsc$w_length))) ) *ipadrlen = adrdsc.dsc$w_length; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Send a line as-is to TCP connection. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** bufp: a buffer with the line to send ** bufl: a length of the buffer ** ** RETURN VALUE: ** ** VMS condition code **-- */ int net_send_line ( void *chan, char *bufp, ushort bufl ) { struct dsc$descriptor buf_dsc; INIT_SDESC(buf_dsc,bufl,bufp); return netlib_writeline (&chan,&buf_dsc,0,0,0,0,0); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Send a line with command and read an answer from the remote host. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** cmd: a command string to send ** cmdl: a length of the command string ** bufp: a work buffer ** bufl: a work buffer length ** rc: a NNTP code ** TimeOut: a timeout of network I/O operation ** ** RETURN VALUE: ** ** VMS condition code **-- */ int net_send_cmd ( void *chan, char *cmd, ushort cmdl, char *bufp, ushort *bufl, ushort *rc, int *TimeOut ) { int status; struct dsc$descriptor buf_dsc; INIT_SDESC(buf_dsc,cmdl,cmd); if ( !(1 & (status = netlib_writeline (&chan,&buf_dsc,0,0,0,0,0))) ) return status; INIT_SDESC(buf_dsc,*bufl,bufp); if ( !(1 & (status = netlib_readline (&chan,&buf_dsc,bufl,0,TimeOut,0,0,0))) ) return status; if ( !lib$cvt_dtb(3,bufp,rc) ) return SS$_BADPARAM; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Send multiple lines to remote host over TCP connection. ** ** FORMAL PARAMETERS: ** ** chan: a network I/O context ** bufp: a buffer with line separated by pair ** bufl: a length of the line buffer ** ** RETURN VALUE: ** ** VMS condition code **-- */ int net_send_mline ( void *chan, char *bufp, ushort bufl ) { struct dsc$descriptor buf_dsc; /* ** Set-up descriptor, and send given line */ INIT_SDESC(buf_dsc,bufl,bufp); netlib_write (&chan,&buf_dsc,0,0,0,0,0); /* ** Set-up and send terminator */ INIT_SDESC(buf_dsc,5,NNTP_EOM); return netlib_write (&chan,&buf_dsc,0,0,0,0,0); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Convert an IP address from binary to text from. ** ** FORMAL PARAMETERS: ** ** ipb: an IP address in binary form ** bufp: a buffer to accept a converted IP address ** bufl: a length of the result string ** ** RETURN VALUE: ** ** VMS condition code **-- */ int net_ip_to_a ( int ipb, char *bufp, ushort *bufl ) { struct dsc$descriptor buf_dsc; INIT_SDESC(buf_dsc,*bufl,bufp); return netlib_addrtostr ((struct INADDRDEF *)&ipb,&buf_dsc,bufl); }