HP OpenVMS Systemsask the wizard |
The Question is:
I cannot get the drop idle and keep alive TCPIP socket options to work. I have
experimented using the attached program and 2 Alpha's running the program as
server on one Alpha and client on the other. Neither server nor client drops
the connection after I
physically disconnect one Alpha from the other. And if I after a while then
physically reconnect the Alpha's then the server continues printing the
message repeatedly sent from the client (as if nothing happened). I have also
verified this by running ser
ver and client from the debugger. Neither side drops out of its select() after
I disconnect one Alpha from the other. I have never yet seen select() return
with an "exception". Is this where I would see an exception? Both Alpha's are
running TCPIP v5.0a.
Any help is much appreciated.
(I ran the attached programs with droptime=10, probetime=-5 and reptime=60)
/*
* This is a testbed for examination of TCPIP sockets.
* It runs as server or client depending on the commandline args.
* The server prints the messages received as sent by clients.
* It is derived from tcpip$examples:tcp_server_ipc.c and tcp_client_ipc.c.
*
* The server args are
*
* <local> : Local interface
* ="": any local interface
* <port> : Port number
* <segsize> : Max size of recv() segments
* =0: no segmentation
* <droptime>: Wait in seconds until drop of idle connection
* =0: no drop time
*
* Examples
*
* mcr <filespec> "" 5678 0 0
* mcr <filespec> "192.168.12.34" 5678 5 60
*
* The client args are
*
* <local> : Local interface
* ="": any local interface
* <remote> : Remote interface
* <port> : Port number
* <message> : Any message
* <segsize> : Max size of send() segments
* =0: no segmentation
* <probetime>: Wait in seconds until next probe
* <0: enable keepalive
* =0: no probe time
* <reptime> : Wait in seconds until repeat
* <0: do not wait
* =0: no repeat time
*
* Examples
*
* mcr <filespec> "" "192.168.12.34" 5678 "Hi there" 0 5 2
* mcr <filespec> "192.168.12.34" omega 5678 "Hi there" 0 0 0
*
*/
#include <ssdef.h> //SS$_<xyz> sys ser return stati <8-)
#include <stdio.h> //UNIX 'Standard I/O' Definitions
#include <iodef.h> //I/O function code defs
#include <starlet.h> //Sys ser calls
#include <lib$routines.h> //LIB$ RTL-routine signatures.
#include <string.h> //String handling function definitions
#include <unixio.h> //Prototypes for UNIX emulation functions
#include <signal.h> //UNIX style Signal Value Definitions
#include <errno.h> //C RTL Unix style error identifiers
#include <in.h> //internet system constants and structures
#include <inet.h> //Network address info.
#include <netdb.h> //Network database library info.
#include <socket.h> //TCP/IP socket definitions.
#include <stdlib.h> //General Utilities
#include <tcpip$inetdef.h> //TCPIP network definitions
static int Server();
static int Client();
static void Cleanup();
static void VacateMsgBuf();
static int GetSockTag();
main(
int argc,
char *argv[] )
int sts, s_t_s, status;
/*
* Check args
*/
if( argc == 5 )
sts = Server( argc, argv );
else
if( argc == 8 )
sts = Client( argc, argv );
else
{
printf( "server args:\n" );
printf( " <local> <port> <segsize> <droptime>\n" );
printf( "client args:\n" );
printf( " <local> <remote> <port> <message> <segsize> <probetime>
<reptime>\n");
sts = 0;
}
return( sts );
/*
* Server
*/
static int Server(
int argc,
char *argv[] )
int sts, s_t_s, status;
int sock;
int port;
int optval;
int flag;
int cnt;
int msgsiz_recv;
int msgoff;
int remsiz;
int segsiz;
int size;
int sock_connect_msgsiz;
int sts_select;
int sock_listen;
int sock_accept;
int sock_connect;
int wait_read;
int wait_write;
int wait_probe;
int wait_drop;
int repeat_probe;
int unsigned sock_mask_read;
int unsigned sock_mask_write;
int unsigned sock_mask_excep;
int unsigned sock_listen_mask;
int unsigned sock_accept_mask;
int unsigned sock_connect_mask;
int unsigned sock_read_mask;
int unsigned sock_write_mask;
int unsigned sock_accept_busy;
int unsigned sizeof_sock_accept_tag;
int unsigned sizeof_sock_connect_tag;
char *local;
char *remote;
char *msgbuf_send;
char *sock_connect_msgbuf;
static //bind fails unless static
struct sockaddr_in sock_listen_tag; //tag struct for socket
static //bind fails unless static
struct sockaddr_in sock_accept_tag; //tag struct for socket
static //bind fails unless static
struct sockaddr_in sock_connect_tag; //tag struct for socket
struct timeval wait_select = { 0, 0 },
*wait_select_p;
char msgbuf_recv[BUFSIZ];
int sock_accept_msgsiz[32] = { 0 };
char sock_accept_msgbuf[32][10];//small to illustrate
struct in_addr sock_connect_addr[32];
/*
* Get args
*/
local = argv[1]; //local interface
port = atoi( argv[2] ); //port number
if( !port || 65535 < port )
{
printf( "Invalid port: %s\n", argv[2] );
return( 0 );
}
segsiz = atoi( argv[3] ); //segment size
wait_drop = atoi( argv[4] ); //idle connection timeout
/*
* Get socket tag of listen socket
*/
sts = GetSockTag( local, port, &sock_listen_tag );
if( !sts )
{
perror( "GetSockTag" );
return( 0 );
}
/*
* Create (untagged) listen socket
*/
sock_listen = socket( AF_INET, SOCK_STREAM, 0 );
if( sock_listen == -1 )
{
perror( "socket" );
return( 0 );
}
/*
* Enable reuse of local addresses in assignment of local addresses to the
* listening socket. Otherwise bind() may fail with error "local address
* already in use" on immediate rerun of the program (because of a delay in
* TCPIP on cleaning up?). Setting the option does not also enable reuse of
* the port number if already in use by another process. Maybe that is what
* option SO_REUSEPORT is for.
* (Note, that TCPIP$C_SOCKOPT as used with the $QIO implementation does
* NOT carry the same value as SOL_SOCKET)
*/
optval = 1;
sts = setsockopt( sock_listen, //socket
SOL_SOCKET, SO_REUSEADDR, //option ident
(char *)&optval, sizeof(optval) );//option value
if( sts == -1 )
{
perror( "setsockopt" );
Cleanup( sock_listen, 0 );
return( 0 );
}
/*
* Assign tag to listen socket
*/
sts = bind( sock_listen,
(struct sockaddr *)&sock_listen_tag,
sizeof(sock_listen_tag) );
if( sts == -1 )
{
perror( "bind" );
Cleanup( sock_listen, 0 );
return( 0 );
}
/*
* Listen on listen socket for connection requests from connect socket.
*/
sts = listen( sock_listen, 5 );
if( sts == -1 )
{
perror( "listen" );
Cleanup( sock_listen, 0 );
return( 0 );
}
sock_listen_mask = 1<<sock_listen;
sock_accept_mask = 0; //no sockets accepted yet
/*
* Process incoming traffic
*/
while( !0 )
{
/*
* Vacate message buffers of idle sockets
*/
sock_accept_busy = sock_accept_mask & sock_mask_read;
for( sock=0; sock<32; sock++ )
{
if( !(sock_accept_msgsiz[sock]) ) //if buffer empty
continue;
if( sock_accept_busy & 1<<sock ) //if buffer busy
continue;
VacateMsgBuf( sock, sock_connect_addr[sock],
sock_accept_msgbuf[sock], &sock_accept_msgsiz[sock] );
}
/*
* Select
*/
sock_read_mask = sock_listen_mask
| sock_accept_mask;
sock_mask_read = sock_read_mask;
sock_mask_write = 0; //no writing in this example
sock_mask_excep = sock_read_mask;
if( !sock_accept_busy ) //if no sockets were busy
wait_select_p = 0; //wait until ready
else
wait_select_p = &wait_select; //wait to coalesce and vacate
sts_select = select( 32,
(void *)&sock_mask_read,
(void *)&sock_mask_write,
(void *)&sock_mask_excep,
(void *)wait_select_p );
/*
* Timeout.
*/
if( !sts_select )
{
continue;
}
/*
* Process exception
*/
if( sock_mask_excep )
{
for( sock=0; sock<32; sock++ )
{
if( !(sock_mask_excep & 1<<sock) )
continue;
sizeof_sock_connect_tag = sizeof( sock_connect_tag );
getsockname( sock, //get tag of peer
(struct sockaddr *)&sock_connect_tag,
&sizeof_sock_connect_tag );
printf( "sock: %d remote: %s select: exception\n",
sock, inet_ntoa(sock_connect_tag.sin_addr) );
}
}
/*
* Accept connection request on listen socket and spawn accept socket
*/
if( sock_listen_mask & sock_mask_read ) //if connection request
{
sizeof_sock_connect_tag = sizeof( sock_connect_tag );
sock_accept = accept( sock_listen,
(struct sockaddr *)&sock_connect_tag,//tag of peer
&sizeof_sock_connect_tag );
if( sock_accept == -1 )
{
perror( "accept" );
Cleanup( sock_listen, 0 );
}
else
if( 32 <= sock_accept ) //if no room in this program
{
printf( "sock: %d remote: %s accept: no room\n",
sock, inet_ntoa(sock_connect_tag.sin_addr) );
Cleanup( sock_accept, 1 );
}
else
{
sock_accept_mask |= 1<<sock_accept; //insert
printf( "sock: %d chnl: %d remote: %s accept: ok\n",
sock_accept, decc$get_sdc( sock_accept ),
inet_ntoa(sock_connect_tag.sin_addr) );
/*
* Save addr of peer for printing
*/
sock_connect_addr[sock_accept] = sock_connect_tag.sin_addr;
/*
* Set connection idle timeout on accept socket
* (Note, that TCPIP$C_TCPOPT and TCPIP$C_TCP as used with the $QIO
* implementation carry the same value as IPPROTO_TCP)
*/
if( wait_drop )
{
sts = setsockopt( sock_accept, //socket
IPPROTO_TCP, TCPIP$C_TCP_DROP_IDLE,//option ident
(char *)&wait_drop, sizeof(wait_drop) );//option value
if( sts == -1 )
{
perror( "setsockopt" );
Cleanup( sock_accept, 1 );
sock_accept_mask &= ~(1<<sock); //remove
}
}
}
}
/*
* Receive message from connect socket to accept socket
*/
sock_accept_busy = sock_accept_mask & sock_mask_read;
if( sock_accept_busy )
{
for( sock=0; sock<32; sock++ )
{
if( !( sock_accept_busy & 1<<sock ) ) //if not busy
continue;
if( !segsiz ) //if no segmentation
size = sizeof(msgbuf_recv);
else
if( segsiz < sizeof(msgbuf_recv) )
size = segsiz;
else
size = sizeof(msgbuf_recv);
flag = 0;
cnt = recv( sock,
msgbuf_recv, size, flag );
if( cnt == -1 ) //if error
{
perror( "recv" );
Cleanup( sock, 1 );
sock_accept_mask &= ~(1<<sock); //remove
}
else
if( cnt == 0 ) //peer closed
{
perror( "recv" );
Cleanup( sock, 1 );
sock_accept_mask &= ~(1<<sock); //remove
}
else //ok
{
/*
* The following is for the sake of the exercise. The buffer
* received is emptied into the dedicated buffer as space permits
* and the dedicated buffer emptied (printed) as it becomes full.
*/
msgoff = 0;
while( cnt )
{
remsiz = sizeof(sock_accept_msgbuf[sock])
- sock_accept_msgsiz[sock];
if( remsiz == 0 ) //no space
{
VacateMsgBuf( sock, sock_connect_addr[sock],//vacate
sock_accept_msgbuf[sock],
&sock_accept_msgsiz[sock] );
continue; //try again
}
if( remsiz < cnt ) //if not enough space
msgsiz_recv = remsiz;
else
msgsiz_recv = cnt;
memcpy( sock_accept_msgbuf[sock] //append
+ sock_accept_msgsiz[sock],
msgbuf_recv+msgoff, msgsiz_recv );
sock_accept_msgsiz[sock] += msgsiz_recv;
msgoff += msgsiz_recv;
cnt -= msgsiz_recv;
}
}
}
}
}
return( 1 );
/*
* Client
*/
static int Client(
int argc,
char *argv[] )
int sts, s_t_s, status;
int sock;
int port;
int optval;
int flag;
int cnt;
int msgsiz_send;
int msgoff;
int remsiz;
int segsiz;
int size;
int sock_connect_msgsiz;
int sts_select;
int sock_listen;
int sock_accept;
int sock_connect;
int wait_read;
int wait_write;
int wait_probe;
int wait_drop;
int repeat_probe;
int unsigned sock_mask_read;
int unsigned sock_mask_write;
int unsigned sock_mask_excep;
int unsigned sock_listen_mask;
int unsigned sock_accept_mask;
int unsigned sock_connect_mask = 0;
int unsigned sock_read_mask;
int unsigned sock_write_mask;
int unsigned sock_accept_busy;
int unsigned sizeof_sock_accept_tag;
int unsigned sizeof_sock_connect_tag;
char *local;
char *remote;
char *msgbuf_send;
char *sock_connect_msgbuf;
static //bind fails unless static
struct sockaddr_in sock_listen_tag; //tag struct for socket
static //bind fails unless static
struct sockaddr_in sock_accept_tag; //tag struct for socket
static //bind fails unless static
struct sockaddr_in sock_connect_tag; //tag struct for socket
struct timeval wait_select = { 0, 0 },
*wait_select_p;
char msgbuf_recv[BUFSIZ];
int sock_accept_msgsiz[32] = { 0 };
char sock_accept_msgbuf[32][10];//small to illustrate
struct in_addr sock_connect_addr[32];
/*
* Get args
*/
local = argv[1];
remote = argv[2];
port = atoi( argv[3] );
if( !port || 65535 < port )
{
printf( "Invalid port: %s\n", argv[2] );
return( 0 );
}
sock_connect_msgbuf = argv[4];
sock_connect_msgsiz = strlen( sock_connect_msgbuf );
segsiz = atoi( argv[5] );
wait_probe = atoi( argv[6] );
if( wait_probe < 0 ) //if enable keepalive
{
wait_probe *= -1; //make positive
repeat_probe = 1; //enable keepalive
}
else
repeat_probe = 0; //do not enable keepalive
wait_write = atoi( argv[7] ); //wait until repeat
/*
* Get socket tag of connect socket
*/
sts = GetSockTag( local, 0, &sock_connect_tag );
if( !sts )
{
perror( "GetSockTag" );
return( 0 );
}
/*
* Get socket tag of listen socket
*/
sts = GetSockTag( remote, port, &sock_listen_tag );
if( !sts )
{
perror( "GetSockTag" );
return( 0 );
}
/*
* Create (untagged) connect socket
*/
sock_connect = socket( AF_INET, SOCK_STREAM, 0 );
if( sock_connect == -1 )
{
perror( "socket" );
return( 0 );
}
/*
* Set wait until connection timeout (and keepalive, if enabled)
* (Note, that TCPIP$C_TCPOPT and TCPIP$C_TCP as used with the $QIO
* implementation carry the same value as IPPROTO_TCP)
*/
if( wait_probe )
{
sts = setsockopt( sock_connect, //socket
IPPROTO_TCP, TCPIP$C_TCP_PROBE_IDLE,//option ident
(char *)&wait_probe, sizeof(wait_probe) );//option value
if( sts == -1 )
{
perror( "setsockopt" );
Cleanup( sock_connect, 0 );
return( 0 );
}
}
/*
* Enable keepalive e.g. enable repeat of probe, if any
* (Note, that TCPIP$C_KEEPALIVE as used with the $QIO implementation
* carry the same value as SO_KEEPALIVE)
*/
if( repeat_probe )
{
optval = repeat_probe;
sts = setsockopt( sock_connect, //socket
SOL_SOCKET, SO_KEEPALIVE, //option ident
(char *)&optval, sizeof(optval) );//option value
if( sts == -1 )
{
perror( "setsockopt" );
Cleanup( sock_connect, 0 );
return( 0 );
}
}
/*
* Assign tag to connect socket
*/
sts = bind( sock_connect,
(struct sockaddr *)&sock_connect_tag,
sizeof(sock_connect_tag) );
if( sts == -1 )
{
perror( "bind" );
Cleanup( sock_connect, 0 );
return( 0 );
}
/*
* Connect connect socket to listen socket.
*/
sts = connect( sock_connect,
(struct sockaddr *)&sock_listen_tag,//socket tag of peer
sizeof(sock_listen_tag) );
if( sts == -1 )
{
perror( "connect" );
Cleanup( sock_connect, 0 );
return( 0 );
}
printf( "sock: %d chnl: %d connect: ok\n",
sock_connect, decc$get_sdc( sock_connect ) );
sock_connect_mask |= 1<<sock_connect; //insert
msgbuf_send = sock_connect_msgbuf; //init
msgsiz_send = sock_connect_msgsiz;
/*
* Process outgoing traffic
*/
while( !0 )
{
if( !msgsiz_send ) { //if nothing to send
msgbuf_send = sock_connect_msgbuf; //reload
msgsiz_send = sock_connect_msgsiz;
if( wait_write < 0 ) //if do not wait
{
sock_write_mask = sock_connect_mask;
wait_select_p = 0; //wait until ready
}
else
if( !wait_write ) //if do not repeat
{
break;
}
else
{
sock_write_mask = 0;
wait_select.tv_sec = wait_write;
wait_select_p = &wait_select; //wait until timeout
}
}
else
{
sock_write_mask = sock_connect_mask;
wait_select_p = 0; //wait until ready
}
/*
* Select
*/
sock_mask_read = 0; //no reading in this example
sock_mask_write = sock_write_mask;
sock_mask_excep = sock_connect_mask;
sts_select = select( 32,
(void *)&sock_mask_read,
(void *)&sock_mask_write,
(void *)&sock_mask_excep,
(void *)wait_select_p );
/*
* Timeout.
*/
if( !sts_select )
{
continue;
}
/*
* Process exception
*/
if( sock_mask_excep )
{
perror( "select" );
}
/*
* Send message from connect socket to accept socket
*/
if( sock_connect_mask & sock_mask_write )
{
if( !segsiz )
size = msgsiz_send;
else
if( segsiz < msgsiz_send )
size = segsiz;
else
size = msgsiz_send;
flag = 0;
cnt = send( sock_connect,
msgbuf_send, size, flag );
if( cnt == -1 ) //if error
{
perror( "send" );
Cleanup( sock_connect, 1 );
sock_connect_mask &= ~(1<<sock_connect);//remove
return( 0 );
}
else
{
msgbuf_send += cnt;
msgsiz_send -= cnt;
}
}
}
/*
* Call cleanup to shutdown and close socket.
*/
Cleanup( sock_connect, 1 );
return( 1 );
static
int GetSockTag(
char *name,
int port,
struct sockaddr_in *sock_tag ) //tag struct for socket
int sts, s_t_s, status;
int idx;
int family;
int addr;
struct hostent *hostent; //pointer to host file entry
/*
* Get value of members of tag structure of listen socket
*/
if( !strlen( name ) )
{
/*
* Interface not specified e.g. listen using any local interface
*/
family = AF_INET; //the only legal value
addr = INADDR_ANY; //any local interface
}
else
{
/*
* Interface specified e.g. listen using specified local interface only
*/
addr = 0;
for( idx=0; !addr; idx++ )
{
switch( idx ) {
case 0: //try by name in host file
hostent = gethostbyname( name );
if( hostent )
{
family = hostent->h_addrtype; //AF_INET
addr = *(int *)hostent->h_addr_list[0];//first one in host file
}
break;
case 1: //try by addr in host file
hostent = gethostbyaddr( name, strlen(name), AF_INET );
if( hostent )
{
family = hostent->h_addrtype; //AF_INET
addr = *(int *)hostent->h_addr_list[0];//first one in host file
}
break;
case 2: //try by addr ignoring host file
family = AF_INET; //the only legal value
addr = inet_addr( name );
if( addr == -1 )
addr = 0;
break;
default:
return( 0 );
}
}
}
/*
* Fill in members of tag structure of listen socket
*/
sock_tag->sin_family = family; //AF_INET
sock_tag->sin_addr = *(struct in_addr *)&addr;//IP address
sock_tag->sin_port = htons( port ); //port number
return( 1 );
static
void Cleanup(
int sock,
int shut )
int sts, s_t_s, status;
/*
* Shutdown socket
*/
if( shut )
{
sts = shutdown( sock, 2 );
if( sts == -1 )
perror( "shutdown" );
}
/*
* Close socket
*/
sts = close( sock );
if( sts == -1 )
perror( "close" );
return;
static
void VacateMsgBuf(
int sock,
struct in_addr sin_addr,
char *msgbuf,
int *msgsiz )
int sts, s_t_s, status;
/*
* Print message contents
*/
printf( "sock: %d remote: %s recv: %*.*s\n",
sock, inet_ntoa(sin_addr), *msgsiz, *msgsiz, msgbuf );
*msgsiz = 0; //now empty
return;
The Answer is : Please contact the Compaq Customer Support Center for assistance with this question.
|