An sbuf_t manages per-client buffer space for socket i/o. It is implemented as a small state machine which has six (6) states, not including the hidden states of being in a read() or write() call. Transitions between the states are triggered in sockserv_run() by the library. There are only two operations done on the sbuf_t:
WARNING: Writing data into the buffer when the state is not SBUF_EMPTY will cause unpredictable results!
sockserv_run() essentially calls sbuf_state() in a loop, which makes the state machine run (and makes data go in or out of the socket.) sbuf_state() returns only when a stable or blocking state has been reached. The resulting state is always the return of sbuf_state(), and sockserv_run() uses this in a switch statement to decide what to do next.
While the socket may be able to handle communication in both directions at once, note that this state machine cannot. If there happens to be a partially received message in the buffer when the server wishes to send something out, the receiving message must first come in completely and then be processed, before anything can go out. In this sense, the communication channel is "half-duplex".
This is prototyped in sbuf.h and implemented in sbuf.c. The complete state model is shown in figure 12.