298 line
7.4 KiB

  1. /*
  2. * neercs console-based window manager
  3. * Copyright (c) 2006-2011 Sam Hocevar <sam@hocevar.net>
  4. * 2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
  5. * 2008-2010 Pascal Terjan <pterjan@linuxfr.org>
  6. * All Rights Reserved
  7. *
  8. * This program is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. #if defined HAVE_CONFIG_H
  15. # include "config.h"
  16. #endif
  17. #include <stdio.h> /* perror() */
  18. #include <stdlib.h> /* malloc(), free() */
  19. #include <unistd.h> /* unlink() */
  20. #include <fcntl.h> /* fcntl() */
  21. #include <string.h> /* memcpy() */
  22. #include <sys/select.h> /* select() */
  23. #include <sys/types.h> /* bind(), connect() */
  24. #include <sys/socket.h> /* bind(), connect() */
  25. #include <sys/stat.h> /* stat(), struct stat */
  26. #include <sys/un.h> /* AF_UNIX */
  27. #include <errno.h> /* AF_UNIX */
  28. #include <time.h> /* time */
  29. #include "mini-neercs.h"
  30. #include "mini-socket.h"
  31. #define SIZEOF_SUN_PATH (sizeof(((struct sockaddr_un *)NULL)->sun_path))
  32. #define offsetof(s, f) ((int)(intptr_t)((s *)NULL)->f)
  33. struct nrx_socket
  34. {
  35. #if 1
  36. /* Linux sockets */
  37. int fd;
  38. int server;
  39. int connected;
  40. char path[SIZEOF_SUN_PATH];
  41. #else
  42. # error No socket implementation
  43. #endif
  44. };
  45. #define QLEN 10
  46. int
  47. serv_listen(const char *name)
  48. {
  49. int fd, len, err, rval;
  50. struct sockaddr_un un;
  51. /* create a UNIX domain stream socket */
  52. if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  53. return(-1);
  54. unlink(name); /* in case it already exists */
  55. /* fill in socket address structure */
  56. memset(&un, 0, sizeof(un));
  57. un.sun_family = AF_UNIX;
  58. strcpy(un.sun_path, name);
  59. len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
  60. /* bind the name to the descriptor */
  61. if (bind(fd, (struct sockaddr *)&un, len) < 0) {
  62. rval = -2;
  63. goto errout;
  64. }
  65. if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */
  66. rval = -3;
  67. goto errout;
  68. }
  69. return(fd);
  70. errout:
  71. err = errno;
  72. close(fd);
  73. errno = err;
  74. return(rval);
  75. }
  76. #define STALE 30 /* client's name can't be older than this (sec) */
  77. /*
  78. * Wait for a client connection to arrive, and accept it.
  79. * We also obtain the client's user ID from the pathname
  80. * that it must bind before calling us.
  81. * Returns new fd if all OK, <0 on error
  82. */
  83. int
  84. serv_accept(int listenfd, uid_t *uidptr)
  85. {
  86. int clifd, len, err, rval;
  87. time_t staletime;
  88. struct sockaddr_un un;
  89. struct stat statbuf;
  90. len = sizeof(un);
  91. if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
  92. return(-1); /* often errno=EINTR, if signal caught */
  93. /* obtain the client's uid from its calling address */
  94. len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
  95. un.sun_path[len] = 0; /* null terminate */
  96. if (stat(un.sun_path, &statbuf) < 0) {
  97. rval = -2;
  98. goto errout;
  99. }
  100. #ifdef S_ISSOCK /* not defined for SVR4 */
  101. if (S_ISSOCK(statbuf.st_mode) == 0) {
  102. rval = -3; /* not a socket */
  103. goto errout;
  104. }
  105. #endif
  106. if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
  107. (statbuf.st_mode & S_IRWXU) != S_IRWXU) {
  108. rval = -4; /* is not rwx------ */
  109. goto errout;
  110. }
  111. staletime = time(NULL) - STALE;
  112. if (statbuf.st_atime < staletime ||
  113. statbuf.st_ctime < staletime ||
  114. statbuf.st_mtime < staletime) {
  115. rval = -5; /* i-node is too old */
  116. goto errout;
  117. }
  118. if (uidptr != NULL)
  119. *uidptr = statbuf.st_uid; /* return uid of caller */
  120. unlink(un.sun_path); /* we're done with pathname now */
  121. return(clifd);
  122. errout:
  123. err = errno;
  124. close(clifd);
  125. errno = err;
  126. return(rval);
  127. }
  128. #define CLI_PATH "/var/tmp/" /* +5 for pid = 14 chars */
  129. #define CLI_PERM S_IRWXU /* rwx for user only */
  130. /*
  131. * Create a client endpoint and connect to a server.
  132. * Returns fd if all OK, <0 on error.
  133. */
  134. int
  135. cli_conn(const char *name)
  136. {
  137. int fd, len, err, rval;
  138. struct sockaddr_un un;
  139. /* create a UNIX domain stream socket */
  140. if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
  141. return(-1);
  142. /* fill socket address structure with our address */
  143. memset(&un, 0, sizeof(un));
  144. un.sun_family = AF_UNIX;
  145. sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
  146. len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
  147. unlink(un.sun_path); /* in case it already exists */
  148. if (bind(fd, (struct sockaddr *)&un, len) < 0) {
  149. rval = -2;
  150. goto errout;
  151. }
  152. if (chmod(un.sun_path, CLI_PERM) < 0) {
  153. rval = -3;
  154. goto errout;
  155. }
  156. /* fill socket address structure with server's address */
  157. memset(&un, 0, sizeof(un));
  158. un.sun_family = AF_UNIX;
  159. strcpy(un.sun_path, name);
  160. len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
  161. if (connect(fd, (struct sockaddr *)&un, len) < 0) {
  162. rval = -4;
  163. goto errout;
  164. }
  165. return(fd);
  166. errout:
  167. err = errno;
  168. close(fd);
  169. errno = err;
  170. return(rval);
  171. }
  172. nrx_socket_t * socket_open(char const *path, int server)
  173. {
  174. nrx_socket_t * sock;
  175. struct sockaddr_un addr;
  176. int ret, fd;
  177. #if 0
  178. fd = socket(AF_UNIX, SOCK_STREAM, 0);
  179. //fd = socket(AF_UNIX, SOCK_DGRAM, 0);
  180. if (fd < 0)
  181. {
  182. perror("socket creation");
  183. return NULL;
  184. }
  185. memset(&addr, 0, sizeof(struct sockaddr_un));
  186. addr.sun_family = AF_UNIX;
  187. strncpy(addr.sun_path, path, SIZEOF_SUN_PATH - 1);
  188. if (server)
  189. {
  190. unlink(path);
  191. ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
  192. }
  193. else
  194. {
  195. ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
  196. }
  197. if (ret < 0)
  198. {
  199. perror(server ? "socket binding" : "socket connection");
  200. close(fd);
  201. return NULL;
  202. }
  203. fcntl(fd, F_SETFL, O_NONBLOCK);
  204. #endif
  205. if (server)
  206. fd = serv_listen(path);
  207. else
  208. fd = cli_conn(path);
  209. if (fd < 0) return NULL;
  210. sock = malloc(sizeof(*sock));
  211. sock->fd = fd;
  212. sock->server = server;
  213. sock->connected = 0;
  214. strncpy(sock->path, path, SIZEOF_SUN_PATH - 1);
  215. return sock;
  216. }
  217. int socket_select(nrx_socket_t *sock, int usecs)
  218. {
  219. fd_set rfds;
  220. struct timeval tv;
  221. int ret;
  222. FD_ZERO(&rfds);
  223. FD_SET(sock->fd, &rfds);
  224. tv.tv_sec = usecs / 1000000;
  225. tv.tv_usec = usecs % 1000000;
  226. ret = select(sock->fd + 1, &rfds, NULL, NULL, &tv);
  227. if (ret < 0)
  228. return -1;
  229. if (FD_ISSET(sock->fd, &rfds))
  230. return 1;
  231. return 0;
  232. }
  233. int socket_puts(nrx_socket_t *sock, char const *str)
  234. {
  235. int ret;
  236. fprintf(stderr, "pid %i sending %i bytes on %s: %s\n", getpid(), (int)strlen(str), sock->path, str);
  237. ret = write(sock->fd, str, strlen(str));
  238. return ret;
  239. }
  240. ssize_t socket_read(nrx_socket_t *sock, void *buf, size_t count)
  241. {
  242. int ret;
  243. ret = read(sock->fd, buf, count);
  244. if (ret >= 0) ((char *)buf)[ret] = 0;
  245. if (ret >= 0) fprintf(stderr, "pid %i recving %i bytes on %s: %s\n", getpid(), ret, sock->path, (char *)buf);
  246. return ret;
  247. }
  248. void socket_close(nrx_socket_t *sock)
  249. {
  250. close(sock->fd);
  251. if (sock->server)
  252. unlink(sock->path);
  253. free(sock);
  254. }