Skip to content

Small shared library to use shared memory as a FILE* stream , with interprocess communication in mind

License

Notifications You must be signed in to change notification settings

kata198/shmfile

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shmfile

Small shared library to use shared memory as a FILE* , with interprocess communication in mind.

Basic Design

Overview

shmfile is desgined in an "owner/guest" format.

One process is the owner [FSHM_OWMER] of a shared mapping (given by a string name). It creates the mapping, and can destroy it.

Other processes then can map that same string name as guest [FSHM_GUEST].

The guest only needs to know the unique name that the owner picked to have access to the data.

Permissions

Permissions for who can map the same shm as FSHM_GUEST and what they can do with the shmfile are specified by the octal: "mode".

These follow the same rules as chmod.

For example, same user only and read-only would be 0400. Same user r/w, all other users r/o, 0644

You specify the mode when the owner creates the shmfile, which will later determine whomelse on the system may have access.

The permissions are specified by the FSHM_OWNER when creating the shmfile.

If fshm_open is used instead of fshm_guest_open to map an existing shmfile stream as FSHM_GUEST, the mode argument is ignored.

Usage

The fshm_open is the core function that returns a FILE* object, with a valid integer file descriptor [ fd ]. It is passed either FSHM_OWNER or FSHM_GUEST in the "flags" argument to define the operation.

The owner may also create an shmfile stream by using the helper function, fshm_create, and a guest may also map an existing shmfile stream by using the helper function, fshm_guest_open.

You can read/write the data using either the buffered I/O functions (like fread, fwrite, fseek) and flushing with fflush, OR

the unbuffered I/O functions (like read, write, lseek) by using the fd returned by fileno( fileObj ) where fileObj is the FILE* returned by one of the aforementioned functions.

The size is completely automatic, you do not need to allocate an underlying buffer -- any data written to it and flushed will expand the buffer automatically.

There is no built-in locking, so it's suggested if you are going to have multiple processes writing to the stream,

that you either use fixed-size sections for each process, or implement your own locking.

Public Functions

The following functions make up the public API of shmfile.

fshm_create - Create a new shmfile stream (convenience/helper function for fshm_open with fshm_flags as FSHM_OWNER)

FILE* fshm_create(const char *name, mode_t mode)

/**
 * fshm_create - Create a new shmfile (as FSHM_OWNER)
 *                 with a given mode.
 *
 *
 *  name - A unique name which corrosponds to this stream.
 *          Guests will use this name as a reference to map
 *           this shmfile stream.
 *
 *  mode - An octal representing the "mode" for guest mappings.
 *           Mode has same meaning as with chmod.
 *         This mode will be used to determine how FSHM_GUEST
 *           mappings will be able to access this stream.
 *
 *         See the 'fshm_open' function for more information
 *          on mode.
 *
 *
 *  RETURN VALUE - 
 *                 A pointer to a FILE structure which may be used
 *                  with standard io functions (e.x. fread, fprintf, fseek)
 *
 *                 On error, this function will return NULL and `errno' will be set
 *
 *  NOTES -
 *                 * This is the same as calling fshm_open(name, mode, FSHM_OWNER)
 *
 *                 * See fshm_open for more info
 */

fshm_guest_open - Opens an existing shmfile stream (convenience/helper function for fshm_open with fshm_flags as FSHM_GUEST)

FILE *fshm_guest_open(const char *name);

/**
 * fshm_guest_open - Maps an existing shmfile stream (as FSHM_GUEST)
 *                    using the given name for reference.
 *
 *
 *  name - The name associated with an already-created fshmfile stream
 *
 *
 *  RETURN VALUE -
 *                 A pointer to a FILE structure which may be used
 *                  with standard io functions (e.x. fread, fprintf, fseek)
 *
 *                 On error, this function will return NULL and `errno' will be set
 *
 *  NOTES -
 *                 * This is the same as calling fshm_open(name, 0, FSHM_GUEST)
 *
 *                 * See fshm_open for more info
 */

fshm_open - Opens a shmfile stream

FILE* fshm_open(const char *name, mode_t mode, int fshm_flags);

This is the "core" function, and can be used both to create a new shared memory stream or open an existing stream. The FILE pointer returned allows you to use all the other I/O systems that come standard with libc.

