PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/daemon/sock-serv.c

https://gitlab.com/karllinden/mradio
C | 297 lines | 240 code | 34 blank | 23 comment | 47 complexity | 67b6499728d3c104229fea0a53573f6f MD5 | raw file
  1. /*
  2. * This file is part of mradio.
  3. *
  4. * Copyright (C) 2014-2016 Karl Linden <karl.j.linden@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301, USA.
  20. *
  21. */
  22. /* This must be set before any #includes. */
  23. #define MRADIO_LOG_DOMAIN MRADIO_LOG_DOMAIN_SERV
  24. #if HAVE_CONFIG_H
  25. # include <config.h>
  26. #endif /* HAVE_CONFIG_H */
  27. #include <errno.h>
  28. #include <stdbool.h>
  29. #include <stddef.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <sys/socket.h>
  34. #include <sys/stat.h>
  35. #include <sys/types.h>
  36. #include <sys/un.h>
  37. #include <unistd.h>
  38. #include <mradio/common.h>
  39. #include <mradio/info.h>
  40. #include <mradio/log.h>
  41. #include <mradio/mstr.h>
  42. #include <mradio/sock.h>
  43. #include <common/massert.h>
  44. #include "ml.h"
  45. #include "nonblock.h"
  46. #include "pipe-serv.h"
  47. #include "serv.h"
  48. #include "sock-serv.h"
  49. #define SOCK_SERV_LISTEN_BACKLOG 16
  50. typedef struct sock_serv_conn_s sock_serv_conn_t;
  51. typedef struct sock_serv_s sock_serv_t;
  52. struct sock_serv_conn_s
  53. {
  54. sock_serv_t * sockserv;
  55. serv_t * pipeserv;
  56. sock_serv_conn_t * prev;
  57. sock_serv_conn_t * next;
  58. };
  59. struct sock_serv_s {
  60. char * unix; /* path if type unix, NULL else */
  61. char * password; /* password or NULL */ /* mstr */
  62. int fd;
  63. int ml_fd;
  64. sock_serv_conn_t * conns; /* linked list of open connections */
  65. };
  66. static void
  67. sock_serv_connfd_close(int connfd)
  68. {
  69. if (shutdown(connfd, SHUT_RDWR)) {
  70. log_error_errno("could not shutdown connection");
  71. }
  72. if (close(connfd)) {
  73. log_error_errno("could not close connection");
  74. }
  75. return;
  76. }
  77. static void NONNULL
  78. sock_serv_conn_link(sock_serv_t * sockserv,
  79. sock_serv_conn_t * conn)
  80. {
  81. sock_serv_conn_t * next = sockserv->conns;
  82. conn->prev = NULL;
  83. conn->next = next;
  84. if (next != NULL)
  85. {
  86. next->prev = conn;
  87. }
  88. sockserv->conns = conn;
  89. return;
  90. }
  91. static void NONNULL
  92. sock_serv_conn_unlink(sock_serv_conn_t * conn)
  93. {
  94. sock_serv_t * sockserv = conn->sockserv;
  95. sock_serv_conn_t * prev = conn->prev;
  96. sock_serv_conn_t * next = conn->next;
  97. if (prev != NULL)
  98. {
  99. prev->next = next;
  100. }
  101. else
  102. {
  103. massert(sockserv->conns == conn);
  104. sockserv->conns = next;
  105. }
  106. if (next != NULL)
  107. {
  108. next->prev = prev;
  109. }
  110. return;
  111. }
  112. static void NONNULL
  113. sock_serv_conn_stop(serv_t * pipeserv)
  114. {
  115. sock_serv_conn_t * conn = pipe_serv_data(pipeserv);
  116. int connfd = pipe_serv_rdfd(pipeserv);
  117. sock_serv_conn_unlink(conn);
  118. sock_serv_connfd_close(connfd);
  119. return;
  120. }
  121. static unsigned NONNULL
  122. sock_serv_accept(int ml_fd)
  123. {
  124. sock_serv_t * sockserv = ml_fd_get_data(ml_fd);
  125. int connfd;
  126. serv_t * pipeserv;
  127. sock_serv_conn_t * conn;
  128. while ((connfd = accept(sockserv->fd, NULL, NULL)) < 0 &&
  129. (errno == ECONNABORTED || errno == EINTR))
  130. {
  131. /* empty */;
  132. }
  133. if (connfd < 0)
  134. {
  135. if (errno != EAGAIN && errno != EWOULDBLOCK)
  136. {
  137. log_error_errno("could not accept connection");
  138. }
  139. return 0;
  140. }
  141. pipeserv = pipe_serv_start(NULL, sockserv->password, connfd, connfd,
  142. sizeof(sock_serv_conn_t),
  143. &sock_serv_conn_stop,
  144. PIPE_SERV_STOP_ALL);
  145. if (pipeserv == NULL)
  146. {
  147. sock_serv_connfd_close(connfd);
  148. return 1;
  149. }
  150. /* Initialize connection structure. */
  151. conn = pipe_serv_data(pipeserv);
  152. conn->sockserv = sockserv;
  153. conn->pipeserv = pipeserv;
  154. sock_serv_conn_link(sockserv, conn);
  155. return 0;
  156. }
  157. serv_t * NONNULL
  158. sock_serv_start(const info_t * info)
  159. {
  160. sockinfo_t sockinfo;
  161. char * name = info_get_name(info); /* mstr */
  162. serv_t * serv = NULL;
  163. sock_serv_t * sockserv = NULL;
  164. bool bound = false;
  165. if (sockinfo_fill(&sockinfo, info))
  166. {
  167. goto error;
  168. }
  169. serv = serv_new(name, SERV_SOCK, sizeof(sock_serv_t));
  170. if (serv == NULL)
  171. {
  172. goto error;
  173. }
  174. mstr_unref(name);
  175. sockserv = serv_data(serv);
  176. sockserv->unix = NULL;
  177. sockserv->password = info_get_password(info);
  178. sockserv->fd = -1;
  179. sockserv->ml_fd = -1;
  180. sockserv->conns = NULL;
  181. if (sockinfo.sockaddr.addr.sa_family == AF_UNIX)
  182. {
  183. sockserv->unix = strdup(sockinfo.sockaddr.un.sun_path);
  184. if (sockserv->unix == NULL)
  185. {
  186. log_error_errno("could not allocate memory");
  187. goto error;
  188. }
  189. }
  190. sockserv->fd = socket(sockinfo.sockaddr.addr.sa_family, SOCK_STREAM,
  191. 0);
  192. if (sockserv->fd < 0) {
  193. log_fatal_errno("could not create socket");
  194. goto error;
  195. }
  196. if (nonblock(sockserv->fd)) {
  197. goto error;
  198. }
  199. if (bind(sockserv->fd, &sockinfo.sockaddr.addr, sockinfo.size)) {
  200. log_fatal_errno("could not bind socket");
  201. goto error;
  202. }
  203. bound = true;
  204. if (listen(sockserv->fd, SOCK_SERV_LISTEN_BACKLOG)) {
  205. log_fatal_errno("could not listen on control socket");
  206. goto error;
  207. }
  208. sockserv->ml_fd = ml_fd_new(sockserv->fd, sockserv);
  209. if (sockserv->ml_fd < 0) {
  210. log_fatal("could not create main loop file descriptor");
  211. goto error;
  212. }
  213. ml_fd_read_cb(sockserv->ml_fd, &sock_serv_accept);
  214. return serv;
  215. error:
  216. COLD;
  217. if (serv != NULL)
  218. {
  219. if (sockserv->ml_fd >= 0)
  220. {
  221. ml_fd_destroy(sockserv->ml_fd);
  222. }
  223. if (sockserv->fd >= 0 && close(sockserv->fd))
  224. {
  225. log_error_errno("could not close socket");
  226. }
  227. if (bound && sockserv->unix != NULL && unlink(sockserv->unix))
  228. {
  229. log_error_errno("could not unlink socket");
  230. }
  231. free(sockserv->unix);
  232. mstr_unref(sockserv->password);
  233. serv_destroy(serv);
  234. }
  235. return NULL;
  236. }
  237. void NONNULL
  238. sock_serv_stop(serv_t * serv)
  239. {
  240. sock_serv_t * sockserv;
  241. sock_serv_conn_t * conn;
  242. sockserv = serv_data(serv);
  243. while ((conn = sockserv->conns) != NULL)
  244. {
  245. pipe_serv_stop(conn->pipeserv);
  246. }
  247. ml_fd_destroy(sockserv->ml_fd);
  248. if (close(sockserv->fd))
  249. {
  250. log_error_errno("could not close socket");
  251. }
  252. if (sockserv->unix != NULL)
  253. {
  254. if (unlink(sockserv->unix))
  255. {
  256. log_error_errno("could not unlink socket");
  257. }
  258. free(sockserv->unix);
  259. }
  260. mstr_unref(sockserv->password);
  261. serv_destroy(serv);
  262. return;
  263. }