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.
|