Hi,
I'm trying to pass a file descriptor from a python program to a nim program but I can't find a way to do it:
# the server is created like this:
# var server = newAsyncSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
# server.bindUnix("\0proxy")
# and the client socket is dispatched to a processClient function
proc processClient(client: AsyncSocket) {.async.} =
var buf: cstring
let n = client.recvmsg(addr buf, 4096)
but the compilation error is:
Error: attempting to call undeclared routine: 'recvmsg'
So I guess that recvmsg is not defined for async sockets, is this expected/not yet implemented ?
I tried to google for an example of message passing with a file descriptor through an async socket but I could not find one.
Is it possible to do such a thing in nim ?
Actually I didn't meant passing a string but it's my fault because I left a var buf: cstring which was just a test.
recvmsg and sendmsg allows to pass a structure which can be used to pass file descriptors.
So I'm not talking about simply passing a string through a socket here but passing file descriptors from a process to another. So recvLine won't help me here.
I'am not sure what you want to do but, is a file descriptor just an integer? The you could just send an integer.
If you want to send a struct/nim object, you can try:
await mysock.send(addr myobj, myobj.sizeof)
@mp035: While descriptors are local, they CAN be passed between processes as @AMIGrAve is trying to do. The details depend on the socket type, which must be an AF_LOCAL or AF_UNIX, IIRC; You can google "sending fd between processes" for answers; a random one I found with examples in C is http://poincare.matf.bg.ac.rs/~ivana/courses/ps/sistemi_knjige/pomocno/apue/APUE/0201433079/ch17lev1sec4.html ; {{man recvmsg}} describes it as well.
But I've only ever done this in straight C
Thanks for backing me up @cumulonimbus .
So yeah, you can transfer file descriptors between processes. Each process have his file descriptor table but the resource behind it can be shared to another process through an ipc socket.
Here's how you would pass a payload along with one or more file descriptors through an ipc socket in python:
...receiving it on the other side can be done with recvmsg: https://docs.python.org/3/library/socket.html#socket.socket.recvmsg
I'm still a nim newbie and I wouldn't even know where to start in order to implement recvmsg in async mode, that said I'm surprised no one encountered this issue before as it's a common practice when doing low level networking systems.
Maybe @dom96 have some experience with this ?
-
mp035
(orginal)
[2019-11-29T01:10:09+01:00]
view original
While descriptors are local, they CAN be passed between processes as @AMIGrAve is trying to do.
Thanks for setting me straight, looks like I'll never stop learning!
-
dom96
(orginal)
[2019-11-29T01:14:18+01:00]
view original
Maybe @dom96 have some experience with this ?
Never attempted to transfer FDs between processes, personally I would avoid it as I doubt it's well supported across different platforms, but I'm no expert on this particular aspect of how sockets/FDs behave when sent across processes.
You should however be able to use newAsyncSocket (this overload) to create an AsyncSocket out of an FD.
I'm curious what you're trying to achieve at a high level though, maybe there is another way that doesn't require FDs being sent across processes?
-
AMIGrAve
(orginal)
[2019-11-29T17:15:15+01:00]
view original
but we do have recvFrom, can you use that instead?
I will check that and keep posted
I'm curious what you're trying to achieve at a high level though, maybe there is another way that doesn't require FDs being sent across processes?
I've already built this containerized shared hosting platform in python which has been successfully running on production for 3 years and actually I was looking at nim in order to speed up one part of the platform which can bottleneck on high concurrency. In many cases I have to pass file descriptors from the "host" to some linux namespaced processes.
-
cumulonimbus
(orginal)
[2019-11-30T21:31:23+01:00]
view original
I'm curious what you're trying to achieve at a high level though, maybe there is another way that doesn't require FDs being sent across processes?
@AMIGrAve already answered, but I'd like to add: This is the most efficient way to do hand-off between processes if you can do, whether it is a listening socket or a connected one.
If all is symmetric, (e.g. multiprocess nginx), then you can have multiple processes listening on the same port; Another common way to deal with this is the old "accept-and-fork", which works very well for long lived connections where overall processing dominates the forking time -- but not with e.g. preforking or long-lived backends.
Unfortunately, the most common way to deal with it -- especially if the backend is itself a long-lived process -- is for the original accepting process to proxy to the actual backend. This is wasteful in cpu , memory, kernel resources, and also requires the proxying process to remain up and responsive (adding latency and reducing reliability). While this is a necessary evil if backends are on a different machine, it is a complete waste if all is running on the same machine - and with 32-64 core servers relatively common these days (especially with containers), it is often the case that you can use the more effiicient route.
The other way to avoid sending FDs is shared memory - which is just a bit less efficient than transferring the FD (basically, just another memory copy and almost uncontended synchronization), but still has the latency/reliability drawback, and is significantly more complicated to get right.
It's available on Linux and most Unix variants, but not on Windows AFAIK.