unixsock_server.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * $Id$
  3. *
  4. * UNIX Domain Socket Server
  5. *
  6. * Copyright (C) 2001-2004 FhG Fokus
  7. * Copyright (C) 2005 iptelorg GmbH
  8. *
  9. * This file is part of ser, a free SIP server.
  10. *
  11. * ser is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version
  15. *
  16. * For a license to use the ser software under conditions
  17. * other than those described here, or to purchase support for this
  18. * software, please contact iptel.org by e-mail at the following addresses:
  19. * [email protected]
  20. *
  21. * ser is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  29. */
  30. /* History:
  31. * created by janakj
  32. * 2004-03-03 added tcp init code (andrei)
  33. * 2004-04-29 added chmod(sock_perm) & chown(sock_user,sock_group) (andrei)
  34. */
  35. #include <unistd.h>
  36. #include <errno.h>
  37. #include <string.h>
  38. #include <sys/types.h>
  39. #include <sys/socket.h>
  40. #include <sys/stat.h>
  41. #include <signal.h>
  42. #include <stdarg.h>
  43. #include <stdio.h>
  44. #include <time.h>
  45. #include <fcntl.h>
  46. #include "../../config.h"
  47. #include "../../ut.h"
  48. #include "../../globals.h"
  49. #include "../../trim.h"
  50. #include "../../pt.h"
  51. #include "../../sr_module.h"
  52. #include "../../mem/mem.h"
  53. #include "unixsock_server.h"
  54. #include "../../tsend.h"
  55. /* AF_LOCAL is not defined on solaris */
  56. #if !defined(AF_LOCAL)
  57. #define AF_LOCAL AF_UNIX
  58. #endif
  59. #if !defined(PF_LOCAL)
  60. #define PF_LOCAL PF_UNIX
  61. #endif
  62. /* solaris doesn't have SUN_LEN */
  63. #ifndef SUN_LEN
  64. #define SUN_LEN(sa) ( strlen((sa)->sun_path) + \
  65. (size_t)(((struct sockaddr_un*)0)->sun_path) )
  66. #endif
  67. #define UNIXSOCK_BUF_SIZE BUF_SIZE
  68. char* unixsock_name = 0;
  69. char* unixsock_user = 0;
  70. char* unixsock_mode = 0;
  71. char* unixsock_group = 0;
  72. unsigned int unixsock_children = 1;
  73. unsigned int unixsock_tx_timeout = 2000; /* Timeout for sending replies in milliseconds */
  74. static int rx_sock, tx_sock;
  75. static char reply_buf[UNIXSOCK_BUF_SIZE];
  76. static str reply_pos;
  77. static struct sockaddr_un reply_addr;
  78. static unsigned int reply_addr_len;
  79. static int parse_cmd(str* cmd, str* buffer)
  80. {
  81. return 1;
  82. }
  83. /*
  84. * Create and bind local socket
  85. */
  86. int init_unixsock_socket(void)
  87. {
  88. struct sockaddr_un addr;
  89. int len, flags;
  90. if (unixsock_name == 0) {
  91. DBG("No unix domain socket will be opened\n");
  92. return 1;
  93. }
  94. len = strlen(unixsock_name);
  95. if (len == 0) {
  96. DBG("Unix domain socket server disabled\n");
  97. return 1;
  98. } else if (len > 107) {
  99. ERR("Socket name too long\n");
  100. return -1;
  101. }
  102. DBG("Initializing Unix domain socket server @ %s\n",
  103. unixsock_name);
  104. if (unlink(unixsock_name) == -1) {
  105. if (errno != ENOENT) {
  106. ERR(L_ERR, "Error while unlinking "
  107. "old socket (%s): %s\n", unixsock_name, strerror(errno));
  108. return -1;
  109. }
  110. }
  111. rx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
  112. if (rx_sock == -1) {
  113. ERR("Cannot create listening socket: %s\n", strerror(errno));
  114. return -1;
  115. }
  116. memset(&addr, 0, sizeof(addr));
  117. addr.sun_family = PF_LOCAL;
  118. memcpy(addr.sun_path, unixsock_name, len);
  119. if (bind(rx_sock, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) {
  120. ERR("bind: %s\n", strerror(errno));
  121. goto err_rx;
  122. }
  123. /* try to change permissions */
  124. if (sock_mode){ /* sock_mode==0 doesn't make sense, nobody can read/write*/
  125. if (chmod(unixsock_name, sock_mode)<0){
  126. ERR("Failed to change the"
  127. " permissions for %s to %04o: %s[%d]\n",
  128. unixsock_name, sock_mode, strerror(errno), errno);
  129. goto err_rx;
  130. }
  131. }
  132. /* try to change the ownership */
  133. if ((sock_uid!=-1) || (sock_gid!=-1)){
  134. if (chown(unixsock_name, sock_uid, sock_gid)<0){
  135. ERR("Failed to change the"
  136. " owner/group for %s to %d.%d; %s[%d]\n",
  137. unixsock_name, sock_uid, sock_gid, strerror(errno), errno);
  138. goto err_rx;
  139. }
  140. }
  141. tx_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
  142. if (tx_sock == -1) {
  143. ERR("Cannot create sending socket:"
  144. " %s\n", strerror(errno));
  145. goto err_rx;
  146. }
  147. /* Turn non-blocking mode on */
  148. flags = fcntl(tx_sock, F_GETFL);
  149. if (flags == -1){
  150. ERR("fcntl failed: %s\n", strerror(errno));
  151. goto err_both;
  152. }
  153. if (fcntl(tx_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
  154. ERR("fcntl: set non-blocking failed: %s\n", strerror(errno));
  155. goto err_both;
  156. }
  157. return 1;
  158. err_both:
  159. close(tx_sock);
  160. err_rx:
  161. close(rx_sock);
  162. return -1;
  163. }
  164. static void unix_server_loop(void)
  165. {
  166. int ret;
  167. str cmd, buffer;
  168. static char buf[UNIXSOCK_BUF_SIZE];
  169. struct unixsock_cmd* c = NULL;
  170. while(1) {
  171. reply_addr_len = sizeof(reply_addr);
  172. ret = recvfrom(rx_sock, buf, UNIXSOCK_BUF_SIZE, 0,
  173. (struct sockaddr*)&reply_addr, &reply_addr_len);
  174. if (ret == -1) {
  175. ERR("recvfrom: (%d) %s\n", errno, strerror(errno));
  176. if ((errno == EINTR) ||
  177. (errno == EAGAIN) ||
  178. (errno == EWOULDBLOCK) ||
  179. (errno == ECONNREFUSED)) {
  180. DBG("Got %d (%s), going on\n", errno, strerror(errno));
  181. continue;
  182. }
  183. ERR("BUG: unexpected recvfrom error\n");
  184. continue;
  185. }
  186. buffer.s = buf;
  187. buffer.len = ret;
  188. unixsock_reply_reset();
  189. if (parse_cmd(&cmd, &buffer) < 0) {
  190. /* unixsock_reply_asciiz("400 First line malformed\n"); */
  191. unixsock_reply_send();
  192. continue;
  193. }
  194. buffer.s = cmd.s + cmd.len + 1;
  195. buffer.len -= cmd.len + 1 + 1;
  196. /* c = lookup_cmd(&cmd); */
  197. if (c == 0) {
  198. ERR("Could not find "
  199. "command '%.*s'\n", cmd.len, ZSW(cmd.s));
  200. /* unixsock_reply_printf("500 Command %.*s not found\n", cmd.len, ZSW(cmd.s)); */
  201. unixsock_reply_send();
  202. continue;
  203. }
  204. /* ret = c->f(&buffer); */
  205. if (ret < 0) {
  206. ERR("Command '%.*s' failed with "
  207. "return value %d\n", cmd.len, ZSW(cmd.s), ret);
  208. /* Note that we do not send reply here, the
  209. * function is supposed to do so, it knows the
  210. * reason of the failure better than us
  211. */
  212. }
  213. }
  214. }
  215. /*
  216. * Spawn listeners
  217. */
  218. int init_unixsock_children(void)
  219. {
  220. int i;
  221. pid_t pid;
  222. if (!unixsock_name || *unixsock_name == '\0') {
  223. return 1;
  224. }
  225. for(i = 0; i < unixsock_children; i++) {
  226. pid = fork_process(PROC_UNIXSOCK,"unix domain socket",1);
  227. if (pid < 0) {
  228. ERR("Unable to fork: %s\n", strerror(errno));
  229. close(rx_sock);
  230. close(tx_sock);
  231. return -1;
  232. } else if (pid == 0) { /* child */
  233. unix_server_loop(); /* Never returns */
  234. }
  235. /* Parent */
  236. }
  237. DBG("Unix domain socket server successfully initialized @ %s\n", unixsock_name);
  238. return 1;
  239. }
  240. /*
  241. * Clean up
  242. */
  243. void close_unixsock_server(void)
  244. {
  245. close(rx_sock);
  246. close(tx_sock);
  247. }
  248. /*
  249. * Send a reply
  250. */
  251. ssize_t unixsock_reply_send(void)
  252. {
  253. return tsend_dgram(tx_sock,
  254. reply_buf, reply_pos.s - reply_buf,
  255. (struct sockaddr*)&reply_addr, reply_addr_len,
  256. unixsock_tx_timeout);
  257. }
  258. /*
  259. * Send a reply
  260. */
  261. ssize_t unixsock_reply_sendto(struct sockaddr_un* to)
  262. {
  263. if (!to) {
  264. ERR("Invalid parameter value\n");
  265. return -1;
  266. }
  267. return tsend_dgram(tx_sock,
  268. reply_buf, reply_pos.s - reply_buf,
  269. (struct sockaddr*)to, SUN_LEN(to),
  270. unixsock_tx_timeout);
  271. }
  272. /*
  273. * Reset the reply buffer -- start to write
  274. * at the beginning
  275. */
  276. void unixsock_reply_reset(void)
  277. {
  278. reply_pos.s = reply_buf;
  279. reply_pos.len = UNIXSOCK_BUF_SIZE;
  280. }
  281. /*
  282. * Return the address of the sender
  283. */
  284. struct sockaddr_un* unixsock_sender_addr(void)
  285. {
  286. return &reply_addr;
  287. }