/**
 * fshm_open - Open a shared memory stream, either creating a new
 *   stream [FSHM_OWNER] or mapping an existing stream [FSHM_GUEST],
 *   and returning a FILE* object with an associated int fd.
 *   This will work with both FILE* and int filedes functions
 *    (e.x.  fwrite and write, fread and read, etc).
 *
 *  name - A unique name which corrosponds to this stream.
 *            If flags contain FSHM_OWNER, we attempt to create
 *             a stream using this name.
 *            Guests who wish to map this shmfile will provide
 *             this same name to reference which shmfile stream
 *             to map.
 *
 *  mode - An octal representing the "mode" for this file stream.
 *           Mode has same meaning as with chmod.
 *
 *         This mode will be used to determine how FSHM_GUEST
 *           mappings will be able to access this stream.
 *
 *         It will also define the permissions (read/write/execute) for the
 *           owner / group-member / other
 *         relations on mappings.
 *
 *
 *         This field only has meaning when creating the shmfile ( FSHM_OWNER ).
 *          For an FSHM_GUEST open of an existing shmfile stream, this can be
 *            set to 0. Any other value will be ignored when flags contains FSHM_GUEST.
 *
 *         Columns:
 *
 *          - First column from left is always 0 for now (no sticky/setguid bit meaning)
 *
 *          - Second column from left is permissions for owner (user who creates shmfile)
 *
 *          - Third column from the left is permissions for users who are a member of
 *            the group associated with this stream. 
 *            This could be primary group of creating user (FSHM_OWNER), or a different
 *            group (set by fshm_chgrp).
 *            
 *          - Fourth column from the left are permissions for any user which
 *            does NOT fall into any categories listed above
 *
 *         Values:
 *
 *          For each column, the number is derived by starting with 0
 *            and following these rules:
 *
 *           - Add 4 to allow FSHM_GUEST mapping and read for represented set
 *           - Add 2 to allow writing to the mapping
 *           - Add 1 to allow execution
 *
 *
 *  Examples - Some examples of various #mode[s] and their meaning
 *
 *        Allow current user only to map as guest, read/write:
 *           0600
 *
 *        Allow current user only to map as guest, read-only:
 *           0400
 *
 *        Allow current user to map as guest, read and write,
 *          allow a different user belonging to same primary group
 *          to map as guest read-only:
 *           0640
 *
 *        Allow anybody on system to map read/write:
 *           0777
 *
 *
 *
 *  fshm_flags - A list of flags OR'd together
 *
 *     FSHM_OWNER  - Specifies that this call will create the stream
 *                    specified by #name . When the owner closes the stream,
 *                    it will be destroyed.
 *
 *     FSHM_GUEST  - Specifies that this call will open an existing stream
 *                    specified by #name . An FSHM_OWNER must have created
 *                    this stream already, or the call will fail.
 *                    Closing the stream as a guest will not destroy the file.
 *
 *     FSHM_PERSIST - Do NOT remove this stream when the FSHM_OWNER closes it.
 *                     fshm_force_destroy must be used to destroy the stream
 *                     when this flag is provided.
 *
 *  Return:
 *
 *     A FILE* object on success, otherwise NULL and errno is set.
 *
 *  NOTES:
 *
 *     The idea here is to simply allow interprocess I/O that exists
 *      only in memory. One process creates the mapping ( FSHM_OWNER )
 *      and several other processes can inherit that mapping,
 *      and share data between them.
 *
 *     There is a real FD associated with this FILE (unlike, open_memstream, for example).
 *
 *     You may choose to use either the buffered variants ( like fwrite, fread),
 *       or the unbuffered variants (like write, read).
 *
 *     Keep in mind that if you use the buffered functions, you must call fflush to
 *       sync the changes.
 *
 *
 *     You can use this object anywhere a FILE* is allowed, or anywhere an fd is allowed
 *      by calling fileno(X) where X is the FILE* returned by this function.
 *
 */

fshm_chgrp - Change the group associated with an shmfile stream

int fshm_chgrp(FILE *fshm_file, gid_t group)

