|
@@ -1,394 +0,0 @@
|
|
|
-
|
|
|
-/**
|
|
|
- * \file unix_sockets.c
|
|
|
- *
|
|
|
- * \brief GIS Library - Unix sockets support functions.
|
|
|
- *
|
|
|
- * Routines related to using UNIX domain sockets for IPC mechanisms
|
|
|
- * (such as XDRIVER).<br>
|
|
|
- *
|
|
|
- * Historically GRASS has used FIFO for interprocess communications for
|
|
|
- * display functions. Unfortunately, FIFO's are not available on all
|
|
|
- * target platforms. An attempt has been made to use IPC message
|
|
|
- * passing, but the semantics are variable and it also isn't available
|
|
|
- * on all target platforms. UNIX sockets, or local or domain sockets,
|
|
|
- * are much more widely available and consistent.<br>
|
|
|
- *
|
|
|
- * <b>Note:</b> This implementation of UNIX sockets provides zero
|
|
|
- * security checking so should not be used from untrusted clients.<br>
|
|
|
- *
|
|
|
- * (C) 2001-2008 by the GRASS Development Team
|
|
|
- *
|
|
|
- * This program is free software under the GNU General Public License
|
|
|
- * (>=v2). Read the file COPYING that comes with GRASS for details.
|
|
|
- *
|
|
|
- * \author Eric G. Miller
|
|
|
- *
|
|
|
- * \date 1999-2008
|
|
|
- */
|
|
|
-
|
|
|
-#include <grass/config.h>
|
|
|
-
|
|
|
-#ifdef HAVE_SOCKET
|
|
|
-
|
|
|
-#include <stdio.h>
|
|
|
-#include <stddef.h>
|
|
|
-#include <stdlib.h>
|
|
|
-#include <errno.h>
|
|
|
-#include <string.h>
|
|
|
-#include <unistd.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/stat.h>
|
|
|
-#ifdef __MINGW32__
|
|
|
-#define USE_TCP
|
|
|
-#include <winsock2.h>
|
|
|
-#include <ws2tcpip.h>
|
|
|
-#define EADDRINUSE WSAEADDRINUSE
|
|
|
-#else
|
|
|
-#include <sys/socket.h>
|
|
|
-#include <sys/un.h>
|
|
|
-#include <netinet/in.h>
|
|
|
-#define INVALID_SOCKET (-1)
|
|
|
-#endif
|
|
|
-
|
|
|
-#include <grass/gis.h>
|
|
|
-#include <grass/version.h>
|
|
|
-#include <grass/glocale.h>
|
|
|
-
|
|
|
-/** For systems where the *_LOCAL (POSIX 1g) is not defined
|
|
|
- ** There's not really any difference between PF and AF in practice.
|
|
|
- **/
|
|
|
-
|
|
|
-static char *_get_make_sock_path(void);
|
|
|
-
|
|
|
-static void init_sockets(void)
|
|
|
-{
|
|
|
-#ifdef __MINGW32__
|
|
|
- static int ready;
|
|
|
- WSADATA wsadata;
|
|
|
-
|
|
|
- if (ready)
|
|
|
- return;
|
|
|
-
|
|
|
- ready = 1;
|
|
|
-
|
|
|
- WSAStartup(0x0001, &wsadata);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-/* ---------------------------------------------------------------------
|
|
|
- * _get_make_sock_path(), builds and tests the path for the socket
|
|
|
- * directory. Returns NULL on any failure, otherwise it returns the
|
|
|
- * directory path. The path will be like
|
|
|
- * "/tmp/grass7-$USER-$GIS_LOCK".
|
|
|
- * ($GIS_LOCK is set in lib/init/init.sh to PID)
|
|
|
- * ---------------------------------------------------------------------*/
|
|
|
-
|
|
|
-static char *_get_make_sock_path(void)
|
|
|
-{
|
|
|
- char *path, *user, *lock;
|
|
|
- const char *prefix = "/tmp/grass7";
|
|
|
- int len, status;
|
|
|
- struct stat theStat;
|
|
|
-
|
|
|
- user = G_whoami(); /* Don't G_free () return value ever! */
|
|
|
- if (user == NULL)
|
|
|
- return NULL;
|
|
|
- else if (user[0] == '?') { /* why's it do that? */
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if ((lock = getenv("GIS_LOCK")) == NULL)
|
|
|
- G_fatal_error(_("Unable to get GIS_LOCK enviroment variable value"));
|
|
|
-
|
|
|
- len = strlen(prefix) + strlen(user) + strlen(lock) + 3;
|
|
|
- path = G_malloc(len);
|
|
|
-
|
|
|
- sprintf(path, "%s-%s-%s", prefix, user, lock);
|
|
|
-
|
|
|
- if ((status = G_lstat(path, &theStat)) != 0) {
|
|
|
- status = G_mkdir(path);
|
|
|
- }
|
|
|
- else {
|
|
|
- if (!S_ISDIR(theStat.st_mode)) {
|
|
|
- status = -1; /* not a directory ?? */
|
|
|
- }
|
|
|
- else {
|
|
|
- status = chmod(path, S_IRWXU); /* fails if we don't own it */
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (status) { /* something's wrong if non-zero */
|
|
|
- G_free(path);
|
|
|
- path = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- return path;
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef USE_TCP
|
|
|
-
|
|
|
-#define PROTO PF_INET
|
|
|
-typedef struct sockaddr_in sockaddr_t;
|
|
|
-
|
|
|
-static int set_port(const char *name, int port)
|
|
|
-{
|
|
|
- FILE *fp = fopen(name, "w");
|
|
|
-
|
|
|
- if (!fp)
|
|
|
- return -1;
|
|
|
-
|
|
|
- fprintf(fp, "%d\n", port);
|
|
|
-
|
|
|
- fclose(fp);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int get_port(const char *name)
|
|
|
-{
|
|
|
- FILE *fp = fopen(name, "r");
|
|
|
- int port;
|
|
|
-
|
|
|
- if (!fp)
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (fscanf(fp, "%d", &port) != 1)
|
|
|
- port = -1;
|
|
|
-
|
|
|
- fclose(fp);
|
|
|
-
|
|
|
- return port;
|
|
|
-}
|
|
|
-
|
|
|
-static int save_port(int sockfd, const char *name)
|
|
|
-{
|
|
|
- sockaddr_t addr;
|
|
|
- socklen_t size = sizeof(addr);
|
|
|
-
|
|
|
- if (getsockname(sockfd, (struct sockaddr *)&addr, &size) != 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (set_port(name, ntohs(addr.sin_port)) < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int make_address(sockaddr_t * addr, const char *name, int exists)
|
|
|
-{
|
|
|
- int port = exists ? get_port(name) : 0;
|
|
|
-
|
|
|
- if (port < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- addr->sin_family = AF_INET;
|
|
|
- addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
- addr->sin_port = htons((unsigned short)port);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-#else
|
|
|
-
|
|
|
-#define PROTO PF_UNIX
|
|
|
-typedef struct sockaddr_un sockaddr_t;
|
|
|
-
|
|
|
-static int make_address(sockaddr_t * addr, const char *name, int exists)
|
|
|
-{
|
|
|
- addr->sun_family = AF_UNIX;
|
|
|
-
|
|
|
- /* The path to the unix socket must fit in sun_path[] */
|
|
|
- if (sizeof(addr->sun_path) < strlen(name) + 1)
|
|
|
- return -1;
|
|
|
-
|
|
|
- strncpy(addr->sun_path, name, sizeof(addr->sun_path) - 1);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-#endif
|
|
|
-
|
|
|
-/**
|
|
|
- * \brief Builds full path for a UNIX socket.
|
|
|
- *
|
|
|
- * Caller should <i>G_free()</i> the return value when it is no longer
|
|
|
- * needed.
|
|
|
- *
|
|
|
- * \param[in] name
|
|
|
- * \return NULL on error
|
|
|
- * \return Pointer to string socket path on success
|
|
|
- */
|
|
|
-
|
|
|
-char *G_sock_get_fname(const char *name)
|
|
|
-{
|
|
|
- char *path, *dirpath;
|
|
|
- int len;
|
|
|
-
|
|
|
- if (name == NULL)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- dirpath = _get_make_sock_path();
|
|
|
-
|
|
|
- if (dirpath == NULL)
|
|
|
- return NULL;
|
|
|
-
|
|
|
- len = strlen(dirpath) + strlen(name) + 2;
|
|
|
- path = G_malloc(len);
|
|
|
- sprintf(path, "%s/%s", dirpath, name);
|
|
|
- G_free(dirpath);
|
|
|
-
|
|
|
- return path;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * \brief Checks socket existence.
|
|
|
- *
|
|
|
- * \param[in] name
|
|
|
- * \return 1 if <b>name</b> exists
|
|
|
- * \return 0 if <b>name</b> does not exist
|
|
|
- */
|
|
|
-
|
|
|
-int G_sock_exists(const char *name)
|
|
|
-{
|
|
|
- struct stat theStat;
|
|
|
-
|
|
|
- if (name == NULL || stat(name, &theStat) != 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
-#ifdef USE_TCP
|
|
|
- if (S_ISREG(theStat.st_mode))
|
|
|
-#else
|
|
|
- if (S_ISSOCK(theStat.st_mode))
|
|
|
-#endif
|
|
|
- return 1;
|
|
|
- else
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * \brief Binds socket to file descriptor.
|
|
|
- *
|
|
|
- * Takes the full pathname for a UNIX socket and returns the file
|
|
|
- * descriptor to the socket after a successful call to <i>bind()</i>.
|
|
|
- *
|
|
|
- * \param[in] name
|
|
|
- * \return -1 and "errno" is set on error
|
|
|
- * \return file descriptor on success
|
|
|
- */
|
|
|
-
|
|
|
-int G_sock_bind(const char *name)
|
|
|
-{
|
|
|
- int sockfd;
|
|
|
- sockaddr_t addr;
|
|
|
- socklen_t size;
|
|
|
-
|
|
|
- if (name == NULL)
|
|
|
- return -1;
|
|
|
-
|
|
|
- init_sockets();
|
|
|
-
|
|
|
- /* Bind requires that the file does not exist. Force the caller
|
|
|
- * to make sure the socket is not in use. The only way to test,
|
|
|
- * is a call to connect().
|
|
|
- */
|
|
|
- if (G_sock_exists(name)) {
|
|
|
- errno = EADDRINUSE;
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- /* must always zero socket structure */
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
|
-
|
|
|
- size = sizeof(addr);
|
|
|
-
|
|
|
- if (make_address(&addr, name, 0) < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- sockfd = socket(PROTO, SOCK_STREAM, 0);
|
|
|
- if (sockfd == INVALID_SOCKET)
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (bind(sockfd, (const struct sockaddr *)&addr, size) != 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
-#ifdef USE_TCP
|
|
|
- if (save_port(sockfd, name) < 0)
|
|
|
- return -1;
|
|
|
-#endif
|
|
|
-
|
|
|
- return sockfd;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * \brief Wrapper function to <i>listen()</i>.
|
|
|
- *
|
|
|
- * \param[in] sockfd
|
|
|
- * \param[in] queue_len
|
|
|
- * \return 0 on success
|
|
|
- * \return -1 and "errno" set on error
|
|
|
- */
|
|
|
-
|
|
|
-int G_sock_listen(int sockfd, unsigned int queue_len)
|
|
|
-{
|
|
|
- return listen(sockfd, queue_len);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * \brief Wrapper around <i>accept()</i>.
|
|
|
- *
|
|
|
- * <b>Note:</b> This call will usually block until a connection arrives.
|
|
|
- * <i>select()</i> can be used for a time out on the call.
|
|
|
- *
|
|
|
- * \param[in] sockfd
|
|
|
- * \return -1 and "errno" set on error
|
|
|
- * \return file descriptor on success
|
|
|
- */
|
|
|
-
|
|
|
-int G_sock_accept(int sockfd)
|
|
|
-{
|
|
|
- sockaddr_t addr;
|
|
|
- socklen_t len = sizeof(addr);
|
|
|
-
|
|
|
- return accept(sockfd, (struct sockaddr *)&addr, &len);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * \brief Tries to connect to the UNIX socket specified by <b>name</b>.
|
|
|
- *
|
|
|
- * \param[in] name
|
|
|
- * \return -1 and "errno" set on error
|
|
|
- * \return file descriptor on success
|
|
|
- */
|
|
|
-
|
|
|
-int G_sock_connect(const char *name)
|
|
|
-{
|
|
|
- int sockfd;
|
|
|
- sockaddr_t addr;
|
|
|
-
|
|
|
- init_sockets();
|
|
|
-
|
|
|
- if (!G_sock_exists(name))
|
|
|
- return -1;
|
|
|
-
|
|
|
- /* must always zero socket structure */
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
|
-
|
|
|
- if (make_address(&addr, name, 1) < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- sockfd = socket(PROTO, SOCK_STREAM, 0);
|
|
|
- if (sockfd == INVALID_SOCKET)
|
|
|
- return -1;
|
|
|
-
|
|
|
- if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
|
|
|
- return -1;
|
|
|
- else
|
|
|
- return sockfd;
|
|
|
-}
|
|
|
-
|
|
|
-#endif
|