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
Nov 14, 2018
Nov 1, 2018
Jul 16, 2018
Nov 14, 2018
Jun 25, 2017
Nov 14, 2018
Nov 14, 2018
Nov 14, 2018
Nov 14, 2018

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