/**
 * fshm_chgrp - Change the group associated with an existing shmfile stream
 *
 *      You must be the the same user as the FSHM_OWNER of the given stream,
 *        or root in order to change the gid assigned to the shmfile.
 *
 *      The shmfile created by fshm_open is assigned the gid
 *        matching the primary group of the creating user.
 *
 *      The purpose is to allow guests in a different group access rights to
 *        this shmfile ( based on the group bits in the mode set with fshm_open ),
 *        but not just open up access for everybody ( using the "other" bits in mode ).
 *
 *      As non-root, you may change the group to any groups to which you are a member.
 *        This includes your primary gid as well as all supplementry groups to which you belong.
 *        As root, you may change the shmfile's group to any group existing on this system.
 *
 *
 *  fshm_file - A FILE* object as returned by fshm_open.
 *                 You must be the FSHM_OWNER of this shmfile to change permissions.
 *
 *
 *  group     - new gid to replace current group on this shmfile.
 *
 *                  If you are not root, this must be either your primary gid
 *                    or a group contained in your list of supplementry groups.
 *
 *
 *  RETURN VALUE -
 *                   0:  Success
 *                  -1:  Failure (and errno will be set)
 *
 *   See man 2 chown for possible error conditions and values of errno
 * 
 */

fshm_chmod - Change the mode (permissions) on this shmfile

int fshm_chmod(FILE *fshm_file, mode_t mode);

/**
 * fshm_chmod - Change the mode on a shmfile
 *
 *   fshm_file - A FILE* object representing an shmfile stream
 *
 *   mode - An octal of permissions. See "chmod" for meaning.
 *
 *  RETURN VALUE -
 *                   0:  Success
 *                  -1:  Failure (and errno will be set)
 *
 *   See man 2 chmod for possible error conditions and values of errno
 */ 

fshm_force_destroy - Forcibly destroys a stream, as a recovery tool.

Use this function if the FSHM_OWNER of a shmfile stream dies before calling fclose on the stream.

int fshm_force_destroy(const char *name);

/**
 * fshm_force_destroy - Forcibly destroy the shared memory region associated
 *                       with #name.
 *
 *   Normal operation does not require this, however, if a process opens
 *     a fshm stream as FSHM_OWNER, and does not close it before terminating,
 *     the stream will maintain stuck open without an owner.
 *
 *
 *    name - The name associated with this stream
 *
 *  NOTES - 
 *
 *   The owner should test for this, and forcibly destroy if required.
 *
 *   Like so:
 *
 *   FILE *fObj;
 *
 *   errno = 0;
 *   fObj = fshm_open("/example1", 0775, FSHM_OWNER);
 *
 *   if ( !fObj && errno == EEXIST )
 *   {
 *      fshm_force_destroy("/example1");
 *      fObj = fshm_open("/example1", 0775, FSHM_OWNER);
 *   }
 *
 *
 *  RETURN:
 *    0 on success, -1 on error.
 */

shmfile_get_version - Gets version info on libshmfile

void shmfile_get_version(unsigned char *major, unsigned char *minor, unsigned char *patchlevel, const char **extra);

/**
 * shmfile_get_version - Get the version info on this version of shmfile
 *
 *    Sets the value of *major, *minor, *patchlevel, and *extra to the numeric version numbers
 */

Defined Constants

FSHM_OWNER - Used as a flag with fshm_open to denote that the current process and user will create and own the shmfile stream.

FSHM_GUEST - Used as a flag with fshm_open to denote that we want to map an existing shmfile stream.

FSHM_PERSIST - Used as a flag with fshm_open to denote that we should not automatically destroy the stream when the FSHM_OWNER closes it. If the owner provides this flag then the stream must be explicitly destroyed by calling fshm_force_destroy

Examples

The source code contains the following examples/tests of libshmfile which can be used as references:

examples/owner ( from examples/owner.c ) is an example that creates a stream ( as FSHM_OWNER ), writes some data to it, and leaves it open for a period of time.

examples/guest ( from examples/guest.c ) is an example that connects to an existing stream ( as FSHM_GUEST ), reads data from it, and prints it to stdout.

These examples test using a struct as data which is given initial values by "owner", and is updated each time "guest" is run.

The examples show both buffered I/O (fwrite and fflush), as well as unbuffered I/O (read and write).

Optionally, the fshm_chgrp method will be used if you uncomment and set the SET_GID_MACRO at the top of examples/owner.c