[nanomsg] Re: How to bind on a random port?

  • From: Martin Sustrik <sustrik@xxxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Sun, 16 Nov 2014 17:58:18 +0100

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Jason,

I am not sure why your use case cannot be implemented using string
service names. Just generate an UUID, use it as a service name and you
are pretty much guaranteed that you won't clash with another application.

Martin

On 16/11/14 17:22, Jason E. Aten wrote:
> I suspect we may be simply thinking about solving different
> problems, but I'll try to outline my use case below.
> 
> Let's ignore the problems of using root-only ports (those below
> number 1024) for the moment, even though practically that does
> make depending on running a service on port 1 an impossibility in
> many situations. Also lets ignore strings versus ports, since that 
> is just a size-of-the-namespace issue, and less fundamental.
> Let's focus on dynamic vs static port allocation.
> 
> Static strings might work for servers (to use a phone analogy,
> where I'm a business and I want a listed number in the phone book),
> but static strings don't work for clients (exactly when I don't
> want to list my number, and in fact for security I may want an
> unknown-in-advance and/or unpredictable number).
> 
> Example: When a client socket connect()s, it cannot reuse a well
> known port on the client end. So the tcp stack allocates the client
> a random, unused port.
> 
> Whenever we have an analogous situation to that, then we'll need a 
> dynamic port, no?
> 
> * * *
> 
> Keeping that analogy in mind, I see a separate set of use cases
> where a dynamically allocated port is required.
> 
> My use case is that I have a simple job processing system with
> multiple worker processes on the same host.
> 
> Each worker wishes to open a port to receive a reply message meant 
> specifically for them. Since we wish to de-couple requests and the 
> replies to those requests, each worker must have its own listening
> port.
> 
> At their start, as workers request a job. As a part of that job
> request, say to a job-dispatching service, the worker tells the 
> dispatcher where to send the job, in the form of an IP:port pair.
> 
> In order to have multiple independent processes running on the
> same machine, and so replies go directly to the worker that
> requested that particular job, each worker must listen for replies
> on its own port.  Since they can't all share the same port, they
> need to allocate a currently unused port.  Really this is just like
> the socket connect() from the client example, perhaps generalized a
> bit.
> 
> * * *
> 
> Practically speaking, the re-try functionality of nanomsg is very 
> important. But failure to bind a port even once at startup time is
> an initialization error that retry cannot solve automagically for
> us.  We should distinguish and elevate a failure to bind a port the
> first time, so that applications using nanomsg can take appropriate
> remedial measures.
> 
> It's rather kludgy to have to determine a port outside of nanomsg
> at the moment, because it has a built in race condition (the gap in
> time between when I ask the kernel for a socket and then release it
> and tell nanomsg to take that port).  I suppose the other way
> things could work would just be to provide a way to tell nanomsg to
> use the socket that I've already allocated.
> 
> 
> Best regards, Jason
> 
> 
> 
> On Sun, Nov 16, 2014 at 6:17 AM, Martin Sustrik
> <sustrik@xxxxxxxxxx <mailto:sustrik@xxxxxxxxxx>> wrote:
> 
> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
> 
> On 16/11/14 05:45, Matt Howlett wrote:
>> It should be treated as a failure to connect. The implementation 
>> should try to re-connect assuming that the interface will become 
>> available eventually.
>> 
>> 
>> I think it would be very common for people to want an atomic way 
>> of checking if a port is free, binding to it if it is, and
>> moving on if it is not (I want this and I notice a number of
>> others here do too). I also think that in most scenarios where a
>> port is already in use, it's likely to stay that way for a time
>> period long enough that the application wanting to bind to it is
>> not going to find it useful to wait for it to become free (I'm
>> not an expert though and could be missing a common scenario where
>> this functionality is actually useful - examples?). So based on
>> that, I think the former behavior is the best, or should at least
>> be an option.
> 
> Ok, let me give you the big picture.
> 
> Long ago the authors of Internet protocol suite have decided to
> use 16-bit integer IDs to address different "services" on a host. I
> guess back then the decision must have seemed reasonable, but later
> on it became clear that the namespace is too small and the service
> often clash using the same ID (port).
> 
> In 1988 there was an attempt to solve the problem (at least for
> TCP) by defining a protocol that used arbitrary string as IDs
> instead of integers (TCPMUX, RFC 1078, TCP port 1) but it never got
> wide adoption.
> 
> If you think of it, using strings solves the problem fully. You
> can use fully qualified name as a service ID, it can contain the
> name of the vendor etc. In such world there's would be no service
> name clashes and thus no need for dynamically assigned service
> IDs.
> 
> Unfortunately, TCPMUX was ignored and instead everybody sticks to
> port numbers and hacks around the problem using dynamically
> assigned ports.
> 
> Yet, dynamically assigned IDs are a spectacularly bad solution:
> 
> 1. The dynamically assigned ID has to be somehow communicated to
> the peers in runtime. That adds whole new layer of complexity to
> the applications.
> 
> 2. Given that service IDs change as the services are restarted, 
> there's no way to define service-specific policies at network
> level (e.g. allocating 100MB/s of bandwidth for service X).
> 
> 3. The solution is prone to inconsistencies and race conditions,
> with different nodes having different ideas about what the ID of
> service X happens to be. You can think of it as a very simple
> distributed database which means you have to deal with CAP theorem:
> Either you can always determine the port number to use
> (Availability) or everybody can agree on the same number
> (Consistency) -- bet never both.
> 
> In context of nanomsg (which does automatics reconnecting) the
> problem becomes even more pronounced: Say you bind to a wi-fi
> interface, get port X assigned, then the interface goes away (you
> are out of range of the wi-fi), then becomes available once more.
> You can try to re-bind to the same port, but it may already be
> taken. You can ask for a new dynamically allocated port but then
> it's certainly going to be different from the old one. The change
> would have to be communicated back to the application. How?
> Callback? And even if so, what would application do in such case?
> Et c.
> 
> The bottom line is the we should rather than using dynamically 
> assigned ports we should rather using string-based service names.
> I was thinking of actually implementing TCPMUX, but the idea
> surfaced again yesterday when speaking of WebSocket transport and
> using WebSocket URLs basically as service names.
> 
> Well, that's more or less it. Sorry for the long rant but I hope
> it'll explain why things are done as they are and what is my
> preferred solution to the problem of service ID clashes.
> 
> Martin
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)

iQEcBAEBAgAGBQJUaNeqAAoJENTpVjxCNN9YlV4IAJ3Nh5qkn8s+59CbvUOPFvIK
ERS2f4H/5v2qGsxDntoSgYdjLzHSiw0ilVL6E5e6B+cZQWeDw3nqvxFqtKWNISF7
ypAVinWJOztTfmeocKPFKw2izrFwMh88epoAu3NDJN5PAwVEm2ay0LaOkaULJUeM
A1x+G9AShovHJ5zr0ixxmYQHrVnXD0fHUQuNv5I3cggumOrkg1l7AuGbIIfaJuQj
PDeecA7+KGAFlRLYCKsvAXRMek+gkBWIwsm0R0II/LUZrHDE+nTQX3mqR1QA7fdv
xWIX6QnyqWutcRNOpoF3BwDot1m2Zbtf5fwUFXhCmsQJFZrCmy1JS45IPJJ3flg=
=u6PR
-----END PGP SIGNATURE-----

Other related posts: