How to get the actual sockaddr bound by Unix.(bind (INET_ADDR (inet_addr_any, 0)))
?
Or Lwt_io.establish_server
?
I want to let system to choose a unused port, and get the port number to tell the client to connect.
How to get the actual sockaddr bound by Unix.(bind (INET_ADDR (inet_addr_any, 0)))
?
Or Lwt_io.establish_server
?
I want to let system to choose a unused port, and get the port number to tell the client to connect.
Do you mean you want to use Unix.listen
?
If you bind
, you have to specify the port as far as I know.
Take a look at http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch04lev1sec4.html
I found it: Unix.getsockname
With Lwt_io.establish_server
, I believe you currently have to create your own socket, and pass it in with Lwt_io.establish_server ~fd:my_fd ...
. You can then call Unix.getsockname my_fd
.
Any chance you’ve got an example of that working @hackwaly?
I’ve found that if I setup a port and call Lwt_unix.getsockname
before it’s bound I’ll get port 0.
If you bind the port it’ll work but passing it to Lwt_io.establish_server_with_client_address
will result in an EINVAL
error when it tries to bind an already bound port.
This doesn’t work for me:
(* Create a new socket *)
let default_protocol = 0 in
let socket = Lwt_unix.socket PF_INET SOCK_STREAM default_protocol in
let _ = Lwt_unix.setsockopt socket SO_REUSEADDR true in
(* Create a socket address *)
let port = 0 in
let host = Unix.inet_addr_loopback in
let addr = Unix.ADDR_INET (host, port) in
(* Determine port *)
let sockaddr = Lwt_unix.getsockname socket in
let bound_port = match sockaddr with
| Unix.ADDR_INET (_, port) -> port
| Unix.ADDR_UNIX _ -> assert false; in
let%lwt _ = Lwt_io.eprintf "Port %d\n%!" bound_port in
(* > Port 0 *)
@seanpoulter, in the code you have included, you don’t ever call bind
, which is the function that associates an address with a socket. One way to see that this can’t work, is that there is no call, direct or indirect, to which both socket
and addr
are ever both passed. In fact, in the code you have included, addr
is an unused variable.
As for establish_server
and its variants, you shouldn’t call bind
yourself, but you should let establish_server
do that. The purpose of passing in a socket for establish_server
to use isn’t to call bind
on it yourself, but to have a reference to the server socket, so you can call getsockname
on it (or whatever you’d like to do), after establish_server
has initialized it.
The establish_server
interface is arguably confusing. Perhaps it would be better if there was a function
server_socket : Lwt_io.server -> Lwt_unix.file_descr
for getting the socket after initialization, which is natural to think about, because you only get access to an Lwt_io.server
after the socket initialization is complete, and bind
has already been called.
Thanks for the help again @antron ! I didn’t think to check for the bound port after calling establish_server
.
Here’s the snipped for context that’s starting a loopback server on any available port:
let establish_server f =
(* Create a new socket *)
let default_protocol = 0 in
let socket = Lwt_unix.socket PF_INET SOCK_STREAM default_protocol in
let _ = Lwt_unix.setsockopt socket SO_REUSEADDR true in
(* Create a socket address *)
let host = Unix.inet_addr_loopback in
let port = 0 in
let addr = Unix.ADDR_INET (host, port) in
(* Start server *)
let max_pending_requests = 0 in
let%lwt _ = Lwt_io.establish_server_with_client_address
~backlog:max_pending_requests ~fd:socket addr f in
(* Determine bound port *)
let sockaddr = Lwt_unix.getsockname socket in
let bound_port = match sockaddr with
| Unix.ADDR_INET (_, port) -> port
| Unix.ADDR_UNIX _ -> assert false; in
let%lwt _ = Lwt_io.eprintf "Port %d\n%!" bound_port; in
Lwt.return ()
It works!