GRASS Programmer's Manual  6.4.2(2012)
unix_socks.c
Go to the documentation of this file.
00001 
00030 #include <grass/config.h>
00031 
00032 #ifdef HAVE_SOCKET
00033 
00034 #include <stdio.h>
00035 #include <stddef.h>
00036 #include <stdlib.h>
00037 #include <errno.h>
00038 #include <string.h>
00039 #include <unistd.h>
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #ifdef __MINGW32__
00043 #define USE_TCP
00044 #include <winsock2.h>
00045 #include <ws2tcpip.h>
00046 #define EADDRINUSE WSAEADDRINUSE
00047 #else
00048 #include <sys/socket.h>
00049 #include <sys/un.h>
00050 #include <netinet/in.h>
00051 #define INVALID_SOCKET (-1)
00052 #endif
00053 
00054 #include <grass/gis.h>
00055 #include <grass/version.h>
00056 #include <grass/glocale.h>
00057 
00062 static char *_get_make_sock_path(void);
00063 
00064 static void init_sockets(void)
00065 {
00066 #ifdef __MINGW32__
00067     static int ready;
00068     WSADATA wsadata;
00069 
00070     if (ready)
00071         return;
00072 
00073     ready = 1;
00074 
00075     WSAStartup(0x0001, &wsadata);
00076 #endif
00077 }
00078 
00079 /* ---------------------------------------------------------------------
00080  * _get_make_sock_path(), builds and tests the path for the socket
00081  * directory.  Returns NULL on any failure, otherwise it returns the
00082  * directory path. The path will be like 
00083  * "/tmp/grass6-$USER-$GIS_LOCK".
00084  * ($GIS_LOCK is set in lib/init/init.sh to PID) 
00085  * ---------------------------------------------------------------------*/
00086 
00087 static char *_get_make_sock_path(void)
00088 {
00089     char *path, *user, *lock;
00090     const char *prefix = "/tmp/grass6";
00091     int len, status;
00092     struct stat theStat;
00093 
00094     user = G_whoami();          /* Don't G_free () return value ever! */
00095     if (user == NULL)
00096         return NULL;
00097     else if (user[0] == '?') {  /* why's it do that? */
00098         return NULL;
00099     }
00100 
00101     if ((lock = getenv("GIS_LOCK")) == NULL)
00102         G_fatal_error(_("Unable to get GIS_LOCK enviroment variable value"));
00103 
00104     len = strlen(prefix) + strlen(user) + strlen(lock) + 3;
00105     path = G_malloc(len);
00106 
00107     sprintf(path, "%s-%s-%s", prefix, user, lock);
00108 
00109     if ((status = G_lstat(path, &theStat)) != 0) {
00110         status = G_mkdir(path);
00111     }
00112     else {
00113         if (!S_ISDIR(theStat.st_mode)) {
00114             status = -1;        /* not a directory ?? */
00115         }
00116         else {
00117             status = chmod(path, S_IRWXU);      /* fails if we don't own it */
00118         }
00119     }
00120 
00121     if (status) {               /* something's wrong if non-zero */
00122         G_free(path);
00123         path = NULL;
00124     }
00125 
00126     return path;
00127 }
00128 
00129 #ifdef USE_TCP
00130 
00131 #define PROTO PF_INET
00132 typedef struct sockaddr_in sockaddr_t;
00133 
00134 static int set_port(const char *name, int port)
00135 {
00136     FILE *fp = fopen(name, "w");
00137 
00138     if (!fp)
00139         return -1;
00140 
00141     fprintf(fp, "%d\n", port);
00142 
00143     fclose(fp);
00144 
00145     return 0;
00146 }
00147 
00148 static int get_port(const char *name)
00149 {
00150     FILE *fp = fopen(name, "r");
00151     int port;
00152 
00153     if (!fp)
00154         return -1;
00155 
00156     if (fscanf(fp, "%d", &port) != 1)
00157         port = -1;
00158 
00159     fclose(fp);
00160 
00161     return port;
00162 }
00163 
00164 static int save_port(int sockfd, const char *name)
00165 {
00166     sockaddr_t addr;
00167     socklen_t size = sizeof(addr);
00168 
00169     if (getsockname(sockfd, (struct sockaddr *)&addr, &size) != 0)
00170         return -1;
00171 
00172     if (set_port(name, ntohs(addr.sin_port)) < 0)
00173         return -1;
00174 
00175     return 0;
00176 }
00177 
00178 static int make_address(sockaddr_t * addr, const char *name, int exists)
00179 {
00180     int port = exists ? get_port(name) : 0;
00181 
00182     if (port < 0)
00183         return -1;
00184 
00185     addr->sin_family = AF_INET;
00186     addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00187     addr->sin_port = htons((unsigned short)port);
00188 
00189     return 0;
00190 }
00191 
00192 #else
00193 
00194 #define PROTO PF_UNIX
00195 typedef struct sockaddr_un sockaddr_t;
00196 
00197 static int make_address(sockaddr_t * addr, const char *name, int exists)
00198 {
00199     addr->sun_family = AF_UNIX;
00200 
00201     /* The path to the unix socket must fit in sun_path[] */
00202     if (sizeof(addr->sun_path) < strlen(name) + 1)
00203         return -1;
00204 
00205     strncpy(addr->sun_path, name, sizeof(addr->sun_path) - 1);
00206 
00207     return 0;
00208 }
00209 
00210 #endif
00211 
00223 char *G_sock_get_fname(const char *name)
00224 {
00225     char *path, *dirpath;
00226     int len;
00227 
00228     if (name == NULL)
00229         return NULL;
00230 
00231     dirpath = _get_make_sock_path();
00232 
00233     if (dirpath == NULL)
00234         return NULL;
00235 
00236     len = strlen(dirpath) + strlen(name) + 2;
00237     path = G_malloc(len);
00238     sprintf(path, "%s/%s", dirpath, name);
00239     G_free(dirpath);
00240 
00241     return path;
00242 }
00243 
00244 
00253 int G_sock_exists(const char *name)
00254 {
00255     struct stat theStat;
00256 
00257     if (name == NULL || stat(name, &theStat) != 0)
00258         return 0;
00259 
00260 #ifdef USE_TCP
00261     if (S_ISREG(theStat.st_mode))
00262 #else
00263     if (S_ISSOCK(theStat.st_mode))
00264 #endif
00265         return 1;
00266     else
00267         return 0;
00268 }
00269 
00270 
00282 int G_sock_bind(const char *name)
00283 {
00284     int sockfd;
00285     sockaddr_t addr;
00286     socklen_t size;
00287 
00288     if (name == NULL)
00289         return -1;
00290 
00291     init_sockets();
00292 
00293     /* Bind requires that the file does not exist. Force the caller
00294      * to make sure the socket is not in use.  The only way to test,
00295      * is a call to connect().
00296      */
00297     if (G_sock_exists(name)) {
00298         errno = EADDRINUSE;
00299         return -1;
00300     }
00301 
00302     /* must always zero socket structure */
00303     memset(&addr, 0, sizeof(addr));
00304 
00305     size = sizeof(addr);
00306 
00307     if (make_address(&addr, name, 0) < 0)
00308         return -1;
00309 
00310     sockfd = socket(PROTO, SOCK_STREAM, 0);
00311     if (sockfd == INVALID_SOCKET)
00312         return -1;
00313 
00314     if (bind(sockfd, (const struct sockaddr *)&addr, size) != 0)
00315         return -1;
00316 
00317 #ifdef USE_TCP
00318     if (save_port(sockfd, name) < 0)
00319         return -1;
00320 #endif
00321 
00322     return sockfd;
00323 }
00324 
00334 int G_sock_listen(int sockfd, unsigned int queue_len)
00335 {
00336     return listen(sockfd, queue_len);
00337 }
00338 
00339 
00351 int G_sock_accept(int sockfd)
00352 {
00353     sockaddr_t addr;
00354     socklen_t len = sizeof(addr);
00355 
00356     return accept(sockfd, (struct sockaddr *)&addr, &len);
00357 }
00358 
00359 
00368 int G_sock_connect(const char *name)
00369 {
00370     int sockfd;
00371     sockaddr_t addr;
00372 
00373     init_sockets();
00374 
00375     if (!G_sock_exists(name))
00376         return -1;
00377 
00378     /* must always zero socket structure */
00379     memset(&addr, 0, sizeof(addr));
00380 
00381     if (make_address(&addr, name, 1) < 0)
00382         return -1;
00383 
00384     sockfd = socket(PROTO, SOCK_STREAM, 0);
00385     if (sockfd == INVALID_SOCKET)
00386         return -1;
00387 
00388     if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
00389         return -1;
00390     else
00391         return sockfd;
00392 }
00393 
00394 #endif
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines