Connect messages

A connect message is issued by the client to perform an operation based on a pathname. This may be a message that establishes a longer term relationship between the client and the resource manager (e.g. open()), or it may be a message that is a "one-shot" event (e.g. rename()).

When you call resmgr_attach(), you pass it a pointer to a resmgr_connect_funcs_t structure that defines your connect functions. This structure is defined in <sys/resmgr.h> as follows:

typedef struct _resmgr_connect_funcs {

    unsigned nfuncs;

    int (*open)      (resmgr_context_t *ctp, io_open_t *msg,
                      RESMGR_HANDLE_T *handle, void *extra);

    int (*unlink)    (resmgr_context_t *ctp, io_unlink_t *msg,
                      RESMGR_HANDLE_T *handle, void *reserved);

    int (*rename)    (resmgr_context_t *ctp, io_rename_t *msg,
                      RESMGR_HANDLE_T *handle,
                      io_rename_extra_t *extra);

    int (*mknod)     (resmgr_context_t *ctp, io_mknod_t *msg,
                      RESMGR_HANDLE_T *handle, void *reserved);

    int (*readlink)  (resmgr_context_t *ctp, io_readlink_t *msg,
                      RESMGR_HANDLE_T *handle, void *reserved);

    int (*link)      (resmgr_context_t *ctp, io_link_t *msg,
                      RESMGR_HANDLE_T *handle,
                      io_link_extra_t *extra);

    int (*unblock)   (resmgr_context_t *ctp, io_pulse_t *msg,
                      RESMGR_HANDLE_T *handle, void *reserved);

    int (*mount)     (resmgr_context_t *ctp, io_mount_t *msg,
                      RESMGR_HANDLE_T *handle,
                      io_mount_extra_t *extra);
} resmgr_connect_funcs_t;

To initialize this structure, call iofunc_func_init() to fill it with pointers to the default handlers, and then override any that your resource manager needs to handle specifically.

Note: The resmgr_attach() function copies the pointers to the resmgr_connect_funcs_t and resmgr_io_funcs_t structures, not the structures themselves. You should allocate the structures, declare them to be static, or make them global variables. If your resource manager is for more than one device with different handlers, create separate structures that define the handlers.

The connect messages all have a type of _IO_CONNECT; the subtype further indicates what's happening. The entries are as follows:

nfuncs
The number of functions in the structure. This allows for future expansion.
open
Handles client calls to open(), fopen(), sopen(), and so on. The message subtype is _IO_CONNECT_COMBINE, _IO_CONNECT_COMBINE_CLOSE, or _IO_CONNECT_OPEN.

For more information about the io_open handler, see "Ways of adding functionality to the resource manager," later in this chapter.

unlink
Handles client calls to unlink(). The message subtype is _IO_CONNECT_UNLINK.
rename
Handles client calls to rename(). The message subtype is _IO_CONNECT_RENAME.
mknod
Handles client calls to mkdir(), mkfifo(), and mknod(). The message subtype is _IO_CONNECT_MKNOD.
readlink
Handles client calls to readlink(). The message subtype is _IO_CONNECT_READLINK.
link
Handles client calls to link(). The message subtype is _IO_CONNECT_LINK.
unblock
Handles requests from the kernel to unblock a client during the connect message phase. There's no corresponding message; the call is synthesized by the library.

For more information about the io_unblock handler, see "Handling client unblocking due to signals or timeouts" in the Signals, Timeouts, and Interrupts chapter.

mount
Handles client calls to mount(). The message subtype is _IO_CONNECT_MOUNT.

For more information about the io_mount handler, see "Handling mount()" in the Handling Other Messages chapter.

If the message is the _IO_CONNECT message (and variants) corresponding with the open() outcall, then a context needs to be established for further I/O messages that will be processed later. This context is referred to as an OCB (Open Control Block); it holds any information required between the connect message and subsequent I/O messages.

Basically, the OCB is a good place to keep information that needs to be stored on a per-open basis. An example of this would be the current position within a file. Each open file descriptor would have its own file position. The OCB is allocated on a per-open basis. During the open handling, you'd initialize the file position; during read and write handling, you'd advance the file position. For more information, see the section "The open control block (OCB) structure" in the POSIX-Layer Data Structures chapter of this guide.