For each supported PF_* protocol family (domain), there is a file /servers/socket/N where N is the numeric value for the PF_* symbol. libc's socket(), socketpair() and friends use _hurd_socket_server to open them: the latter computes the /servers/socket/N path, then opens it with __file_name_lookup, and returns the result. Since those paths are translated (see showtrans on /servers/socket/N), it's a port to a translator which is returned. Right now PF LOCAL (a.k.a. PF_UNIX or AF_UNIX) N=1, PF INET (a.k.a AF_INET) N=2 and PF INET6 (a.k.a AF_INET6) N=26 are supported.

In case of problems to find out which server is called rpctrace can be of use: search for the output dir_lookup ("servers/socket/N" ...)

User programs open those files, and use the socket_create RPC to make a new socket. With that socket, they can use the other socket_* RPCs and also the io_* RPCs. The socket_* RPCs are essentially clones of the Unix system calls in question.

The only exception is sockaddrs, which are implemented as ports instead of the opaque data arrays they are in the system calls. You manipulate sockaddr ports with the socket_create_address, socket_fabricate_address, and socket_whatis_address calls. The sockaddr port is then used in socket calls like socket_connect and socket_accept.

PF_INET sockaddr ports are manipulated with socket_create_address from the usual struct sockaddr_in. PF_LOCAL sockaddr ports are stored by S_IFSOCK filesystem nodes; you find the address associated with a node with ifsock_getsockaddr. The file system server will get a sockaddr to return with socket_fabricate_address.