unix_socks.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /**
  2. * \file unix_sockets.c
  3. *
  4. * \brief GIS Library - Unix sockets support functions.
  5. *
  6. * Routines related to using UNIX domain sockets for IPC mechanisms
  7. * (such as XDRIVER).<br>
  8. *
  9. * Historically GRASS has used FIFO for interprocess communications for
  10. * display functions. Unfortunately, FIFO's are not available on all
  11. * target platforms. An attempt has been made to use IPC message
  12. * passing, but the semantics are variable and it also isn't available
  13. * on all target platforms. UNIX sockets, or local or domain sockets,
  14. * are much more widely available and consistent.<br>
  15. *
  16. * <b>Note:</b> This implementation of UNIX sockets provides zero
  17. * security checking so should not be used from untrusted clients.<br>
  18. *
  19. * (C) 2001-2008 by the GRASS Development Team
  20. *
  21. * This program is free software under the GNU General Public License
  22. * (>=v2). Read the file COPYING that comes with GRASS for details.
  23. *
  24. * \author Eric G. Miller
  25. *
  26. * \date 1999-2008
  27. */
  28. #include <grass/config.h>
  29. #ifdef HAVE_SOCKET
  30. #include <stdio.h>
  31. #include <stddef.h>
  32. #include <stdlib.h>
  33. #include <errno.h>
  34. #include <string.h>
  35. #include <unistd.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #ifdef __MINGW32__
  39. #define USE_TCP
  40. #include <winsock2.h>
  41. #include <ws2tcpip.h>
  42. #define EADDRINUSE WSAEADDRINUSE
  43. #else
  44. #include <sys/socket.h>
  45. #include <sys/un.h>
  46. #include <netinet/in.h>
  47. #define INVALID_SOCKET (-1)
  48. #endif
  49. #include <grass/gis.h>
  50. #include <grass/version.h>
  51. #include <grass/glocale.h>
  52. /** For systems where the *_LOCAL (POSIX 1g) is not defined
  53. ** There's not really any difference between PF and AF in practice.
  54. **/
  55. static char *_get_make_sock_path(void);
  56. static void init_sockets(void)
  57. {
  58. #ifdef __MINGW32__
  59. static int ready;
  60. WSADATA wsadata;
  61. if (ready)
  62. return;
  63. ready = 1;
  64. WSAStartup(0x0001, &wsadata);
  65. #endif
  66. }
  67. /* ---------------------------------------------------------------------
  68. * _get_make_sock_path(), builds and tests the path for the socket
  69. * directory. Returns NULL on any failure, otherwise it returns the
  70. * directory path. The path will be like
  71. * "/tmp/grass7-$USER-$GIS_LOCK".
  72. * ($GIS_LOCK is set in lib/init/init.sh to PID)
  73. * ---------------------------------------------------------------------*/
  74. static char *_get_make_sock_path(void)
  75. {
  76. char *path, *user, *lock;
  77. const char *prefix = "/tmp/grass7";
  78. int len, status;
  79. struct stat theStat;
  80. user = G_whoami(); /* Don't G_free () return value ever! */
  81. if (user == NULL)
  82. return NULL;
  83. else if (user[0] == '?') { /* why's it do that? */
  84. return NULL;
  85. }
  86. if ((lock = getenv("GIS_LOCK")) == NULL)
  87. G_fatal_error(_("Unable to get GIS_LOCK enviroment variable value"));
  88. len = strlen(prefix) + strlen(user) + strlen(lock) + 3;
  89. path = G_malloc(len);
  90. sprintf(path, "%s-%s-%s", prefix, user, lock);
  91. if ((status = G_lstat(path, &theStat)) != 0) {
  92. status = G_mkdir(path);
  93. }
  94. else {
  95. if (!S_ISDIR(theStat.st_mode)) {
  96. status = -1; /* not a directory ?? */
  97. }
  98. else {
  99. status = chmod(path, S_IRWXU); /* fails if we don't own it */
  100. }
  101. }
  102. if (status) { /* something's wrong if non-zero */
  103. G_free(path);
  104. path = NULL;
  105. }
  106. return path;
  107. }
  108. #ifdef USE_TCP
  109. #define PROTO PF_INET
  110. typedef struct sockaddr_in sockaddr_t;
  111. static int set_port(const char *name, int port)
  112. {
  113. FILE *fp = fopen(name, "w");
  114. if (!fp)
  115. return -1;
  116. fprintf(fp, "%d\n", port);
  117. fclose(fp);
  118. return 0;
  119. }
  120. static int get_port(const char *name)
  121. {
  122. FILE *fp = fopen(name, "r");
  123. int port;
  124. if (!fp)
  125. return -1;
  126. if (fscanf(fp, "%d", &port) != 1)
  127. port = -1;
  128. fclose(fp);
  129. return port;
  130. }
  131. static int save_port(int sockfd, const char *name)
  132. {
  133. sockaddr_t addr;
  134. socklen_t size = sizeof(addr);
  135. if (getsockname(sockfd, (struct sockaddr *)&addr, &size) != 0)
  136. return -1;
  137. if (set_port(name, ntohs(addr.sin_port)) < 0)
  138. return -1;
  139. return 0;
  140. }
  141. static int make_address(sockaddr_t * addr, const char *name, int exists)
  142. {
  143. int port = exists ? get_port(name) : 0;
  144. if (port < 0)
  145. return -1;
  146. addr->sin_family = AF_INET;
  147. addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  148. addr->sin_port = htons((unsigned short)port);
  149. return 0;
  150. }
  151. #else
  152. #define PROTO PF_UNIX
  153. typedef struct sockaddr_un sockaddr_t;
  154. static int make_address(sockaddr_t * addr, const char *name, int exists)
  155. {
  156. addr->sun_family = AF_UNIX;
  157. /* The path to the unix socket must fit in sun_path[] */
  158. if (sizeof(addr->sun_path) < strlen(name) + 1)
  159. return -1;
  160. strncpy(addr->sun_path, name, sizeof(addr->sun_path) - 1);
  161. return 0;
  162. }
  163. #endif
  164. /**
  165. * \brief Builds full path for a UNIX socket.
  166. *
  167. * Caller should <i>G_free()</i> the return value when it is no longer
  168. * needed.
  169. *
  170. * \param[in] name
  171. * \return NULL on error
  172. * \return Pointer to string socket path on success
  173. */
  174. char *G_sock_get_fname(const char *name)
  175. {
  176. char *path, *dirpath;
  177. int len;
  178. if (name == NULL)
  179. return NULL;
  180. dirpath = _get_make_sock_path();
  181. if (dirpath == NULL)
  182. return NULL;
  183. len = strlen(dirpath) + strlen(name) + 2;
  184. path = G_malloc(len);
  185. sprintf(path, "%s/%s", dirpath, name);
  186. G_free(dirpath);
  187. return path;
  188. }
  189. /**
  190. * \brief Checks socket existence.
  191. *
  192. * \param[in] name
  193. * \return 1 if <b>name</b> exists
  194. * \return 0 if <b>name</b> does not exist
  195. */
  196. int G_sock_exists(const char *name)
  197. {
  198. struct stat theStat;
  199. if (name == NULL || stat(name, &theStat) != 0)
  200. return 0;
  201. #ifdef USE_TCP
  202. if (S_ISREG(theStat.st_mode))
  203. #else
  204. if (S_ISSOCK(theStat.st_mode))
  205. #endif
  206. return 1;
  207. else
  208. return 0;
  209. }
  210. /**
  211. * \brief Binds socket to file descriptor.
  212. *
  213. * Takes the full pathname for a UNIX socket and returns the file
  214. * descriptor to the socket after a successful call to <i>bind()</i>.
  215. *
  216. * \param[in] name
  217. * \return -1 and "errno" is set on error
  218. * \return file descriptor on success
  219. */
  220. int G_sock_bind(const char *name)
  221. {
  222. int sockfd;
  223. sockaddr_t addr;
  224. socklen_t size;
  225. if (name == NULL)
  226. return -1;
  227. init_sockets();
  228. /* Bind requires that the file does not exist. Force the caller
  229. * to make sure the socket is not in use. The only way to test,
  230. * is a call to connect().
  231. */
  232. if (G_sock_exists(name)) {
  233. errno = EADDRINUSE;
  234. return -1;
  235. }
  236. /* must always zero socket structure */
  237. memset(&addr, 0, sizeof(addr));
  238. size = sizeof(addr);
  239. if (make_address(&addr, name, 0) < 0)
  240. return -1;
  241. sockfd = socket(PROTO, SOCK_STREAM, 0);
  242. if (sockfd == INVALID_SOCKET)
  243. return -1;
  244. if (bind(sockfd, (const struct sockaddr *)&addr, size) != 0)
  245. return -1;
  246. #ifdef USE_TCP
  247. if (save_port(sockfd, name) < 0)
  248. return -1;
  249. #endif
  250. return sockfd;
  251. }
  252. /**
  253. * \brief Wrapper function to <i>listen()</i>.
  254. *
  255. * \param[in] sockfd
  256. * \param[in] queue_len
  257. * \return 0 on success
  258. * \return -1 and "errno" set on error
  259. */
  260. int G_sock_listen(int sockfd, unsigned int queue_len)
  261. {
  262. return listen(sockfd, queue_len);
  263. }
  264. /**
  265. * \brief Wrapper around <i>accept()</i>.
  266. *
  267. * <b>Note:</b> This call will usually block until a connection arrives.
  268. * <i>select()</i> can be used for a time out on the call.
  269. *
  270. * \param[in] sockfd
  271. * \return -1 and "errno" set on error
  272. * \return file descriptor on success
  273. */
  274. int G_sock_accept(int sockfd)
  275. {
  276. sockaddr_t addr;
  277. socklen_t len = sizeof(addr);
  278. return accept(sockfd, (struct sockaddr *)&addr, &len);
  279. }
  280. /**
  281. * \brief Tries to connect to the UNIX socket specified by <b>name</b>.
  282. *
  283. * \param[in] name
  284. * \return -1 and "errno" set on error
  285. * \return file descriptor on success
  286. */
  287. int G_sock_connect(const char *name)
  288. {
  289. int sockfd;
  290. sockaddr_t addr;
  291. init_sockets();
  292. if (!G_sock_exists(name))
  293. return -1;
  294. /* must always zero socket structure */
  295. memset(&addr, 0, sizeof(addr));
  296. if (make_address(&addr, name, 1) < 0)
  297. return -1;
  298. sockfd = socket(PROTO, SOCK_STREAM, 0);
  299. if (sockfd == INVALID_SOCKET)
  300. return -1;
  301. if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
  302. return -1;
  303. else
  304. return sockfd;
  305. }
  306. #endif