[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: TIMW Issues in FTPAPI



Sender: Scott Klement <sk@xxxxxxxxxxxxxxxx>

Brian,

HTTPAPI performs it's network communications using a "driver" approach. This is similar to the way a video driver or printer driver works on your Windows PC. Depending on the sort of communications required, HTTPAPI selects a different driver, and that driver does the communications work.

At the moment the code to select a driver looks like this:

c                   select
c                   when      peCommType = 'http'
c                   eval      p_CommNew = %paddr('COMMTCP_NEW')
 /if defined(HAVE_SSLAPI)
c                   when      peCommType = 'https'
c                   eval      p_CommNew = %paddr('COMMSSL_NEW')
 /endif
c                   other
c                   callp     SetError( HTTP_NOCDRIV
c                                     : 'No comm driver to handle '
c                                     +  %trimr(peCommType)
c                                     +  ' protocool' )
c                   return    *NULL
c                   endsl

c                   eval      p_CommDriver = comm_new
c                   return    p_CommDriver

The p_CommDriver is a pointer a data structure. In that data structure are procedure pointers to every routine needed for HTTPAPI to do communication.

This data structure is populated by calling the CommTcp_New() or CommSSL_New() subprocedure. The comm_new() routine calls one or the other of these, depending on what the p_CommNew procedure pointer is set to. (and that's set by the select statement)

Consequently, if I ever wanted to add a different means of communication (other than SSL or TCP) I could add an additional WHEN to the select statement, and that's the only thing that would be needed to attach HTTPAPI to the new driver.

At some point, I could even give the caller the ability to provide the name/library of a service program, and it could dynamically load the service program and use it for communications. I haven't taken it quite that far yet, but it'd be relatively easy to do. Then anyone could write their own communication driver and just plug it in when needed without touching the code for HTTPAPI itself. These drivers could even be written by vendors and distributed as pre-compiled objects, just like Windows printer drivers are today.

ANYWAY...

If you look at the CommTcp_New() subprocedure you'll see that it allocates the memory for a new comm driver data structure, and (optionally) can allocate additional memory that it can use for it's own internal use. It then populates the procedure pointers to point to it's own internal routines for looking up a host, connecting, sending data, receiving data, etc.

There are prototypes in COMM_H that use these procedure pointers. So every time HTTPAPI calls a routine named COMM_something(), it'll call whichever routine the COMMTCPR4 service program designated in the CommTcp_New() routine. And, of course, if you called CommSSL_new() instead, the comm_xxxx routines would point to that service program instead.

If you look at the actual routines for connecting, reading, etc. HTTPAPI's routines are written to make sure that they never get "stuck forever".

With the default options, HTTPAPI uses the alarm() API to perform a timeout on the connect() attempt. If the SIGALRM signal arrives before the connect() is complete, then the connect() API will return EINTR to tell me that the signal was received. I then know that it wasn't able to connect within that period of time, so I close the socket and give up.

Once the connection is established, HTTPAPI switches the socket to non-blocking mode. This means that the send() and recv() APIs (in this case, anyway) will never wait for data to arrive on the socket. If there's no data to read from the socket at the moment HTTPAPI calls them, I'll get an error (EAGAIN). It won't wait for data.

To wait for data, I use the select() API. So if you look at the CommTcp_read() routine, you'll see that it tries to use recv(), but if a EAGAIN error occurs, it'll call the select() API to wait until there's data to read and then run recv() again. The advantage to this approach is that select() allows me to provide a timeout so that I never reach a point where I'm stuck "forever". Even if there's a timing problem and select() says that there's data, but an instant later when I call recv() that data is already gone, I won't get stuck because the socket is non-blocking.

FTPAPI does not use non-blocking sockets right now, so is prone to a timing error that would lock the socket up indefinitely.

HTTPAPI's driver routines use the same level of care for sending and they do for receiving.

So this is what needs to be done to FTPAPI:

a) Analysis of the code needs to be done to determine which routines would be required in a driver module. Are the routines that HTTPAPI provides the correct ones, or are there others that would be wanted for FTP?

b) A driver module type of structure needs to be put together for FTPAPI based on the above requirements. It should support TCP today, and we'll want to add SSL in the future.

c) The driver module should be written using non-blocking sockets and timing out, just as HTTPAPIs is. This means having parameters for timeout on each call to the driver, and upgrading HTTPAPI to pass that timeout to all of the driver routines.

d) Some coordination should be done with the folks who are interested in adding SSL support to FTPAPI, since this communication module backend will have a great impact on them.

e) You need to keep compatibility in mind. The changes you make should not affect existing users -- you should be able to upgrade from the current FTPAPI to your patched version without impacting existing users.

f) You need to keep release compatibilty in mind. At this point, we promise to support V4R2 (though I have absolutely no way to test a release that old), so you can't use newer programming constructs, even if it'd make your code simpler (this drives me nuts)

Does that answer all of your questions?

---
Scott Klement  http://www.scottklement.com



On Wed, 25 Jan 2006, Brian Eckenrod wrote:

In your previous note you mentioned looking at code in HTTPAPI, but I am
not sure what code exactly to look at.  Maybe a better approach is to say
something like:

"This is what needs changed" and then point me to the similar routine or
code snippet in HTTPAPI that could perhaps guide me.

I'm open to any approach really.  I'd just like to fix this and share the
solution when I get it figured out.


-----------------------------------------------------------------------
This is the FTPAPI mailing list.  To unsubsribe from the list send mail
to majordomo@xxxxxxxxxxxxx with the body: unsubscribe ftpapi mymailaddr
-----------------------------------------------------------------------