Operating System - OpenVMS
1752323 Members
5260 Online
108786 Solutions
New Discussion

Re: UDP programming - how to specify a read timeout using io$readvblk

 
gmala
Occasional Contributor

UDP programming - how to specify a read timeout using io$readvblk

Is it possible to specify a read timeout on a UDP socket

using a sys$qiow (IO$READVBLK) like one can do using select()/recv()

using C-socket programming style?

Do I need to call some sort of sys$qiow (IO$SETMODE) with an appropriate

item list?

 

Thanks a lot in advance.

 

Giovanni

7 REPLIES 7
John Gillings
Honored Contributor

Re: UDP programming - how to specify a read timeout using io$readvblk

Giovanni,

 

   Some drivers implement a timeout option IO$M_TIMEOUT, some don't. If you haven't found it documented for your driver, you can assume your driver doesn't have one.

 

  If that's the case, you can implement your own timeout using "crossed ASTs". The idea is to have a timer with an AST that cancels the I/O, and specify an AST on the I/O that cancels the timer. In pseudo code

 

 

$SETIMR daytim=TimeoutInterval astadr=CancelIO reqidt=MyTimer
$QIOW chan=MyChan func=IO$READVBLK iosb=IOSB astadr=CancelTimer astprm=MyTimer (other parameters as required)



routine CancelIO
  $CANCEL chan=MyChan
end

routine CancelTimer(timerID)
  $CANTIM reqidt=timerID
end

 

After the $QIOW look at your IOSB. If it is successful, the I/O "won" the race, and the timer will have been cancelled. If the timer won, the IOSB will be SS$_CANCEL or SS$_ABORT, depending on how far the I/O had progressed. There are no race conditions, either the I/O will complete or it will get cancelled.

 

This mechanism also works for $QIO (asyncronous) I/Os, you just have to think a bit harder about the completion paths and how you manage them.

A crucible of informative mistakes
Hoff
Honored Contributor

Re: UDP programming - how to specify a read timeout using io$readvblk

From what I can tell of the documentation, there's no timeout available on the TCP/IP Services $qio IO$_READVBLK call.

 

As an alternative to the approach that Mr Gillings describes, you can also use $qio and ASTs and just leave the read hanging until something UDP happens, or until you're done with the networking.

 

It's entirely possible to issue these $qio reads in a self-requeuing loop, and where the AST passes the arriving packets off to the mainline code  via an in-memory interlocked queue and (for instance) a $wake call, and the mainline processes until its done, and then issues a $hiber. 

 

