I would be interested, simply out of curiosity. I wouldn't want or expect you to post any identifying info about your site.
I'll be brief, to avoid making this post too much about Ada. I've had a very pleasant realization about how I should design the uTP package, several days ago.
To design my UDP package, I first wrote a package binding just the bare POSIX filth, so that I could separate concerns; Ada has standard functionality for interfacing with the C, COBOL, and FORTRAN languages. Once I had the lowest package, I built a much nicer package over it.
Ada has what are called private types, which are obvious, and limited types, which aren't. A limited type has no language-defined assignment or equality, which effectively gives to the programmer complete control over how the type is used. Copies can't be made unless an interface is specifically designed for such, and this means they can be tracked, alongside other things. These are designed to accomodate types that are like this by nature, such as the unit of active concurrent programming, the task; what does it mean to copy a task when the underlying system needs to do something special with it for it to run; clearly, it doesn't. However, any type can be made limited, and so this can be used to force one to treat a type like this, even when it's not truly necessary in implementation. My UDP resource type is limited, but it's just a C language integer underneath. It's also a controlled type.
Controlled types are a very special part of the language, and the gist is they allow the programmer to extend a special magic type that runs code at initialization, assignment if applicable, and termination. My better UDP package makes the resource type controlled because it becomes much more pleasant to use. I won't get into discriminated types, but I also prevent the programmer from so much as declaring an instance of the type without also giving the desired port at the same time; then, the initialization code handles the calls to allocate resources and reserve the port, or throws an error otherwise; I won't get into why throwing an error here is more convenient, either.
So, my first thought was to make the uTP package a state machine that just processes messages, and to let the programmer relay them to the UDP system and back, but it was unpleasant every time I thought about it. I realized I should make the uTP package pretend to be special like the UDP package, and treat it as its own separate thing. Making it independent of any particular UDP interface over just using mine is unnecessary. The really nice thing is thinking about the design of the uTP package made me realize some nice qualities a TCP package can have, once I get around to writing packages for that.
Every instance of a uTP resource can appear to be free-standing, but my code should slot it into some hidden structure at initialization for easy message routing from the UDP resource. When a uTP resource needs to be used, it can activate the machinery that will service any other resources, until it's satisfied. This touches on another issue.
POSIX has the concept of
blocking and
non-blocking sockets, but I don't want to deal with this for several reasons, one being the difficulty of interfacing with a C language environment without getting oneself dirty. If I use a
non-blocking socket, the relevant calls will still return a value of negative one to indicate an error, but then I must check the C language value
errno
to see what the particular error is, and I must know the numerical values of each error because they're implemented as text replacement; by the by,
errno
is a macro too, and even C language programmers don't tend to know how it's implemented. The reasonable options are writing C language functions and using them from Ada, or avoiding this shit entirely. By using the
blocking sockets, I can get away with treating all errors identically, after careful consideration of all applicable failure cases. After all, in a program using UDP, what else is there to do besides ignore the errors and try again, so long as I can reserve a resource at all? I can ensure my program won't hit any of the errors that exist just to placate the C language, such as invalid pointer or socket integer errors, leaving relatively few for my uses, all of which are conflatable here.
The issue with this is the program waits for a result when using a
blocking socket, which isn't necessarily desirable, but I should be able to use the concurrent features of the Ada language to largely avoid this. I can just dedicate a task entirely to handling the UDP, while independent tasks do other things. This works because an entire program may need one UDP resource. This doesn't work when every, say, TCP connection or similar resource would be involved.
Well, since I'll control everything about this uTP package, I can clearly give to it a subprogram that waits for any relevant uTP resource to become active, at least for reading, since I don't really care about waiting to send as much. That subprogram can return some private type that lets it use another subprogram to resolve it unambiguously into the real uTP resource. POSIX programmers may recognize I'm describing something similar to
poll
, but without the C language baggage. This made me realize I could have a TCP package that hides this utter nonsense far more effectively than I first figured feasible. I was expecting my TCP package, whenever I design it, to effectively eat the control structure of any program needing it, but that may be avoidable yet.
So, in closing, that's what I've been thinking about lately, and that's the amount of thought that goes into something like representing how to expose uTP functionality. I think I'll handle the Bencoding first, however.