unix_socks.c

Go to the documentation of this file.
00001 /*
00002 ****************************************************************************
00003 *
00004 * LIBRARY:      unix_socks.c  -- Routines related to using UNIX domain 
00005 *               sockets for IPC mechanisms (such as XDRIVER).
00006 *
00007 * AUTHOR(S):    Eric G. Miller
00008 *
00009 * PURPOSE:      Historically GRASS has used FIFO for interprocess communic-
00010 *               ations for display functions.  Unfortunately, FIFO's are
00011 *               not available on all target platforms.  An attempt has been
00012 *               made to use IPC message passing, but the semantics are
00013 *               variable and it also isn't available on all target platforms.
00014 *               UNIX sockets, or local or domain sockets, are much more
00015 *               widely available and consistent.  NOTE: This implementation
00016 *               of UNIX sockets provides zero security checking so should
00017 *               not be used from untrusted clients.
00018 *
00019 * COPYRIGHT:    (C) 2000 by the GRASS Development Team
00020 *
00021 *               This program is free software under the GNU General Public
00022 *               License (>=v2). Read the file COPYING that comes with GRASS
00023 *               for details.
00024 *
00025 *****************************************************************************/
00026 
00027 #ifndef __MINGW32__
00028 
00029 #include <grass/gis.h>
00030 #include <grass/version.h>
00031 #include <stdio.h>
00032 #include <stddef.h>
00033 #include <stdlib.h>
00034 #include <errno.h>
00035 #include <string.h>
00036 #include <unistd.h>
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <sys/socket.h>
00040 #include <sys/un.h>
00041 
00045 #ifndef AF_LOCAL
00046 #define AF_LOCAL AF_UNIX
00047 #endif
00048 #ifndef PF_LOCAL
00049 #define PF_LOCAL PF_UNIX
00050 #endif
00051 
00052 
00053 /* ---------------------------------------------------------------------
00054  * _get_make_sock_path(), builds and tests the path for the socket
00055  * directory.  Returns NULL on any failure, otherwise it returns the
00056  * directory path. The path will be like 
00057  * "/tmp/grass6-$USER-$GIS_LOCK".
00058  * ($GIS_LOCK is set in lib/init/init.sh to PID) 
00059  * ---------------------------------------------------------------------*/
00060 static char *
00061 _get_make_sock_path (void)
00062 {
00063     char *path, *user, *lock;
00064     const char *prefix = "/tmp/grass6";
00065     int len, status;
00066     struct stat theStat;
00067     
00068     user = G_whoami(); /* Don't G_free () return value ever! */
00069     if (user == NULL)
00070         return NULL;
00071     else if (user[0] == '?') /* why's it do that? */
00072     {
00073         return NULL;
00074     }
00075 
00076     if ( (lock = getenv ( "GIS_LOCK" )) == NULL )
00077         G_fatal_error ("Cannot get GIS_LOCK enviroment variable value");
00078 
00079     len = strlen(prefix) + strlen(user) + strlen(GRASS_VERSION_MAJOR) + strlen(GRASS_VERSION_MINOR) + strlen(lock) + 3;
00080     path = G_malloc (len);
00081     
00082     sprintf (path, "%s-%s-%s", prefix, user, lock);
00083 
00084     if ((status = lstat (path, &theStat)) != 0)
00085     {
00086         status = mkdir (path, S_IRWXU);
00087     }
00088     else 
00089     {
00090         if (!S_ISDIR (theStat.st_mode))
00091         {
00092             status = -1;  /* not a directory ?? */
00093         }
00094         else
00095         {
00096             status = chmod (path, S_IRWXU); /* fails if we don't own it */
00097         }
00098     }
00099 
00100     if (status) /* something's wrong if non-zero */
00101     {
00102         G_free (path);
00103         path = NULL;
00104     }
00105 
00106     return path;
00107 }
00108 
00109         
00110  /* ----------------------------------------------------------------------
00111  * G_sock_get_fname(), builds the full path for a UNIX socket.  Caller 
00112  * should G_free () the return value when it is no longer needed.  Returns
00113  * NULL on failure.
00114  * ---------------------------------------------------------------------*/
00115 char *
00116 G_sock_get_fname (const char *name)
00117 {
00118     char *path, *dirpath;
00119     int len;
00120 
00121     if (name == NULL)
00122         return NULL;
00123     
00124     dirpath = _get_make_sock_path();
00125     
00126     if (dirpath == NULL)
00127         return NULL;
00128 
00129     len = strlen (dirpath) + strlen(name) + 2;
00130     path = G_malloc (len);
00131     sprintf (path, "%s/%s", dirpath, name);
00132     G_free (dirpath);
00133 
00134     return path;
00135 }
00136 
00137 
00138 /* -------------------------------------------------------------------
00139  * G_sock_exists(char *): Returns 1 if path is to a UNIX socket that
00140  * already exists, 0 otherwise.
00141  * -------------------------------------------------------------------*/
00142     
00143 int
00144 G_sock_exists (const char *name)
00145 {
00146     struct stat theStat;
00147 
00148     if (name == NULL || stat (name, &theStat) != 0)
00149         return 0;
00150 
00151     if (S_ISSOCK (theStat.st_mode))
00152         return 1;
00153     else
00154         return 0;
00155 }
00156 
00157 
00158 /* -----------------------------------------------------------------
00159  * G_sock_bind (char *): Takes the full pathname for a UNIX socket
00160  * and returns the file descriptor to the socket after a successful
00161  * call to bind().  On error, it returns -1.  Check "errno" if you
00162  * want to find out why this failed (clear it before the call).
00163  * ----------------------------------------------------------------*/
00164 
00165 int
00166 G_sock_bind (const char *name)
00167 {
00168     int    sockfd;
00169     size_t size;
00170     struct sockaddr_un addr;
00171 
00172     if (name == NULL)
00173         return -1;
00174 
00175     /* Bind requires that the file does not exist. Force the caller
00176      * to make sure the socket is not in use.  The only way to test,
00177      * is a call to connect().
00178      */
00179     if (G_sock_exists (name))
00180     {
00181         errno = EADDRINUSE;
00182         return -1;
00183     }
00184 
00185     /* must always zero socket structure */
00186     memset (&addr, 0, sizeof(addr));
00187 
00188     /* The path to the unix socket must fit in sun_path[] */
00189     if (sizeof (addr.sun_path) < strlen(name) + 1)
00190         return -1;
00191     
00192     strncpy (addr.sun_path, name, sizeof (addr.sun_path) - 1);
00193     
00194     addr.sun_family = AF_LOCAL;
00195 
00196     sockfd = socket (PF_LOCAL, SOCK_STREAM, 0);
00197 
00198     size = (offsetof (struct sockaddr_un, sun_path) 
00199             + strlen (addr.sun_path) + 1);
00200 
00201     if (bind (sockfd, (struct sockaddr *) &addr, size) != 0)
00202         return -1;
00203 
00204     return sockfd;
00205 }
00206 
00207 
00208 /* ---------------------------------------------------------------------
00209  * G_sock_listen(int, unsigned int): Wrapper around the listen() 
00210  * function.
00211  * --------------------------------------------------------------------*/
00212 
00213 int
00214 G_sock_listen (int sockfd, unsigned int queue_len)
00215 {
00216     return listen (sockfd, queue_len);
00217 }
00218 
00219 /* -----------------------------------------------------------------------
00220  * G_sock_accept (int sockfd):
00221  * Wrapper around the accept() function. No client info is returned, but
00222  * that's not generally useful for local sockets anyway.  Function returns
00223  * the file descriptor or an error code generated by accept().  Note,
00224  * this call will usually block until a connection arrives.  You can use
00225  * select() for a time out on the call.
00226  * ---------------------------------------------------------------------*/
00227 
00228 int
00229 G_sock_accept (int sockfd)
00230 {
00231     struct sockaddr_un addr;
00232     int len = sizeof(addr);
00233     return accept (sockfd, (struct sockaddr *) &addr, &len);
00234 }
00235  
00236 
00237 /* ----------------------------------------------------------------------
00238  * G_sock_connect (char *name):  Tries to connect to the unix socket
00239  * specified by "name".  Returns the file descriptor if successful, or
00240  * -1 if unsuccessful.  Global errno is set by connect() if return is -1
00241  * (though you should zero errno first, since this function doesn't set
00242  * it for a couple conditions).
00243  * --------------------------------------------------------------------*/
00244 
00245 int
00246 G_sock_connect (const char *name)
00247 {
00248     int    sockfd;
00249     struct sockaddr_un addr;
00250 
00251     if (!G_sock_exists (name))
00252         return -1;
00253 
00254     /* must always zero socket structure */
00255     memset (&addr, 0, sizeof(addr));
00256 
00257     /* The path to the unix socket must fit in sun_path[] */
00258     if (sizeof (addr.sun_path) < strlen(name) + 1)
00259         return -1;
00260     
00261     strncpy (addr.sun_path, name, sizeof (addr.sun_path) - 1);
00262     
00263     addr.sun_family = AF_LOCAL;
00264 
00265     sockfd = socket (PF_LOCAL, SOCK_STREAM, 0);
00266 
00267     if (connect (sockfd, (struct sockaddr *) &addr, sizeof (addr)) != 0)
00268         return -1;
00269     else
00270         return sockfd;
00271 }
00272 
00273 /* vim: set softtabstop=4 shiftwidth=4 expandtab : */
00274 
00275 int
00276 G_sock_socketpair(int family, int type, int protocol, int *fd)
00277 {
00278         int             n;
00279 
00280         if ( (n = socketpair(family, type, protocol, fd)) < 0)
00281                 return -1;
00282         else 
00283                 return 0;
00284 }
00285 
00286 #endif

Generated on Wed Dec 19 14:59:06 2007 for GRASS by  doxygen 1.5.4