Put another way, it can be easier to use an aio-style asynchronous program on VMS, using ASTs and $hiber and $wake, rather than trying to mimic a synchronous sequence.  (Threads can also work here, but mixing threads and ASTs is tricky, and TCP/IP Services $qio calls will mean you're using ASTs for at least some of your processing.)

 

Traditional wrinkles: packet sizes, fragmentation, applications getting "stuck" if a UDP message gets lost, and UDP messages can get lost.

 

$hiber and $wake wrinkles: if you use $hiber and $wake here, issue a $schdwk call as a backstop, and that'll force the mainline to wake up (maybe every 10 seconds or so) and check the queue — this is ugly, but can avoid a deadlock.

gmala
Occasional Contributor

Re: UDP programming - how to specify a read timeout using io$readvblk

First of all thanks to you and Mr Gillings for your answer and suggestion.

Coming to my original question, it look like  it is possible to fill-in a socket-options descriptor like the following:

 

 sockopt_itemlist.length = sizeof(tmo_itemlist);
 sockopt_itemlist.type = TCPIP$C_SOCKOPT;
 sockopt_itemlist.address = &tmo_itemlist;

 

pointing to an itemlist like

 

tmo_itemlist.length = sizeof(tmo);
tmo_itemlist.type = TCPIP$C_RCVTIMEO;
tmo_itemlist.address = &tmo;

 

where tmo is a structure containing seconds/microseconds you want to wait (pieces of codes I found

somewhare in this same blog).

 

Then  I wonder if passing all this stuff to a call like the following, before calling the actual sys$qiow(IO$READVBLK), could do the trick.

 

status = sys$qiow(0, conn_channel, IO$_SETMODE, &iosb, 0, 0, 0, 0, &sockopt_itemlist, 0 );

 

Now, TCPIP$C_SOCKOPT should apply to both TCP and UDP sockets.

TCPIP$C_RCVTIMEO is described (in the TCPIP programming guide) as:

 

 

TCPIP$C_RCVTIMEO For HP use only . Sets the timeout value for a recv() operation. The argument is a pointer

to a timeval structure containing an integer value specified in second

(I'm a little bit worried about that "For HP use only").

 

 

 

Many thanks in advance for what you can elaborate on this.

 

Giovanni 

 

 

Hoff
Honored Contributor

Re: UDP programming - how to specify a read timeout using io$readvblk

Ask HP support directly.  

 

With HP, things here probably weren't going to change all that much, so you could test that and then reasonably assume whatever current behavior was observed would probably persist.  Now with VSI involved, it's anybody's guess what happens with the "reserved to..." stuff.

 

Or use the approaches that John and I have described, which are supported.

 

I've gotten burned by timeouts on more than a few occasions; races in the cancellation logic can be far too easy to create, and ugly to replicate.   I've found it's much simpler to be AST-based, and to leave the $qio outstanding, and to detect when I don't care about the read response anymore within the code of the completion AST (via an interlocked bitflag or such), and to save the $cancel for when I'm shutting down the channel or the application.

 

Ruslan R. Laishev
Super Advisor

Re: UDP programming - how to specify a read timeout using io$readvblk

Hi !

 

http://starlet.deltatel.ru/~laishev/aaa-vms/pmas_radius.c

 

 

		/*
		** Prepare to timeout processing
		*/
		if ( !(1 & (status = sys$setimr(EFN$C_ENF, &delta_tmo,timer_ast,&reqidt,0))) )
			break;

		/*
		** Wait for an answer to request from RADIUS server
		*/ 
		if ( !(1 & (status = sys$qiow (EFN$C_ENF,chan,IO$_READVBLK,&netiosb,0,0,
                                        &ibuf,sizeof(ibuf),&rem_host,0,0,0))) )
			break;

		/*
		** Check status, byte count, and remote IP address 
		*/
		if ( netiosb.iosb$w_bcnt && (netiosb.iosb$w_status & 1) &&
			(auth_ans->radpkt$b_id == auth_req->radpkt$b_id) &&
			sock_host.sin_addr.s_addr == ipaddr )
			break;
		}

	sys$cantim(&reqidt,0);

 

 

 

 

Jess Goodman
Esteemed Contributor

Re: UDP programming - how to specify a read timeout using io$readvblk

I like to work on VMS programs that use ASTs;  I really do.  AST-based code, when done correctly, is frequently more efficient and less prone to race-condition issues than any non-AST solution.

 

But I also recognize the fact that many users coming to VMS from other OSs may not be entirely comfortable using ASTs.  So just in case you would prefer a non-AST solution, I have attached a C  routine to this post routine as a .TXT file.

 

I wrote SYNCH_WITH_TIMEOUT.C back in 1993.   Originally we used it for programs that did data-transfers using the terminal driver.  Yes, I know that the VMS terminal driver has a built-in time-out function.   See comments about that below.

 

Since then I have used it for many other applications, on Alpha and IA64, and it has always worked reliably.

 

A call to the synchronous SYS$QIOW() system service is documented as being identical to a call to the aynchronouse SYS$QIO() service followed immediately by a call to the SYS$SYNCH() service.   My routine works just  like SYS$SYNCH() but it has two additonal arguments.  The I/O channel being used, and a F format floating point value for the timeout in units of  seconds.   (It would be easy to change the code to accept an integer value in .01 seconds units instead.)

 

 

I have one, but it's personal.
Craig A Berry
Honored Contributor

Re: UDP programming - how to specify a read timeout using io$readvblk

Looks nice, Jess, but note that on Itanium with default compiler options that timeout will be S_FLOAT, not F_FLOAT, which might not do what you intended when passed to LIB$CVTF_TO_INTERNAL_TIME