Hi Dan,

here is another of my 'notorious' long mails  ;-)


on Tue 20-06-2000 00:16 Dan Ackerman wrote:
>
>I haven't got anything done towards it, but I was thinking about
>the UDP problem earlier today.  What do you think about just modifying the
>udp_open call so that it will handle it?

That should work, at least as far as the client interface is concerned.
But the question is if that will do all that we want it to do.

There are some other complications 'inside' the protocol of course, as such
a connection should not 'lock' to the sender of the first incoming packet
like all present passive connections will do, and data of successive packets
should therefore not be combined into a stream.

This also implies that the only call valid for reading the data of such a
connection is CNget_NDB, as that is the only way to ensure that each packet
is handled separately.


>The default address for this is 0.0.0.0 , that is INADDR_ANY.

Also, INADDR_ANY is already used by UDP_open of normal passive connections,
that do 'lock' to the first sender.  This is really quite logical too, as
'ANY' is not really a plural form.  It is just an unspecific form.


>However this is actually an obsolete address.

But then it must be replaced by something else with _identical_ purpose.
Is that really the case ?  And if so what is that then ?


>We should probably go with 255.255.255.255 which is INADDR_BROADCAST.

Ok, that makes sense to me, as 'BROADCAST' does imply communication with
multiple partners.  But I am unsure of how this is used with 'sockets',
as I have not found any examples of that.

Hmmm...  I just checked some MiNT sources again, and as far as I can tell
they use INADDR_ANY for all UDP connections that allow calls from any
remote host, regardless of whether they expect only one or many calls.
If they want separate connections per remote they bind a new socket
to the calling remote and keep listening on the old socket.

They also have another definition, INADDR_NONE, with the same value as
INADDR_BROADCAST.  I have not seen these in use, but I think I understand
what they mean.  If you have contrary information please share it, as I
have no hard info on this at all. The following is just my own conclusion.

ANY and NONE both refer to what remotes the socket accepts packets from,
while BROADCAST refers to the sending behaviour.  Since they 'lock' a
socket to a specific remote by a separate API call, INADDR_ANY will work
both for normal (one remote per session) connections and for the ones that
receive continuously from multiple hosts.  This is in conflict with all old
STiK definitions, but I think I see a way to accomplish it, although the
old STiK methods must remain the default for compatibility reasons.

However, if we are ever going to get the full use of UDP, then I think
we must accept the fact that UDP is so different from TCP that always
using exactly the same connection model is not a realistic option.
It would limit us too much in comparison to socket-based stacks.


>The names in caps are just the common names I've seen for these.

Sure, but as they do represent current usage on the net, we too should try
to use them in compatible (or at least similar) ways.


>I was just thinking that going this route would more closely
>mimick BSD sockets and would not necessitate the programmer to issue
>another command to achieve their purpose.

I agree that this is a useful feature, though I have a different angle on
how we should implement it.

Also, AFAIK it is quite normal with socket models to issue extra commands
after a connection is established, so as to modify its operating mode, and
that is exactly what I propose that we introduce for STiK and STinG too.


>Think on it and give me your thoughts.

First, I think that INADDR_ANY should be used as UDP_open argument whenever
listening for some unspecified remotes, as I believe that INADDR_BROADCAST
has an entirely different meaning.

Second, I think that we should use a new UDP_info request bit to switch
the connection from normal STiK mode to 'socket_like' mode.

Also, it can be crucial that the receiving APP be able to know from which
remote host a specific packet came, but the NDB definition does not allow
us to retrieve the IP header of an NDB, as that was never needed before.
And yet we do not want to redefine that struct, or introduce any new such
struct, as that would only cause compatibility problems and confusion.


I think I have a solution that satisfies most of these needs and which
only requires the NDB creation code to be slightly modified, without
adding or redefining any element of the NDB struct as such.

Let's take a look at its definition again:

typedef struct ndb          /* Network Data Block.  For data delivery		*/
{   char    *ptr;           /* Pointer to base of block. (For KRfree();)	*/
    char    *ndata;         /* Pointer to next data to deliver				*/
    uint16  len;            /* Length of remaining data						*/
    struct  ndb *next;      /* Next NDB in chain or NULL					*/
}   NDB;


In current STinG implementations a newly created NDB has 'ptr' pointing to
the base of the UDP header, which is directly followed by the data block
to which 'next' is pointing. This means that we have an 8 byte 'hole' in
that KRmalloc block, which was used for a UDP header which will never be
used again after the transformation to NDB storage.

I'm not sure how STiK does it, but I assume that STiK too avoids wasting
time on moving the data to eliminate such 'header holes', so that this
space is available with STiK as well.

Given this, we can use those 8 bytes as we please, without storage loss,
and without altering any previously defined structure or struct element.
'ptr' still keeps its old meaning of pointing to the block base for KRfree,
and the only thing that has changed is that the data it points to now has
a defined meaning.  (For UDP that is, as TCP has no need of this stuff.)

As I am sure you have already realized, my suggestion is that we simply
store the remote IP address of the sender here, as well as the remote
UDP port, since those are the values that may vary between packets that
are received on an 'INADDR_ANY' socket.  The client can then easily check
the identity of the sender for each NDB received. 


Now, how about sending data on such a connection ?  It does not have a
well-defined remote host even after receiving data, so where is data to
be sent for UDP_send ?  Well, the client can check for the sender of a
packet as described above, but he has no good way of sending the replies.

In the socket model it is possible to use a single socket to send packets
to many receivers too, simply by modifying a structure element. At least
that is how it appears to me when reading their code.  For the STiK model
this would correspond to modifying the remote host IP while a connection
is in progress, which simply does not fit the current STiK model at all.
(Btw: as used in this mail, "STiK model" always means STinG too.)

Now we still need some method to specify a remote host for packets to be
sent, and since UDP_send only deals with pure data (not NDBs), we can't
use the same method for that.  Fortunately there are other ways to do it.

One such way is to define two new elements for UDPIB, and two new command
bits for UDP_info.  When UDP_info is called with any of those bits set in
the request element of UDPIB, then the corresponding entries for remote
host IP and remote UDP port will be stored in the connection structure,
for use as the next destination of UDP_send.

This naturally means we must add those elements to UDP connection struct
too, but as this struct is 'hidden' inside the kernel (STX for STinG),
that need never concern anyone else.  During a normal UDP_open we should
initialize these elements to match the remote address specified, and for
normal passive connections we should also reinitialize them when some
packet comes in (thus 'locking' the connection).

The effect is that the UDP connection structs now contain separate remote
host address entries for reception and sending, but as long as the new
UDP_info features are unused the addresses will always be the same.


Finally I suggest that we implement INADDR_BROADCAST==INADDR_NONE, for
use in UDP_open to create connections that only send data, but do not
accept any incomimg packets (I think that is what they are for).



Summary of capabilities:
------------------------
All UDP client usage following old STiK model remains completely unchanged.
A connection can receive from multiple remotes
A connection can send to multiple remotes
A connection can be set to 'send_only' mode


Summary of changes required:
----------------------------
3 new UDP_info request bits, and corresponding case clauses in the code
2 new UDPIB structure elements
2 new UDP connection structure elements, and code to init/reinit them
1 small modification of NDB creation code (for UDP only)

That's all, and it is not really much compared to the gains.
What do you think ?

-- 
-------------------------------------------------------------------------
Regards:  Ronald Andersson                  mailto:dlanor@ettnet.se
http://dlanor.atari.org/    ICQ:38857203    http://www.ettnet.se/~dlanor/
-------------------------------------------------------------------------
