in hilbert os, a "socket" is a two-way byte-wise communication construct. each
socket has two ends, which can be either open or closed. each process has a
number of handles to sockets. sockets can be created in one of two ways: either
creating a private socket or connecting to a socket listener.

private sockets:
  a private socket is created with the "create private socket" system call. the
  process creating the socket gets both ends of the socket.

socket listeners:
  a socket listener is created with the "create socket listener" system call.
  an id string is passed to that system call and remains associated with the
  listener throughout its lifetime. only one socket listener may have a given
  id at once. while a socket listener exists, the owner of the listener can
  call the "accept socket connection" system call, and any process can call the
  "connect to socket" system call with that id passed. each of these system
  calls blocks until the other occurs, at which point a socket is created with
  the two process as its endpoints, and then both system calls return. the
  listener remains alive after the socket is created, and can be used to create
  more sockets until stopped with the "stop socket listener" system call.

when a process is created, an end of a socket can be "gifted" to that process.
when that happens, the end remains open, and is now accessible by the giftee
and not by the gifter.

when either end of a socket is closed, the other end of the socket remains
valid, and can be read from until empty. when both ends of a socket are closed,
the socket disappears.
