Experimental IRC client, daemon and bot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2261 lines
61 KiB

  1. /*
  2. * zyklonb.c: the experimental IRC bot
  3. *
  4. * Copyright (c) 2014, Přemysl Janouch <p.janouch@gmail.com>
  5. * All rights reserved.
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  14. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  16. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  17. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. *
  19. */
  20. #include "config.h"
  21. #include "common.c"
  22. #include <arpa/inet.h>
  23. // --- Configuration (application-specific) ------------------------------------
  24. static struct config_item g_config_table[] =
  25. {
  26. { "nickname", "ZyklonB", "IRC nickname" },
  27. { "username", "bot", "IRC user name" },
  28. { "realname", "ZyklonB IRC bot", "IRC real name/e-mail" },
  29. { "irc_host", NULL, "Address of the IRC server" },
  30. { "irc_port", "6667", "Port of the IRC server" },
  31. { "ssl_use", "off", "Whether to use SSL" },
  32. { "ssl_cert", NULL, "Client SSL certificate (PEM)" },
  33. { "autojoin", NULL, "Channels to join on start" },
  34. { "reconnect", "on", "Whether to reconnect on error" },
  35. { "reconnect_delay", "5", "Time between reconnecting" },
  36. { "socks_host", NULL, "Address of a SOCKS 4a/5 proxy" },
  37. { "socks_port", "1080", "SOCKS port number" },
  38. { "socks_username", NULL, "SOCKS auth. username" },
  39. { "socks_password", NULL, "SOCKS auth. password" },
  40. { "prefix", ":", "The prefix for bot commands" },
  41. { "admin", NULL, "Host mask for administrators" },
  42. { "plugins", NULL, "The plugins to load on startup" },
  43. { "plugin_dir", PLUGIN_DIR, "Where to search for plugins" },
  44. { "recover", "on", "Whether to re-launch on crash" },
  45. { NULL, NULL, NULL }
  46. };
  47. // --- Application data --------------------------------------------------------
  48. struct plugin_data
  49. {
  50. LIST_HEADER (plugin_data)
  51. struct bot_context *ctx; ///< Parent context
  52. char *name; ///< Plugin identifier
  53. pid_t pid; ///< PID of the plugin process
  54. bool is_zombie; ///< Whether the child is a zombie
  55. bool initialized; ///< Ready to exchange IRC messages
  56. struct str queued_output; ///< Output queued up until initialized
  57. // Since we're doing non-blocking I/O, we need to queue up data so that
  58. // we don't stall on plugins unnecessarily.
  59. int read_fd; ///< The read end of the comm. pipe
  60. int write_fd; ///< The write end of the comm. pipe
  61. struct str read_buffer; ///< Unprocessed input
  62. struct str write_buffer; ///< Output yet to be sent out
  63. };
  64. static void
  65. plugin_data_init (struct plugin_data *self)
  66. {
  67. memset (self, 0, sizeof *self);
  68. self->pid = -1;
  69. str_init (&self->queued_output);
  70. self->read_fd = -1;
  71. str_init (&self->read_buffer);
  72. self->write_fd = -1;
  73. str_init (&self->write_buffer);
  74. }
  75. static void
  76. plugin_data_free (struct plugin_data *self)
  77. {
  78. soft_assert (self->pid == -1);
  79. free (self->name);
  80. str_free (&self->read_buffer);
  81. if (!soft_assert (self->read_fd == -1))
  82. xclose (self->read_fd);
  83. str_free (&self->write_buffer);
  84. if (!soft_assert (self->write_fd == -1))
  85. xclose (self->write_fd);
  86. if (!self->initialized)
  87. str_free (&self->queued_output);
  88. }
  89. struct bot_context
  90. {
  91. struct str_map config; ///< User configuration
  92. regex_t *admin_re; ///< Regex to match our administrator
  93. bool reconnect; ///< Whether to reconnect on conn. fail.
  94. unsigned long reconnect_delay; ///< Reconnect delay in seconds
  95. int irc_fd; ///< Socket FD of the server
  96. struct str read_buffer; ///< Input yet to be processed
  97. bool irc_ready; ///< Whether we may send messages now
  98. SSL_CTX *ssl_ctx; ///< SSL context
  99. SSL *ssl; ///< SSL connection
  100. struct plugin_data *plugins; ///< Linked list of plugins
  101. struct str_map plugins_by_name; ///< Indexes @em plugins by their name
  102. struct poller poller; ///< Manages polled descriptors
  103. bool quitting; ///< User requested quitting
  104. bool polling; ///< The event loop is running
  105. };
  106. static void
  107. bot_context_init (struct bot_context *self)
  108. {
  109. str_map_init (&self->config);
  110. self->config.free = free;
  111. load_config_defaults (&self->config, g_config_table);
  112. self->admin_re = NULL;
  113. self->irc_fd = -1;
  114. str_init (&self->read_buffer);
  115. self->irc_ready = false;
  116. self->ssl = NULL;
  117. self->ssl_ctx = NULL;
  118. self->plugins = NULL;
  119. str_map_init (&self->plugins_by_name);
  120. poller_init (&self->poller);
  121. self->quitting = false;
  122. self->polling = false;
  123. }
  124. static void
  125. bot_context_free (struct bot_context *self)
  126. {
  127. str_map_free (&self->config);
  128. if (self->admin_re)
  129. regex_free (self->admin_re);
  130. str_free (&self->read_buffer);
  131. // TODO: terminate the plugins properly before this is called
  132. struct plugin_data *link, *tmp;
  133. for (link = self->plugins; link; link = tmp)
  134. {
  135. tmp = link->next;
  136. plugin_data_free (link);
  137. free (link);
  138. }
  139. if (self->irc_fd != -1)
  140. xclose (self->irc_fd);
  141. if (self->ssl)
  142. SSL_free (self->ssl);
  143. if (self->ssl_ctx)
  144. SSL_CTX_free (self->ssl_ctx);
  145. str_map_free (&self->plugins_by_name);
  146. poller_free (&self->poller);
  147. }
  148. static void
  149. irc_shutdown (struct bot_context *ctx)
  150. {
  151. // TODO: set a timer after which we cut the connection?
  152. // Generally non-critical
  153. if (ctx->ssl)
  154. soft_assert (SSL_shutdown (ctx->ssl) != -1);
  155. else
  156. soft_assert (shutdown (ctx->irc_fd, SHUT_WR) == 0);
  157. }
  158. static void
  159. try_finish_quit (struct bot_context *ctx)
  160. {
  161. if (ctx->quitting && ctx->irc_fd == -1 && !ctx->plugins)
  162. ctx->polling = false;
  163. }
  164. static bool plugin_zombify (struct plugin_data *);
  165. static void
  166. initiate_quit (struct bot_context *ctx)
  167. {
  168. // Initiate bringing down of the two things that block our shutdown:
  169. // a/ the IRC socket, b/ our child processes:
  170. for (struct plugin_data *plugin = ctx->plugins;
  171. plugin; plugin = plugin->next)
  172. plugin_zombify (plugin);
  173. if (ctx->irc_fd != -1)
  174. irc_shutdown (ctx);
  175. ctx->quitting = true;
  176. try_finish_quit (ctx);
  177. }
  178. static bool irc_send (struct bot_context *ctx,
  179. const char *format, ...) ATTRIBUTE_PRINTF (2, 3);
  180. static bool
  181. irc_send (struct bot_context *ctx, const char *format, ...)
  182. {
  183. va_list ap;
  184. if (g_debug_mode)
  185. {
  186. fputs ("[IRC] <== \"", stderr);
  187. va_start (ap, format);
  188. vfprintf (stderr, format, ap);
  189. va_end (ap);
  190. fputs ("\"\n", stderr);
  191. }
  192. if (!soft_assert (ctx->irc_fd != -1))
  193. return false;
  194. va_start (ap, format);
  195. struct str str;
  196. str_init (&str);
  197. str_append_vprintf (&str, format, ap);
  198. str_append (&str, "\r\n");
  199. va_end (ap);
  200. bool result = true;
  201. if (ctx->ssl)
  202. {
  203. // TODO: call SSL_get_error() to detect if a clean shutdown has occured
  204. if (SSL_write (ctx->ssl, str.str, str.len) != (int) str.len)
  205. {
  206. print_debug ("%s: %s: %s", __func__, "SSL_write",
  207. ERR_error_string (ERR_get_error (), NULL));
  208. result = false;
  209. }
  210. }
  211. else if (write (ctx->irc_fd, str.str, str.len) != (ssize_t) str.len)
  212. {
  213. print_debug ("%s: %s: %s", __func__, "write", strerror (errno));
  214. result = false;
  215. }
  216. str_free (&str);
  217. return result;
  218. }
  219. static bool
  220. irc_initialize_ssl (struct bot_context *ctx, struct error **e)
  221. {
  222. const char *error_info = NULL;
  223. ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
  224. if (!ctx->ssl_ctx)
  225. goto error_ssl_1;
  226. // We don't care; some encryption is always better than no encryption
  227. SSL_CTX_set_verify (ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
  228. // XXX: maybe we should call SSL_CTX_set_options() for some workarounds
  229. ctx->ssl = SSL_new (ctx->ssl_ctx);
  230. if (!ctx->ssl)
  231. goto error_ssl_2;
  232. const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
  233. if (ssl_cert)
  234. {
  235. char *path = resolve_config_filename (ssl_cert);
  236. if (!path)
  237. print_error ("%s: %s", "cannot open file", ssl_cert);
  238. // XXX: perhaps we should read the file ourselves for better messages
  239. else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM)
  240. || !SSL_use_PrivateKey_file (ctx->ssl, path, SSL_FILETYPE_PEM))
  241. print_error ("%s: %s", "setting the SSL client certificate failed",
  242. ERR_error_string (ERR_get_error (), NULL));
  243. free (path);
  244. }
  245. SSL_set_connect_state (ctx->ssl);
  246. if (!SSL_set_fd (ctx->ssl, ctx->irc_fd))
  247. goto error_ssl_3;
  248. // Avoid SSL_write() returning SSL_ERROR_WANT_READ
  249. SSL_set_mode (ctx->ssl, SSL_MODE_AUTO_RETRY);
  250. switch (xssl_get_error (ctx->ssl, SSL_connect (ctx->ssl), &error_info))
  251. {
  252. case SSL_ERROR_NONE:
  253. return true;
  254. case SSL_ERROR_ZERO_RETURN:
  255. error_info = "server closed the connection";
  256. default:
  257. break;
  258. }
  259. error_ssl_3:
  260. SSL_free (ctx->ssl);
  261. ctx->ssl = NULL;
  262. error_ssl_2:
  263. SSL_CTX_free (ctx->ssl_ctx);
  264. ctx->ssl_ctx = NULL;
  265. error_ssl_1:
  266. // XXX: these error strings are really nasty; also there could be
  267. // multiple errors on the OpenSSL stack.
  268. if (!error_info)
  269. error_info = ERR_error_string (ERR_get_error (), NULL);
  270. error_set (e, "%s: %s", "could not initialize SSL", error_info);
  271. return false;
  272. }
  273. static bool
  274. irc_establish_connection (struct bot_context *ctx,
  275. const char *host, const char *port, struct error **e)
  276. {
  277. struct addrinfo gai_hints, *gai_result, *gai_iter;
  278. memset (&gai_hints, 0, sizeof gai_hints);
  279. // We definitely want TCP.
  280. gai_hints.ai_socktype = SOCK_STREAM;
  281. int err = getaddrinfo (host, port, &gai_hints, &gai_result);
  282. if (err)
  283. {
  284. error_set (e, "%s: %s: %s",
  285. "connection failed", "getaddrinfo", gai_strerror (err));
  286. return false;
  287. }
  288. int sockfd;
  289. for (gai_iter = gai_result; gai_iter; gai_iter = gai_iter->ai_next)
  290. {
  291. sockfd = socket (gai_iter->ai_family,
  292. gai_iter->ai_socktype, gai_iter->ai_protocol);
  293. if (sockfd == -1)
  294. continue;
  295. set_cloexec (sockfd);
  296. int yes = 1;
  297. soft_assert (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
  298. &yes, sizeof yes) != -1);
  299. const char *real_host = host;
  300. // Let's try to resolve the address back into a real hostname;
  301. // we don't really need this, so we can let it quietly fail
  302. char buf[NI_MAXHOST];
  303. err = getnameinfo (gai_iter->ai_addr, gai_iter->ai_addrlen,
  304. buf, sizeof buf, NULL, 0, 0);
  305. if (err)
  306. print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
  307. else
  308. real_host = buf;
  309. // XXX: we shouldn't mix these statuses with `struct error'; choose 1!
  310. char *address = format_host_port_pair (real_host, port);
  311. print_status ("connecting to %s...", address);
  312. free (address);
  313. if (!connect (sockfd, gai_iter->ai_addr, gai_iter->ai_addrlen))
  314. break;
  315. xclose (sockfd);
  316. }
  317. freeaddrinfo (gai_result);
  318. if (!gai_iter)
  319. {
  320. error_set (e, "connection failed");
  321. return false;
  322. }
  323. ctx->irc_fd = sockfd;
  324. return true;
  325. }
  326. // --- Signals -----------------------------------------------------------------
  327. static int g_signal_pipe[2]; ///< A pipe used to signal... signals
  328. static struct str_vector
  329. g_original_argv, ///< Original program arguments
  330. g_recovery_env; ///< Environment for re-exec recovery
  331. /// Program termination has been requested by a signal
  332. static volatile sig_atomic_t g_termination_requested;
  333. /// Points to startup reason location within `g_recovery_environment'
  334. static char **g_startup_reason_location;
  335. /// The environment variable used to pass the startup reason when re-executing
  336. static const char g_startup_reason_str[] = "STARTUP_REASON";
  337. static void
  338. sigchld_handler (int signum)
  339. {
  340. (void) signum;
  341. int original_errno = errno;
  342. // Just so that the read end of the pipe wakes up the poller.
  343. // NOTE: Linux has signalfd() and eventfd(), and the BSD's have kqueue.
  344. // All of them are better than this approach, although platform-specific.
  345. if (write (g_signal_pipe[1], "c", 1) == -1)
  346. soft_assert (errno == EAGAIN);
  347. errno = original_errno;
  348. }
  349. static void
  350. sigterm_handler (int signum)
  351. {
  352. (void) signum;
  353. g_termination_requested = true;
  354. int original_errno = errno;
  355. if (write (g_signal_pipe[1], "t", 1) == -1)
  356. soft_assert (errno == EAGAIN);
  357. errno = original_errno;
  358. }
  359. static void
  360. setup_signal_handlers (void)
  361. {
  362. if (pipe (g_signal_pipe) == -1)
  363. exit_fatal ("%s: %s", "pipe", strerror (errno));
  364. set_cloexec (g_signal_pipe[0]);
  365. set_cloexec (g_signal_pipe[1]);
  366. // So that the pipe cannot overflow; it would make write() block within
  367. // the signal handler, which is something we really don't want to happen.
  368. // The same holds true for read().
  369. set_blocking (g_signal_pipe[0], false);
  370. set_blocking (g_signal_pipe[1], false);
  371. struct sigaction sa;
  372. sa.sa_flags = SA_RESTART;
  373. sa.sa_handler = sigchld_handler;
  374. sigemptyset (&sa.sa_mask);
  375. if (sigaction (SIGCHLD, &sa, NULL) == -1)
  376. exit_fatal ("sigaction: %s", strerror (errno));
  377. signal (SIGPIPE, SIG_IGN);
  378. sa.sa_handler = sigterm_handler;
  379. if (sigaction (SIGINT, &sa, NULL) == -1
  380. || sigaction (SIGTERM, &sa, NULL) == -1)
  381. exit_fatal ("sigaction: %s", strerror (errno));
  382. }
  383. static void
  384. translate_signal_info (int no, const char **name, int code, const char **reason)
  385. {
  386. if (code == SI_USER) *reason = "signal sent by kill()";
  387. if (code == SI_QUEUE) *reason = "signal sent by sigqueue()";
  388. switch (no)
  389. {
  390. case SIGILL:
  391. *name = "SIGILL";
  392. if (code == ILL_ILLOPC) *reason = "illegal opcode";
  393. if (code == ILL_ILLOPN) *reason = "illegal operand";
  394. if (code == ILL_ILLADR) *reason = "illegal addressing mode";
  395. if (code == ILL_ILLTRP) *reason = "illegal trap";
  396. if (code == ILL_PRVOPC) *reason = "privileged opcode";
  397. if (code == ILL_PRVREG) *reason = "privileged register";
  398. if (code == ILL_COPROC) *reason = "coprocessor error";
  399. if (code == ILL_BADSTK) *reason = "internal stack error";
  400. break;
  401. case SIGFPE:
  402. *name = "SIGFPE";
  403. if (code == FPE_INTDIV) *reason = "integer divide by zero";
  404. if (code == FPE_INTOVF) *reason = "integer overflow";
  405. if (code == FPE_FLTDIV) *reason = "floating-point divide by zero";
  406. if (code == FPE_FLTOVF) *reason = "floating-point overflow";
  407. if (code == FPE_FLTUND) *reason = "floating-point underflow";
  408. if (code == FPE_FLTRES) *reason = "floating-point inexact result";
  409. if (code == FPE_FLTINV) *reason = "invalid floating-point operation";
  410. if (code == FPE_FLTSUB) *reason = "subscript out of range";
  411. break;
  412. case SIGSEGV:
  413. *name = "SIGSEGV";
  414. if (code == SEGV_MAPERR)
  415. *reason = "address not mapped to object";
  416. if (code == SEGV_ACCERR)
  417. *reason = "invalid permissions for mapped object";
  418. break;
  419. case SIGBUS:
  420. *name = "SIGBUS";
  421. if (code == BUS_ADRALN) *reason = "invalid address alignment";
  422. if (code == BUS_ADRERR) *reason = "nonexistent physical address";
  423. if (code == BUS_OBJERR) *reason = "object-specific hardware error";
  424. break;
  425. default:
  426. *name = NULL;
  427. }
  428. }
  429. static void
  430. recovery_handler (int signum, siginfo_t *info, void *context)
  431. {
  432. (void) context;
  433. // TODO: maybe try to force a core dump like this: if (fork() == 0) return;
  434. // TODO: maybe we could even send "\r\nQUIT :reason\r\n" to the server. >_>
  435. // As long as we're not connected via TLS, that is.
  436. const char *signal_name = NULL, *reason = NULL;
  437. translate_signal_info (signum, &signal_name, info->si_code, &reason);
  438. char buf[128], numbuf[8];
  439. if (!signal_name)
  440. {
  441. snprintf (numbuf, sizeof numbuf, "%d", signum);
  442. signal_name = numbuf;
  443. }
  444. if (reason)
  445. snprintf (buf, sizeof buf, "%s=%s: %s: %s", g_startup_reason_str,
  446. "signal received", signal_name, reason);
  447. else
  448. snprintf (buf, sizeof buf, "%s=%s: %s", g_startup_reason_str,
  449. "signal received", signal_name);
  450. *g_startup_reason_location = buf;
  451. // TODO: maybe pregenerate the path, see the following for some other ways
  452. // that would be illegal to do from within a signal handler:
  453. // http://stackoverflow.com/a/1024937
  454. // http://stackoverflow.com/q/799679
  455. // Especially if we change the current working directory in the program.
  456. //
  457. // Note that I can just overwrite g_orig_argv[0].
  458. // NOTE: our children will read EOF on the read ends of their pipes as a
  459. // a result of O_CLOEXEC. That should be enough to make them terminate.
  460. char **argv = g_original_argv.vector, **argp = g_recovery_env.vector;
  461. execve ("/proc/self/exe", argv, argp); // Linux
  462. execve ("/proc/curproc/file", argv, argp); // BSD
  463. execve ("/proc/curproc/exe", argv, argp); // BSD
  464. execve ("/proc/self/path/a.out", argv, argp); // Solaris
  465. execve (argv[0], argv, argp); // unreliable fallback
  466. // Let's just crash
  467. perror ("execve");
  468. signal (signum, SIG_DFL);
  469. raise (signum);
  470. }
  471. static void
  472. prepare_recovery_environment (void)
  473. {
  474. str_vector_init (&g_recovery_env);
  475. str_vector_add_vector (&g_recovery_env, environ);
  476. // Prepare a location within the environment where we will put the startup
  477. // (or maybe rather restart) reason in case of an irrecoverable error.
  478. char **iter;
  479. for (iter = g_recovery_env.vector; *iter; iter++)
  480. {
  481. const size_t len = sizeof g_startup_reason_str - 1;
  482. if (!strncmp (*iter, g_startup_reason_str, len) && (*iter)[len] == '=')
  483. break;
  484. }
  485. if (iter)
  486. g_startup_reason_location = iter;
  487. else
  488. {
  489. str_vector_add (&g_recovery_env, "");
  490. g_startup_reason_location =
  491. g_recovery_env.vector + g_recovery_env.len - 1;
  492. }
  493. }
  494. static void
  495. setup_recovery_handler (struct bot_context *ctx)
  496. {
  497. const char *recover_str = str_map_find (&ctx->config, "recover");
  498. hard_assert (recover_str != NULL); // We have a default value for this
  499. bool recover;
  500. if (!set_boolean_if_valid (&recover, recover_str))
  501. {
  502. print_error ("invalid configuration value for `%s'", "recover");
  503. exit (EXIT_FAILURE);
  504. }
  505. if (!recover)
  506. return;
  507. // Make sure these signals aren't blocked, otherwise we would be unable
  508. // to handle them, making the critical conditions fatal.
  509. sigset_t mask;
  510. sigemptyset (&mask);
  511. sigaddset (&mask, SIGSEGV);
  512. sigaddset (&mask, SIGBUS);
  513. sigaddset (&mask, SIGFPE);
  514. sigaddset (&mask, SIGILL);
  515. sigprocmask (SIG_UNBLOCK, &mask, NULL);
  516. struct sigaction sa;
  517. sa.sa_flags = SA_SIGINFO;
  518. sa.sa_sigaction = recovery_handler;
  519. sigemptyset (&sa.sa_mask);
  520. prepare_recovery_environment ();
  521. // TODO: also handle SIGABRT... or avoid doing abort() in the first place?
  522. if (sigaction (SIGSEGV, &sa, NULL) == -1
  523. || sigaction (SIGBUS, &sa, NULL) == -1
  524. || sigaction (SIGFPE, &sa, NULL) == -1
  525. || sigaction (SIGILL, &sa, NULL) == -1)
  526. print_error ("sigaction: %s", strerror (errno));
  527. }
  528. // --- SOCKS 5/4a (blocking implementation) ------------------------------------
  529. // These are awkward protocols. Note that the `username' is used differently
  530. // in SOCKS 4a and 5. In the former version, it is the username that you can
  531. // get ident'ed against. In the latter version, it forms a pair with the
  532. // password field and doesn't need to be an actual user on your machine.
  533. // TODO: make a non-blocking poller-based version of this; we need c-ares
  534. struct socks_addr
  535. {
  536. enum socks_addr_type
  537. {
  538. SOCKS_IPV4 = 1, ///< IPv4 address
  539. SOCKS_DOMAIN = 3, ///< Domain name to be resolved
  540. SOCKS_IPV6 = 4 ///< IPv6 address
  541. }
  542. type; ///< The type of this address
  543. union
  544. {
  545. uint8_t ipv4[4]; ///< IPv4 address, network octet order
  546. const char *domain; ///< Domain name
  547. uint8_t ipv6[16]; ///< IPv6 address, network octet order
  548. }
  549. data; ///< The address itself
  550. };
  551. struct socks_data
  552. {
  553. struct socks_addr address; ///< Target address
  554. uint16_t port; ///< Target port
  555. const char *username; ///< Authentication username
  556. const char *password; ///< Authentication password
  557. struct socks_addr bound_address; ///< Bound address at the server
  558. uint16_t bound_port; ///< Bound port at the server
  559. };
  560. static bool
  561. socks_get_socket (struct addrinfo *addresses, int *fd, struct error **e)
  562. {
  563. int sockfd;
  564. for (; addresses; addresses = addresses->ai_next)
  565. {
  566. sockfd = socket (addresses->ai_family,
  567. addresses->ai_socktype, addresses->ai_protocol);
  568. if (sockfd == -1)
  569. continue;
  570. set_cloexec (sockfd);
  571. int yes = 1;
  572. soft_assert (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE,
  573. &yes, sizeof yes) != -1);
  574. if (!connect (sockfd, addresses->ai_addr, addresses->ai_addrlen))
  575. break;
  576. xclose (sockfd);
  577. }
  578. if (!addresses)
  579. {
  580. error_set (e, "couldn't connect to the SOCKS server");
  581. return false;
  582. }
  583. *fd = sockfd;
  584. return true;
  585. }
  586. #define SOCKS_FAIL(...) \
  587. BLOCK_START \
  588. error_set (e, __VA_ARGS__); \
  589. goto fail; \
  590. BLOCK_END
  591. #define SOCKS_RECV(buf, len) \
  592. BLOCK_START \
  593. if ((n = recv (sockfd, (buf), (len), 0)) == -1) \
  594. SOCKS_FAIL ("%s: %s", "recv", strerror (errno)); \
  595. if (n != (len)) \
  596. SOCKS_FAIL ("%s: %s", "protocol error", "unexpected EOF"); \
  597. BLOCK_END
  598. static bool
  599. socks_4a_connect (struct addrinfo *addresses, struct socks_data *data,
  600. int *fd, struct error **e)
  601. {
  602. int sockfd;
  603. if (!socks_get_socket (addresses, &sockfd, e))
  604. return false;
  605. const void *dest_ipv4 = "\x00\x00\x00\x01";
  606. const char *dest_domain = NULL;
  607. char buf[INET6_ADDRSTRLEN];
  608. switch (data->address.type)
  609. {
  610. case SOCKS_IPV4:
  611. dest_ipv4 = data->address.data.ipv4;
  612. break;
  613. case SOCKS_IPV6:
  614. // About the best thing we can do, not sure if it works anywhere at all
  615. if (!inet_ntop (AF_INET6, &data->address.data.ipv6, buf, sizeof buf))
  616. SOCKS_FAIL ("%s: %s", "inet_ntop", strerror (errno));
  617. dest_domain = buf;
  618. break;
  619. case SOCKS_DOMAIN:
  620. dest_domain = data->address.data.domain;
  621. }
  622. struct str req;
  623. str_init (&req);
  624. str_append_c (&req, 4); // version
  625. str_append_c (&req, 1); // connect
  626. str_append_c (&req, data->port >> 8); // higher bits of port
  627. str_append_c (&req, data->port); // lower bits of port
  628. str_append_data (&req, dest_ipv4, 4); // destination address
  629. if (data->username)
  630. str_append (&req, data->username);
  631. str_append_c (&req, '\0');
  632. if (dest_domain)
  633. {
  634. str_append (&req, dest_domain);
  635. str_append_c (&req, '\0');
  636. }
  637. ssize_t n = send (sockfd, req.str, req.len, 0);
  638. str_free (&req);
  639. if (n == -1)
  640. SOCKS_FAIL ("%s: %s", "send", strerror (errno));
  641. uint8_t resp[8];
  642. SOCKS_RECV (resp, sizeof resp);
  643. if (resp[0] != 0)
  644. SOCKS_FAIL ("protocol error");
  645. switch (resp[1])
  646. {
  647. case 90:
  648. break;
  649. case 91:
  650. SOCKS_FAIL ("request rejected or failed");
  651. case 92:
  652. SOCKS_FAIL ("%s: %s", "request rejected",
  653. "SOCKS server cannot connect to identd on the client");
  654. case 93:
  655. SOCKS_FAIL ("%s: %s", "request rejected",
  656. "identd reports different user-id");
  657. default:
  658. SOCKS_FAIL ("protocol error");
  659. }
  660. *fd = sockfd;
  661. return true;
  662. fail:
  663. xclose (sockfd);
  664. return false;
  665. }
  666. #undef SOCKS_FAIL
  667. #define SOCKS_FAIL(...) \
  668. BLOCK_START \
  669. error_set (e, __VA_ARGS__); \
  670. return false; \
  671. BLOCK_END
  672. static bool
  673. socks_5_userpass_auth (int sockfd, struct socks_data *data, struct error **e)
  674. {
  675. size_t ulen = strlen (data->username);
  676. if (ulen > 255)
  677. ulen = 255;
  678. size_t plen = strlen (data->password);
  679. if (plen > 255)
  680. plen = 255;
  681. uint8_t req[3 + ulen + plen], *p = req;
  682. *p++ = 0x01; // version
  683. *p++ = ulen; // username length
  684. memcpy (p, data->username, ulen);
  685. p += ulen;
  686. *p++ = plen; // password length
  687. memcpy (p, data->password, plen);
  688. p += plen;
  689. ssize_t n = send (sockfd, req, p - req, 0);
  690. if (n == -1)
  691. SOCKS_FAIL ("%s: %s", "send", strerror (errno));
  692. uint8_t resp[2];
  693. SOCKS_RECV (resp, sizeof resp);
  694. if (resp[0] != 0x01)
  695. SOCKS_FAIL ("protocol error");
  696. if (resp[1] != 0x00)
  697. SOCKS_FAIL ("authentication failure");
  698. return true;
  699. }
  700. static bool
  701. socks_5_auth (int sockfd, struct socks_data *data, struct error **e)
  702. {
  703. bool can_auth = data->username && data->password;
  704. uint8_t hello[4];
  705. hello[0] = 0x05; // version
  706. hello[1] = 1 + can_auth; // number of authentication methods
  707. hello[2] = 0x00; // no authentication required
  708. hello[3] = 0x02; // username/password
  709. ssize_t n = send (sockfd, hello, 3 + can_auth, 0);
  710. if (n == -1)
  711. SOCKS_FAIL ("%s: %s", "send", strerror (errno));
  712. uint8_t resp[2];
  713. SOCKS_RECV (resp, sizeof resp);
  714. if (resp[0] != 0x05)
  715. SOCKS_FAIL ("protocol error");
  716. switch (resp[1])
  717. {
  718. case 0x02:
  719. if (!can_auth)
  720. SOCKS_FAIL ("protocol error");
  721. if (!socks_5_userpass_auth (sockfd, data, e))
  722. return false;
  723. case 0x00:
  724. break;
  725. case 0xFF:
  726. SOCKS_FAIL ("no acceptable authentication methods");
  727. default:
  728. SOCKS_FAIL ("protocol error");
  729. }
  730. return true;
  731. }
  732. static bool
  733. socks_5_send_req (int sockfd, struct socks_data *data, struct error **e)
  734. {
  735. uint8_t req[4 + 256 + 2], *p = req;
  736. *p++ = 0x05; // version
  737. *p++ = 0x01; // connect
  738. *p++ = 0x00; // reserved
  739. *p++ = data->address.type;
  740. switch (data->address.type)
  741. {
  742. case SOCKS_IPV4:
  743. memcpy (p, data->address.data.ipv4, sizeof data->address.data.ipv4);
  744. p += sizeof data->address.data.ipv4;
  745. break;
  746. case SOCKS_DOMAIN:
  747. {
  748. size_t dlen = strlen (data->address.data.domain);
  749. if (dlen > 255)
  750. dlen = 255;
  751. *p++ = dlen;
  752. memcpy (p, data->address.data.domain, dlen);
  753. p += dlen;
  754. break;
  755. }
  756. case SOCKS_IPV6:
  757. memcpy (p, data->address.data.ipv6, sizeof data->address.data.ipv6);
  758. p += sizeof data->address.data.ipv6;
  759. break;
  760. }
  761. *p++ = data->port >> 8;
  762. *p++ = data->port;
  763. if (send (sockfd, req, p - req, 0) == -1)
  764. SOCKS_FAIL ("%s: %s", "send", strerror (errno));
  765. return true;
  766. }
  767. static bool
  768. socks_5_process_resp (int sockfd, struct socks_data *data, struct error **e)
  769. {
  770. uint8_t resp_header[4];
  771. ssize_t n;
  772. SOCKS_RECV (resp_header, sizeof resp_header);
  773. if (resp_header[0] != 0x05)
  774. SOCKS_FAIL ("protocol error");
  775. switch (resp_header[1])
  776. {
  777. case 0x00:
  778. break;
  779. case 0x01: SOCKS_FAIL ("general SOCKS server failure");
  780. case 0x02: SOCKS_FAIL ("connection not allowed by ruleset");
  781. case 0x03: SOCKS_FAIL ("network unreachable");
  782. case 0x04: SOCKS_FAIL ("host unreachable");
  783. case 0x05: SOCKS_FAIL ("connection refused");
  784. case 0x06: SOCKS_FAIL ("TTL expired");
  785. case 0x07: SOCKS_FAIL ("command not supported");
  786. case 0x08: SOCKS_FAIL ("address type not supported");
  787. default: SOCKS_FAIL ("protocol error");
  788. }
  789. switch ((data->bound_address.type = resp_header[3]))
  790. {
  791. case SOCKS_IPV4:
  792. SOCKS_RECV (data->bound_address.data.ipv4,
  793. sizeof data->bound_address.data.ipv4);
  794. break;
  795. case SOCKS_IPV6:
  796. SOCKS_RECV (data->bound_address.data.ipv6,
  797. sizeof data->bound_address.data.ipv6);
  798. break;
  799. case SOCKS_DOMAIN:
  800. {
  801. uint8_t len;
  802. SOCKS_RECV (&len, sizeof len);
  803. char domain[len + 1];
  804. SOCKS_RECV (domain, len);
  805. domain[len] = '\0';
  806. data->bound_address.data.domain = xstrdup (domain);
  807. }
  808. default:
  809. SOCKS_FAIL ("protocol error");
  810. }
  811. uint16_t port;
  812. SOCKS_RECV (&port, sizeof port);
  813. data->bound_port = ntohs (port);
  814. return true;
  815. }
  816. #undef SOCKS_FAIL
  817. #undef SOCKS_RECV
  818. static bool
  819. socks_5_connect (struct addrinfo *addresses, struct socks_data *data,
  820. int *fd, struct error **e)
  821. {
  822. int sockfd;
  823. if (!socks_get_socket (addresses, &sockfd, e))
  824. return false;
  825. if (!socks_5_auth (sockfd, data, e)
  826. || !socks_5_send_req (sockfd, data, e)
  827. || !socks_5_process_resp (sockfd, data, e))
  828. {
  829. xclose (sockfd);
  830. return false;
  831. }
  832. *fd = sockfd;
  833. return true;
  834. }
  835. static int
  836. socks_connect (const char *socks_host, const char *socks_port,
  837. const char *host, const char *port,
  838. const char *username, const char *password, struct error **e)
  839. {
  840. struct addrinfo gai_hints, *gai_result;
  841. memset (&gai_hints, 0, sizeof gai_hints);
  842. gai_hints.ai_socktype = SOCK_STREAM;
  843. int err = getaddrinfo (socks_host, socks_port, &gai_hints, &gai_result);
  844. if (err)
  845. {
  846. error_set (e, "%s: %s", "getaddrinfo", gai_strerror (err));
  847. return false;
  848. }
  849. unsigned long port_no;
  850. const struct servent *serv;
  851. if ((serv = getservbyname (port, "tcp")))
  852. port_no = (uint16_t) ntohs (serv->s_port);
  853. else if (!xstrtoul (&port_no, port, 10) || !port_no || port_no > UINT16_MAX)
  854. {
  855. error_set (e, "invalid port number");
  856. return false;
  857. }
  858. struct socks_data data =
  859. { .username = username, .password = password, .port = port_no };
  860. if (inet_pton (AF_INET, host, &data.address.data.ipv4) == 1)
  861. data.address.type = SOCKS_IPV4;
  862. else if (inet_pton (AF_INET6, host, &data.address.data.ipv6) == 1)
  863. data.address.type = SOCKS_IPV6;
  864. else
  865. {
  866. data.address.type = SOCKS_DOMAIN;
  867. data.address.data.domain = host;
  868. }
  869. int fd;
  870. bool success = socks_5_connect (gai_result, &data, &fd, NULL)
  871. || socks_4a_connect (gai_result, &data, &fd, e);
  872. freeaddrinfo (gai_result);
  873. if (data.bound_address.type == SOCKS_DOMAIN)
  874. free ((char *) data.bound_address.data.domain);
  875. return success ? fd : -1;
  876. }
  877. // --- Plugins -----------------------------------------------------------------
  878. /// The name of the special IRC command for interprocess communication
  879. static const char *plugin_ipc_command = "ZYKLONB";
  880. static struct plugin_data *
  881. plugin_find_by_pid (struct bot_context *ctx, pid_t pid)
  882. {
  883. struct plugin_data *iter;
  884. for (iter = ctx->plugins; iter; iter = iter->next)
  885. if (iter->pid == pid)
  886. return iter;
  887. return NULL;
  888. }
  889. static bool
  890. plugin_zombify (struct plugin_data *plugin)
  891. {
  892. if (plugin->is_zombie)
  893. return false;
  894. // FIXME: make sure that we don't remove entries from the poller while we
  895. // still may have stuff to read; maybe just check that the read pipe is
  896. // empty before closing it... and then on EOF check if `pid == -1' and
  897. // only then dispose of it (it'd be best to simulate that both of these
  898. // cases may happen).
  899. ssize_t poller_idx =
  900. poller_find_by_fd (&plugin->ctx->poller, plugin->write_fd);
  901. if (poller_idx != -1)
  902. poller_remove_at_index (&plugin->ctx->poller, poller_idx);
  903. // TODO: try to flush the write buffer (non-blocking)?
  904. // The plugin should terminate itself after it receives EOF.
  905. xclose (plugin->write_fd);
  906. plugin->write_fd = -1;
  907. // Make it a pseudo-anonymous zombie. In this state we process any
  908. // remaining commands it attempts to send to us before it finally dies.
  909. str_map_set (&plugin->ctx->plugins_by_name, plugin->name, NULL);
  910. plugin->is_zombie = true;
  911. // TODO: wait a few seconds and then send SIGKILL to the plugin
  912. return true;
  913. }
  914. static void
  915. on_plugin_writable (const struct pollfd *fd, struct plugin_data *plugin)
  916. {
  917. struct bot_context *ctx = plugin->ctx;
  918. struct str *buf = &plugin->write_buffer;
  919. size_t written_total = 0;
  920. if (fd->revents & ~(POLLOUT | POLLHUP | POLLERR))
  921. print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
  922. while (written_total != buf->len)
  923. {
  924. ssize_t n_written = write (fd->fd, buf->str + written_total,
  925. buf->len - written_total);
  926. if (n_written < 0)
  927. {
  928. if (errno == EAGAIN)
  929. break;
  930. if (errno == EINTR)
  931. continue;
  932. soft_assert (errno == EPIPE);
  933. // Zombies shouldn't get dispatched for writability
  934. hard_assert (!plugin->is_zombie);
  935. print_debug ("%s: %s", "write", strerror (errno));
  936. print_error ("failure on writing to plugin `%s',"
  937. " therefore I'm unloading it", plugin->name);
  938. plugin_zombify (plugin);
  939. break;
  940. }
  941. // This may be equivalent to EAGAIN on some implementations
  942. if (n_written == 0)
  943. break;
  944. written_total += n_written;
  945. }
  946. if (written_total != 0)
  947. str_remove_slice (buf, 0, written_total);
  948. if (buf->len == 0)
  949. {
  950. // Everything has been written, there's no need to end up in here again
  951. ssize_t index = poller_find_by_fd (&ctx->poller, fd->fd);
  952. if (index != -1)
  953. poller_remove_at_index (&ctx->poller, index);
  954. }
  955. }
  956. static void
  957. plugin_queue_write (struct plugin_data *plugin)
  958. {
  959. if (plugin->is_zombie)
  960. return;
  961. // Don't let the write buffer grow infinitely. If there's a ton of data
  962. // waiting to be processed by the plugin, it usually means there's something
  963. // wrong with it (such as someone stopping the process).
  964. if (plugin->write_buffer.len >= (1 << 20))
  965. {
  966. print_warning ("plugin `%s' does not seem to process messages fast"
  967. " enough, I'm unloading it", plugin->name);
  968. plugin_zombify (plugin);
  969. return;
  970. }
  971. poller_set (&plugin->ctx->poller, plugin->write_fd, POLLOUT,
  972. (poller_dispatcher_fn) on_plugin_writable, plugin);
  973. }
  974. static void
  975. plugin_send (struct plugin_data *plugin, const char *format, ...)
  976. ATTRIBUTE_PRINTF (2, 3);
  977. static void
  978. plugin_send (struct plugin_data *plugin, const char *format, ...)
  979. {
  980. va_list ap;
  981. if (g_debug_mode)
  982. {
  983. fprintf (stderr, "[%s] <-- \"", plugin->name);
  984. va_start (ap, format);
  985. vfprintf (stderr, format, ap);
  986. va_end (ap);
  987. fputs ("\"\n", stderr);
  988. }
  989. va_start (ap, format);
  990. str_append_vprintf (&plugin->write_buffer, format, ap);
  991. va_end (ap);
  992. str_append (&plugin->write_buffer, "\r\n");
  993. plugin_queue_write (plugin);
  994. }
  995. static void
  996. plugin_process_message (const struct irc_message *msg,
  997. const char *raw, void *user_data)
  998. {
  999. struct plugin_data *plugin = user_data;
  1000. struct bot_context *ctx = plugin->ctx;
  1001. if (g_debug_mode)
  1002. fprintf (stderr, "[%s] --> \"%s\"\n", plugin->name, raw);
  1003. if (!strcasecmp (msg->command, plugin_ipc_command))
  1004. {
  1005. // Replies are sent in the order in which they came in, so there's
  1006. // no need to attach a special identifier to them. It might be
  1007. // desirable in some cases, though.
  1008. if (msg->params.len < 1)
  1009. return;
  1010. const char *command = msg->params.vector[0];
  1011. if (!plugin->initialized && !strcasecmp (command, "register"))
  1012. {
  1013. // Register for relaying of IRC traffic
  1014. plugin->initialized = true;
  1015. // Flush any queued up traffic here. The point of queuing it in
  1016. // the first place is so that we don't have to wait for plugin
  1017. // initialization during startup.
  1018. //
  1019. // Note that if we start filtering data coming to the plugins e.g.
  1020. // based on what it tells us upon registration, we might need to
  1021. // filter `queued_output' as well.
  1022. str_append_str (&plugin->write_buffer, &plugin->queued_output);
  1023. str_free (&plugin->queued_output);
  1024. // NOTE: this may trigger the buffer length check
  1025. plugin_queue_write (plugin);
  1026. }
  1027. else if (!strcasecmp (command, "get_config"))
  1028. {
  1029. if (msg->params.len < 2)
  1030. return;
  1031. const char *value =
  1032. str_map_find (&ctx->config, msg->params.vector[1]);
  1033. // TODO: escape the value (although there's no need to ATM)
  1034. plugin_send (plugin, "%s :%s",
  1035. plugin_ipc_command, value ? value : "");
  1036. }
  1037. else if (!strcasecmp (command, "print"))
  1038. {
  1039. if (msg->params.len < 2)
  1040. return;
  1041. printf ("%s\n", msg->params.vector[1]);
  1042. }
  1043. }
  1044. else if (plugin->initialized && ctx->irc_ready)
  1045. {
  1046. // Pass everything else through to the IRC server
  1047. // XXX: when the server isn't ready yet, these messages get silently
  1048. // discarded, which shouldn't pose a problem most of the time.
  1049. // Perhaps we could send a "connected" notification on `register'
  1050. // if `irc_ready' is true, or after it becomes true later, so that
  1051. // plugins know when to start sending unprovoked IRC messages.
  1052. // XXX: another case is when the connection gets interrupted and the
  1053. // plugin tries to send something back while we're reconnecting.
  1054. // For that we might set up a global buffer that gets flushed out
  1055. // after `irc_ready' becomes true. Note that there is always some
  1056. // chance of messages getting lost without us even noticing it.
  1057. irc_send (ctx, "%s", raw);
  1058. }
  1059. }
  1060. static void
  1061. on_plugin_readable (const struct pollfd *fd, struct plugin_data *plugin)
  1062. {
  1063. if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
  1064. print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
  1065. // TODO: see if I can reuse irc_fill_read_buffer()
  1066. struct str *buf = &plugin->read_buffer;
  1067. while (true)
  1068. {
  1069. str_ensure_space (buf, 512 + 1);
  1070. ssize_t n_read = read (fd->fd, buf->str + buf->len,
  1071. buf->alloc - buf->len - 1);
  1072. if (n_read < 0)
  1073. {
  1074. if (errno == EAGAIN)
  1075. break;
  1076. if (soft_assert (errno == EINTR))
  1077. continue;
  1078. if (!plugin->is_zombie)
  1079. {
  1080. print_error ("failure on reading from plugin `%s',"
  1081. " therefore I'm unloading it", plugin->name);
  1082. plugin_zombify (plugin);
  1083. }
  1084. return;
  1085. }
  1086. // EOF; hopefully it will die soon (maybe it already has)
  1087. if (n_read == 0)
  1088. break;
  1089. buf->str[buf->len += n_read] = '\0';
  1090. if (buf->len >= (1 << 20))
  1091. {
  1092. // XXX: this isn't really the best flood prevention mechanism,
  1093. // but it wasn't even supposed to be one.
  1094. if (plugin->is_zombie)
  1095. {
  1096. print_error ("a zombie of plugin `%s' is trying to flood us,"
  1097. " therefore I'm killing it", plugin->name);
  1098. kill (plugin->pid, SIGKILL);
  1099. }
  1100. else
  1101. {
  1102. print_error ("plugin `%s' seems to spew out data frantically,"
  1103. " therefore I'm unloading it", plugin->name);
  1104. plugin_zombify (plugin);
  1105. }
  1106. return;
  1107. }
  1108. }
  1109. irc_process_buffer (buf, plugin_process_message, plugin);
  1110. }
  1111. static bool
  1112. is_valid_plugin_name (const char *name)
  1113. {
  1114. if (!*name)
  1115. return false;
  1116. for (const char *p = name; *p; p++)
  1117. if (!isgraph (*p) || *p == '/')
  1118. return false;
  1119. return true;
  1120. }
  1121. static bool
  1122. plugin_load (struct bot_context *ctx, const char *name, struct error **e)
  1123. {
  1124. const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir");
  1125. if (!plugin_dir)
  1126. {
  1127. error_set (e, "plugin directory not set");
  1128. return false;
  1129. }
  1130. if (!is_valid_plugin_name (name))
  1131. {
  1132. error_set (e, "invalid plugin name");
  1133. return false;
  1134. }
  1135. if (str_map_find (&ctx->plugins_by_name, name))
  1136. {
  1137. error_set (e, "the plugin has already been loaded");
  1138. return false;
  1139. }
  1140. int stdin_pipe[2];
  1141. if (pipe (stdin_pipe) == -1)
  1142. {
  1143. error_set (e, "%s: %s: %s",
  1144. "failed to load the plugin", "pipe", strerror (errno));
  1145. goto fail_1;
  1146. }
  1147. int stdout_pipe[2];
  1148. if (pipe (stdout_pipe) == -1)
  1149. {
  1150. error_set (e, "%s: %s: %s",
  1151. "failed to load the plugin", "pipe", strerror (errno));
  1152. goto fail_2;
  1153. }
  1154. set_cloexec (stdin_pipe[1]);
  1155. set_cloexec (stdout_pipe[0]);
  1156. pid_t pid = fork ();
  1157. if (pid == -1)
  1158. {
  1159. error_set (e, "%s: %s: %s",
  1160. "failed to load the plugin", "fork", strerror (errno));
  1161. goto fail_3;
  1162. }
  1163. if (pid == 0)
  1164. {
  1165. // Redirect the child's stdin and stdout to the pipes
  1166. hard_assert (dup2 (stdin_pipe[0], STDIN_FILENO) != -1);
  1167. hard_assert (dup2 (stdout_pipe[1], STDOUT_FILENO) != -1);
  1168. xclose (stdin_pipe[0]);
  1169. xclose (stdout_pipe[1]);
  1170. struct str pathname;
  1171. str_init (&pathname);
  1172. str_append (&pathname, plugin_dir);
  1173. str_append_c (&pathname, '/');
  1174. str_append (&pathname, name);
  1175. // Restore some of the signal handling
  1176. signal (SIGPIPE, SIG_DFL);
  1177. char *const argv[] = { pathname.str, NULL };
  1178. execve (argv[0], argv, environ);
  1179. // We will collect the failure later via SIGCHLD
  1180. print_error ("%s: %s: %s",
  1181. "failed to load the plugin", "exec", strerror (errno));
  1182. _exit (EXIT_FAILURE);
  1183. }
  1184. xclose (stdin_pipe[0]);
  1185. xclose (stdout_pipe[1]);
  1186. set_blocking (stdout_pipe[0], false);
  1187. set_blocking (stdin_pipe[1], false);
  1188. struct plugin_data *plugin = xmalloc (sizeof *plugin);
  1189. plugin_data_init (plugin);
  1190. plugin->ctx = ctx;
  1191. plugin->pid = pid;
  1192. plugin->name = xstrdup (name);
  1193. plugin->read_fd = stdout_pipe[0];
  1194. plugin->write_fd = stdin_pipe[1];
  1195. LIST_PREPEND (ctx->plugins, plugin);
  1196. str_map_set (&ctx->plugins_by_name, name, plugin);
  1197. poller_set (&ctx->poller, stdout_pipe[0], POLLIN,
  1198. (poller_dispatcher_fn) on_plugin_readable, plugin);
  1199. return true;
  1200. fail_3:
  1201. xclose (stdout_pipe[0]);
  1202. xclose (stdout_pipe[1]);
  1203. fail_2:
  1204. xclose (stdin_pipe[0]);
  1205. xclose (stdin_pipe[1]);
  1206. fail_1:
  1207. return false;
  1208. }
  1209. static bool
  1210. plugin_unload (struct bot_context *ctx, const char *name, struct error **e)
  1211. {
  1212. struct plugin_data *plugin = str_map_find (&ctx->plugins_by_name, name);
  1213. if (!plugin)
  1214. {
  1215. error_set (e, "no such plugin is loaded");
  1216. return false;
  1217. }
  1218. plugin_zombify (plugin);
  1219. // TODO: add a `kill zombies' command to forcefully get rid of processes
  1220. // that do not understand the request.
  1221. return true;
  1222. }
  1223. static void
  1224. plugin_load_all_from_config (struct bot_context *ctx)
  1225. {
  1226. const char *plugin_list = str_map_find (&ctx->config, "plugins");
  1227. if (!plugin_list)
  1228. return;
  1229. struct str_vector plugins;
  1230. str_vector_init (&plugins);
  1231. split_str_ignore_empty (plugin_list, ',', &plugins);
  1232. for (size_t i = 0; i < plugins.len; i++)
  1233. {
  1234. char *name = strip_str_in_place (plugins.vector[i], " ");
  1235. struct error *e = NULL;
  1236. if (!plugin_load (ctx, name, &e))
  1237. {
  1238. print_error ("plugin `%s' failed to load: %s", name, e->message);
  1239. error_free (e);
  1240. }
  1241. }
  1242. str_vector_free (&plugins);
  1243. }
  1244. // --- Main program ------------------------------------------------------------
  1245. static bool
  1246. parse_bot_command (const char *s, const char *command, const char **following)
  1247. {
  1248. size_t command_len = strlen (command);
  1249. if (strncasecmp (s, command, command_len))
  1250. return false;
  1251. s += command_len;
  1252. // Expect a word boundary, so that we don't respond to invalid things
  1253. if (isalnum (*s))
  1254. return false;
  1255. // Ignore any initial spaces; the rest is the command's argument
  1256. while (isblank (*s))
  1257. s++;
  1258. *following = s;
  1259. return true;
  1260. }
  1261. static void
  1262. split_bot_command_argument_list (const char *arguments, struct str_vector *out)
  1263. {
  1264. split_str_ignore_empty (arguments, ',', out);
  1265. for (size_t i = 0; i < out->len; )
  1266. {
  1267. if (!*strip_str_in_place (out->vector[i], " \t"))
  1268. str_vector_remove (out, i);
  1269. else
  1270. i++;
  1271. }
  1272. }
  1273. static bool
  1274. is_private_message (const struct irc_message *msg)
  1275. {
  1276. hard_assert (msg->params.len);
  1277. return !strchr ("#&+!", *msg->params.vector[0]);
  1278. }
  1279. static bool
  1280. is_sent_by_admin (struct bot_context *ctx, const struct irc_message *msg)
  1281. {
  1282. // No administrator set -> everyone is an administrator
  1283. if (!ctx->admin_re)
  1284. return true;
  1285. return regexec (ctx->admin_re, msg->prefix, 0, NULL, 0) != REG_NOMATCH;
  1286. }
  1287. static void respond_to_user (struct bot_context *ctx, const struct
  1288. irc_message *msg, const char *format, ...) ATTRIBUTE_PRINTF (3, 4);
  1289. static void
  1290. respond_to_user (struct bot_context *ctx, const struct irc_message *msg,
  1291. const char *format, ...)
  1292. {
  1293. if (!soft_assert (msg->prefix && msg->params.len))
  1294. return;
  1295. char nick[strcspn (msg->prefix, "!") + 1];
  1296. strncpy (nick, msg->prefix, sizeof nick - 1);
  1297. nick[sizeof nick - 1] = '\0';
  1298. struct str text;
  1299. va_list ap;
  1300. str_init (&text);
  1301. va_start (ap, format);
  1302. str_append_vprintf (&text, format, ap);
  1303. va_end (ap);
  1304. if (is_private_message (msg))
  1305. irc_send (ctx, "PRIVMSG %s :%s", nick, text.str);
  1306. else
  1307. irc_send (ctx, "PRIVMSG %s :%s: %s",
  1308. msg->params.vector[0], nick, text.str);
  1309. str_free (&text);
  1310. }
  1311. static void
  1312. process_plugin_load (struct bot_context *ctx,
  1313. const struct irc_message *msg, const char *name)
  1314. {
  1315. struct error *e = NULL;
  1316. if (plugin_load (ctx, name, &e))
  1317. respond_to_user (ctx, msg, "plugin `%s' queued for loading", name);
  1318. else
  1319. {
  1320. respond_to_user (ctx, msg, "plugin `%s' could not be loaded: %s",
  1321. name, e->message);
  1322. error_free (e);
  1323. }
  1324. }
  1325. static void
  1326. process_plugin_unload (struct bot_context *ctx,
  1327. const struct irc_message *msg, const char *name)
  1328. {
  1329. struct error *e = NULL;
  1330. if (plugin_unload (ctx, name, &e))
  1331. respond_to_user (ctx, msg, "plugin `%s' unloaded", name);
  1332. else
  1333. {
  1334. respond_to_user (ctx, msg, "plugin `%s' could not be unloaded: %s",
  1335. name, e->message);
  1336. error_free (e);
  1337. }
  1338. }
  1339. static void
  1340. process_plugin_reload (struct bot_context *ctx,
  1341. const struct irc_message *msg, const char *name)
  1342. {
  1343. // XXX: we might want to wait until the plugin terminates before we try
  1344. // to reload it (so that it can save its configuration or whatever)
  1345. // So far the only error that can occur is that the plugin hasn't been
  1346. // loaded, which in this case doesn't really matter.
  1347. plugin_unload (ctx, name, NULL);
  1348. process_plugin_load (ctx, msg, name);
  1349. }
  1350. static void
  1351. process_privmsg (struct bot_context *ctx, const struct irc_message *msg)
  1352. {
  1353. if (!is_sent_by_admin (ctx, msg))
  1354. return;
  1355. if (msg->params.len < 2)
  1356. return;
  1357. const char *prefix = str_map_find (&ctx->config, "prefix");
  1358. hard_assert (prefix != NULL); // We have a default value for this
  1359. // For us to recognize the command, it has to start with the prefix,
  1360. // with the exception of PM's sent directly to us.
  1361. const char *text = msg->params.vector[1];
  1362. if (!strncmp (text, prefix, strlen (prefix)))
  1363. text += strlen (prefix);
  1364. else if (!is_private_message (msg))
  1365. return;
  1366. const char *following;
  1367. struct str_vector list;
  1368. str_vector_init (&list);
  1369. if (parse_bot_command (text, "quote", &following))
  1370. // This seems to replace tons of random stupid commands
  1371. irc_send (ctx, "%s", following);
  1372. else if (parse_bot_command (text, "quit", &following))
  1373. {
  1374. // We actually need this command (instead of just `quote') because we
  1375. // could try to reconnect to the server automatically otherwise.
  1376. if (*following)
  1377. irc_send (ctx, "QUIT :%s", following);
  1378. else
  1379. irc_send (ctx, "QUIT");
  1380. initiate_quit (ctx);
  1381. }
  1382. else if (parse_bot_command (text, "status", &following))
  1383. {
  1384. struct str report;
  1385. str_init (&report);
  1386. const char *reason = getenv (g_startup_reason_str);
  1387. if (!reason)
  1388. reason = "launched normally";
  1389. str_append_printf (&report,
  1390. "\x02startup reason:\x0f %s; \x02plugins:\x0f ", reason);
  1391. size_t zombies = 0;
  1392. const char *prepend = "";
  1393. for (struct plugin_data *plugin = ctx->plugins;
  1394. plugin; plugin = plugin->next)
  1395. {
  1396. if (plugin->is_zombie)
  1397. zombies++;
  1398. else
  1399. {
  1400. str_append_printf (&report, "%s%s", prepend, plugin->name);
  1401. prepend = ", ";
  1402. }
  1403. }
  1404. if (!ctx->plugins)
  1405. str_append (&report, "\x02none\x0f");
  1406. str_append_printf (&report, "; \x02zombies:\x0f %zu", zombies);
  1407. respond_to_user (ctx, msg, "%s", report.str);
  1408. str_free (&report);
  1409. }
  1410. else if (parse_bot_command (text, "load", &following))
  1411. {
  1412. split_bot_command_argument_list (following, &list);
  1413. for (size_t i = 0; i < list.len; i++)
  1414. process_plugin_load (ctx, msg, list.vector[i]);
  1415. }
  1416. else if (parse_bot_command (text, "reload", &following))
  1417. {
  1418. split_bot_command_argument_list (following, &list);
  1419. for (size_t i = 0; i < list.len; i++)
  1420. process_plugin_reload (ctx, msg, list.vector[i]);
  1421. }
  1422. else if (parse_bot_command (text, "unload", &following))
  1423. {
  1424. split_bot_command_argument_list (following, &list);
  1425. for (size_t i = 0; i < list.len; i++)
  1426. process_plugin_unload (ctx, msg, list.vector[i]);
  1427. }
  1428. str_vector_free (&list);
  1429. }
  1430. static void
  1431. irc_forward_message_to_plugins (struct bot_context *ctx, const char *raw)
  1432. {
  1433. // For consistency with plugin_process_message()
  1434. if (!ctx->irc_ready)
  1435. return;
  1436. for (struct plugin_data *plugin = ctx->plugins;
  1437. plugin; plugin = plugin->next)
  1438. {
  1439. if (plugin->is_zombie)
  1440. continue;
  1441. if (plugin->initialized)
  1442. plugin_send (plugin, "%s", raw);
  1443. else
  1444. // TODO: make sure that this buffer doesn't get too large either
  1445. str_append_printf (&plugin->queued_output, "%s\r\n", raw);
  1446. }
  1447. }
  1448. static void
  1449. irc_process_message (const struct irc_message *msg,
  1450. const char *raw, void *user_data)
  1451. {
  1452. struct bot_context *ctx = user_data;
  1453. if (g_debug_mode)
  1454. fprintf (stderr, "[%s] ==> \"%s\"\n", "IRC", raw);
  1455. // This should be as minimal as possible, I don't want to have the whole bot
  1456. // written in C, especially when I have this overengineered plugin system.
  1457. // Therefore the very basic functionality only.
  1458. //
  1459. // I should probably even rip out the autojoin...
  1460. irc_forward_message_to_plugins (ctx, raw);
  1461. if (!strcasecmp (msg->command, "PING"))
  1462. {
  1463. if (msg->params.len)
  1464. irc_send (ctx, "PONG :%s", msg->params.vector[0]);
  1465. else
  1466. irc_send (ctx, "PONG");
  1467. }
  1468. else if (!ctx->irc_ready && (!strcasecmp (msg->command, "MODE")
  1469. || !strcasecmp (msg->command, "376") // RPL_ENDOFMOTD
  1470. || !strcasecmp (msg->command, "422"))) // ERR_NOMOTD
  1471. {
  1472. print_status ("successfully connected");
  1473. ctx->irc_ready = true;
  1474. const char *autojoin = str_map_find (&ctx->config, "autojoin");
  1475. if (autojoin)
  1476. irc_send (ctx, "JOIN :%s", autojoin);
  1477. }
  1478. else if (!strcasecmp (msg->command, "PRIVMSG"))
  1479. process_privmsg (ctx, msg);
  1480. }
  1481. enum irc_read_result
  1482. {
  1483. IRC_READ_OK, ///< Some data were read successfully
  1484. IRC_READ_EOF, ///< The server has closed connection
  1485. IRC_READ_AGAIN, ///< No more data at the moment
  1486. IRC_READ_ERROR ///< General connection failure
  1487. };
  1488. static enum irc_read_result
  1489. irc_fill_read_buffer_ssl (struct bot_context *ctx, struct str *buf)
  1490. {
  1491. int n_read;
  1492. start:
  1493. n_read = SSL_read (ctx->ssl, buf->str + buf->len,
  1494. buf->alloc - buf->len - 1 /* null byte */);
  1495. const char *error_info = NULL;
  1496. switch (xssl_get_error (ctx->ssl, n_read, &error_info))
  1497. {
  1498. case SSL_ERROR_NONE:
  1499. buf->str[buf->len += n_read] = '\0';
  1500. return IRC_READ_OK;
  1501. case SSL_ERROR_ZERO_RETURN:
  1502. return IRC_READ_EOF;
  1503. case SSL_ERROR_WANT_READ:
  1504. return IRC_READ_AGAIN;
  1505. case SSL_ERROR_WANT_WRITE:
  1506. {
  1507. // Let it finish the handshake as we don't poll for writability;
  1508. // any errors are to be collected by SSL_read() in the next iteration
  1509. struct pollfd pfd = { .fd = ctx->irc_fd, .events = POLLOUT };
  1510. soft_assert (poll (&pfd, 1, 0) > 0);
  1511. goto start;
  1512. }
  1513. case XSSL_ERROR_TRY_AGAIN:
  1514. goto start;
  1515. default:
  1516. print_debug ("%s: %s: %s", __func__, "SSL_read", error_info);
  1517. return IRC_READ_ERROR;
  1518. }
  1519. }
  1520. static enum irc_read_result
  1521. irc_fill_read_buffer (struct bot_context *ctx, struct str *buf)
  1522. {
  1523. ssize_t n_read;
  1524. start:
  1525. n_read = recv (ctx->irc_fd, buf->str + buf->len,
  1526. buf->alloc - buf->len - 1 /* null byte */, 0);
  1527. if (n_read > 0)
  1528. {
  1529. buf->str[buf->len += n_read] = '\0';
  1530. return IRC_READ_OK;
  1531. }
  1532. if (n_read == 0)
  1533. return IRC_READ_EOF;
  1534. if (errno == EAGAIN)
  1535. return IRC_READ_AGAIN;
  1536. if (errno == EINTR)
  1537. goto start;
  1538. print_debug ("%s: %s: %s", __func__, "recv", strerror (errno));
  1539. return IRC_READ_ERROR;
  1540. }
  1541. static bool irc_connect (struct bot_context *, struct error **);
  1542. static void irc_queue_reconnect (struct bot_context *);
  1543. static void
  1544. irc_cancel_timers (struct bot_context *ctx)
  1545. {
  1546. ssize_t i;
  1547. struct poller_timers *timers = &ctx->poller.timers;
  1548. while ((i = poller_timers_find_by_data (timers, ctx)) != -1)
  1549. poller_timers_remove_at_index (timers, i);
  1550. }
  1551. static void
  1552. irc_on_reconnect_timeout (void *user_data)
  1553. {
  1554. struct bot_context *ctx = user_data;
  1555. struct error *e = NULL;
  1556. if (irc_connect (ctx, &e))
  1557. {
  1558. // TODO: inform plugins about the new connection
  1559. return;
  1560. }
  1561. print_error ("%s", e->message);
  1562. error_free (e);
  1563. irc_queue_reconnect (ctx);
  1564. }
  1565. static void
  1566. irc_queue_reconnect (struct bot_context *ctx)
  1567. {
  1568. hard_assert (ctx->irc_fd == -1);
  1569. print_status ("trying to reconnect in %ld seconds...",
  1570. ctx->reconnect_delay);
  1571. poller_timers_add (&ctx->poller.timers,
  1572. irc_on_reconnect_timeout, ctx, ctx->reconnect_delay * 1000);
  1573. }
  1574. static void
  1575. on_irc_disconnected (struct bot_context *ctx)
  1576. {
  1577. // Get rid of the dead socket and related things
  1578. if (ctx->ssl)
  1579. {
  1580. SSL_free (ctx->ssl);
  1581. ctx->ssl = NULL;
  1582. SSL_CTX_free (ctx->ssl_ctx);
  1583. ctx->ssl_ctx = NULL;
  1584. }
  1585. ssize_t i = poller_find_by_fd (&ctx->poller, ctx->irc_fd);
  1586. if (i != -1)
  1587. poller_remove_at_index (&ctx->poller, i);
  1588. xclose (ctx->irc_fd);
  1589. ctx->irc_fd = -1;
  1590. ctx->irc_ready = false;
  1591. // TODO: inform plugins about the disconnect event
  1592. // All of our timers have lost their meaning now
  1593. irc_cancel_timers (ctx);
  1594. if (ctx->quitting)
  1595. try_finish_quit (ctx);
  1596. else if (!ctx->reconnect)
  1597. initiate_quit (ctx);
  1598. else
  1599. irc_queue_reconnect (ctx);
  1600. }
  1601. static void
  1602. on_irc_ping_timeout (void *user_data)
  1603. {
  1604. struct bot_context *ctx = user_data;
  1605. print_error ("connection timeout");
  1606. on_irc_disconnected (ctx);
  1607. }
  1608. static void
  1609. on_irc_timeout (void *user_data)
  1610. {
  1611. // Provoke a response from the server
  1612. struct bot_context *ctx = user_data;
  1613. irc_send (ctx, "PING :%s",
  1614. (char *) str_map_find (&ctx->config, "nickname"));
  1615. }
  1616. static void
  1617. irc_reset_connection_timeouts (struct bot_context *ctx)
  1618. {
  1619. irc_cancel_timers (ctx);
  1620. poller_timers_add (&ctx->poller.timers,
  1621. on_irc_timeout, ctx, 3 * 60 * 1000);
  1622. poller_timers_add (&ctx->poller.timers,
  1623. on_irc_ping_timeout, ctx, (3 * 60 + 30) * 1000);
  1624. }
  1625. static void
  1626. on_irc_readable (const struct pollfd *fd, struct bot_context *ctx)
  1627. {
  1628. if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
  1629. print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
  1630. (void) set_blocking (ctx->irc_fd, false);
  1631. struct str *buf = &ctx->read_buffer;
  1632. enum irc_read_result (*fill_buffer)(struct bot_context *, struct str *)
  1633. = ctx->ssl
  1634. ? irc_fill_read_buffer_ssl
  1635. : irc_fill_read_buffer;
  1636. bool disconnected = false;
  1637. while (true)
  1638. {
  1639. str_ensure_space (buf, 512);
  1640. switch (fill_buffer (ctx, buf))
  1641. {
  1642. case IRC_READ_AGAIN:
  1643. goto end;
  1644. case IRC_READ_ERROR:
  1645. print_error ("reading from the IRC server failed");
  1646. disconnected = true;
  1647. goto end;
  1648. case IRC_READ_EOF:
  1649. print_status ("the IRC server closed the connection");
  1650. disconnected = true;
  1651. goto end;
  1652. case IRC_READ_OK:
  1653. break;
  1654. }
  1655. if (buf->len >= (1 << 20))
  1656. {
  1657. print_error ("the IRC server seems to spew out data frantically");
  1658. irc_shutdown (ctx);
  1659. goto end;
  1660. }
  1661. }
  1662. end:
  1663. (void) set_blocking (ctx->irc_fd, true);
  1664. irc_process_buffer (buf, irc_process_message, ctx);
  1665. if (disconnected)
  1666. on_irc_disconnected (ctx);
  1667. else
  1668. irc_reset_connection_timeouts (ctx);
  1669. }
  1670. static bool
  1671. irc_connect (struct bot_context *ctx, struct error **e)
  1672. {
  1673. const char *irc_host = str_map_find (&ctx->config, "irc_host");
  1674. const char *irc_port = str_map_find (&ctx->config, "irc_port");
  1675. const char *ssl_use_str = str_map_find (&ctx->config, "ssl_use");
  1676. const char *socks_host = str_map_find (&ctx->config, "socks_host");
  1677. const char *socks_port = str_map_find (&ctx->config, "socks_port");
  1678. const char *socks_username = str_map_find (&ctx->config, "socks_username");
  1679. const char *socks_password = str_map_find (&ctx->config, "socks_password");
  1680. const char *nickname = str_map_find (&ctx->config, "nickname");
  1681. const char *username = str_map_find (&ctx->config, "username");
  1682. const char *realname = str_map_find (&ctx->config, "realname");
  1683. // We have a default value for these
  1684. hard_assert (irc_port && ssl_use_str && socks_port);
  1685. hard_assert (nickname && username && realname);
  1686. // TODO: again, get rid of `struct error' in here. The question is: how
  1687. // do we tell our caller that he should not try to reconnect?
  1688. if (!irc_host)
  1689. {
  1690. error_set (e, "no hostname specified in configuration");
  1691. return false;
  1692. }
  1693. bool use_ssl;
  1694. if (!set_boolean_if_valid (&use_ssl, ssl_use_str))
  1695. {
  1696. error_set (e, "invalid configuration value for `%s'", "use_ssl");
  1697. return false;
  1698. }
  1699. if (socks_host)
  1700. {
  1701. char *address = format_host_port_pair (irc_host, irc_port);
  1702. char *socks_address = format_host_port_pair (socks_host, socks_port);
  1703. print_status ("connecting to %s via %s...", address, socks_address);
  1704. free (socks_address);
  1705. free (address);
  1706. struct error *error = NULL;
  1707. int fd = socks_connect (socks_host, socks_port, irc_host, irc_port,
  1708. socks_username, socks_password, &error);
  1709. if (fd == -1)
  1710. {
  1711. error_set (e, "%s: %s", "SOCKS connection failed", error->message);
  1712. error_free (error);
  1713. return false;
  1714. }
  1715. ctx->irc_fd = fd;
  1716. }
  1717. else if (!irc_establish_connection (ctx, irc_host, irc_port, e))
  1718. return false;
  1719. if (use_ssl && !irc_initialize_ssl (ctx, e))
  1720. {
  1721. xclose (ctx->irc_fd);
  1722. ctx->irc_fd = -1;
  1723. return false;
  1724. }
  1725. print_status ("connection established");
  1726. // TODO: in exec try: 1/ set blocking, 2/ setsockopt() SO_LINGER,
  1727. // (struct linger) { .l_onoff = true; .l_linger = 1 /* 1s should do */; }
  1728. // 3/ /* O_CLOEXEC */ But only if the QUIT message proves unreliable.
  1729. poller_set (&ctx->poller, ctx->irc_fd, POLLIN,
  1730. (poller_dispatcher_fn) on_irc_readable, ctx);
  1731. irc_reset_connection_timeouts (ctx);
  1732. irc_send (ctx, "NICK %s", nickname);
  1733. irc_send (ctx, "USER %s 8 * :%s", username, realname);
  1734. return true;
  1735. }
  1736. static bool
  1737. parse_config (struct bot_context *ctx, struct error **e)
  1738. {
  1739. const char *reconnect_str = str_map_find (&ctx->config, "reconnect");
  1740. hard_assert (reconnect_str != NULL); // We have a default value for this
  1741. if (!set_boolean_if_valid (&ctx->reconnect, reconnect_str))
  1742. {
  1743. error_set (e, "invalid configuration value for `%s'", "reconnect");
  1744. return false;
  1745. }
  1746. const char *delay_str = str_map_find (&ctx->config, "reconnect_delay");
  1747. hard_assert (delay_str != NULL); // We have a default value for this
  1748. if (!xstrtoul (&ctx->reconnect_delay, delay_str, 10))
  1749. {
  1750. error_set (e, "invalid configuration value for `%s'",
  1751. "reconnect_delay");
  1752. return false;
  1753. }
  1754. hard_assert (!ctx->admin_re);
  1755. const char *admin = str_map_find (&ctx->config, "admin");
  1756. if (!admin)
  1757. return true;
  1758. struct error *error = NULL;
  1759. ctx->admin_re = regex_compile (admin, REG_EXTENDED | REG_NOSUB, &error);
  1760. if (!error)
  1761. return true;
  1762. error_set (e, "invalid configuration value for `%s': %s",
  1763. "admin", error->message);
  1764. error_free (error);
  1765. return false;
  1766. }
  1767. static void
  1768. on_signal_pipe_readable (const struct pollfd *fd, struct bot_context *ctx)
  1769. {
  1770. char *dummy;
  1771. (void) read (fd->fd, &dummy, 1);
  1772. if (g_termination_requested && !ctx->quitting)
  1773. {
  1774. // There may be a timer set to reconnect to the server
  1775. irc_cancel_timers (ctx);
  1776. if (ctx->irc_fd != -1)
  1777. irc_send (ctx, "QUIT :Terminated by signal");
  1778. initiate_quit (ctx);
  1779. }
  1780. // Reap all dead children (since the pipe may overflow, we ask waitpid()
  1781. // to return all the zombies it knows about).
  1782. while (true)
  1783. {
  1784. int status;
  1785. pid_t zombie = waitpid (-1, &status, WNOHANG);
  1786. if (zombie == -1)
  1787. {
  1788. // No children to wait on
  1789. if (errno == ECHILD)
  1790. break;
  1791. hard_assert (errno == EINTR);
  1792. continue;
  1793. }
  1794. if (zombie == 0)
  1795. break;
  1796. struct plugin_data *plugin = plugin_find_by_pid (ctx, zombie);
  1797. // Something has died but we don't recognize it (re-exec?)
  1798. if (!soft_assert (plugin != NULL))
  1799. continue;
  1800. // TODO: callbacks on children death, so that we may tell the user
  1801. // "plugin `name' died like a dirty jewish pig"; use `status'
  1802. if (!plugin->is_zombie && WIFSIGNALED (status))
  1803. {
  1804. const char *notes = "";
  1805. #ifdef WCOREDUMP
  1806. if (WCOREDUMP (status))
  1807. notes = " (core dumped)";
  1808. #endif
  1809. print_warning ("Plugin `%s' died from signal %d%s",
  1810. plugin->name, WTERMSIG (status), notes);
  1811. }
  1812. // Let's go through the zombie state to simplify things a bit
  1813. // TODO: might not be a completely bad idea to restart the plugin
  1814. plugin_zombify (plugin);
  1815. plugin->pid = -1;
  1816. ssize_t poller_idx = poller_find_by_fd (&ctx->poller, plugin->read_fd);
  1817. if (poller_idx != -1)
  1818. poller_remove_at_index (&ctx->poller, poller_idx);
  1819. xclose (plugin->read_fd);
  1820. plugin->read_fd = -1;
  1821. LIST_UNLINK (ctx->plugins, plugin);
  1822. plugin_data_free (plugin);
  1823. free (plugin);
  1824. // Living child processes block us from quitting
  1825. try_finish_quit (ctx);
  1826. }
  1827. }
  1828. static void
  1829. print_usage (const char *program_name)
  1830. {
  1831. fprintf (stderr,
  1832. "Usage: %s [OPTION]...\n"
  1833. "Experimental IRC bot.\n"
  1834. "\n"
  1835. " -d, --debug run in debug mode\n"
  1836. " -h, --help display this help and exit\n"
  1837. " -V, --version output version information and exit\n"
  1838. " --write-default-cfg [filename]\n"
  1839. " write a default configuration file and exit\n",
  1840. program_name);
  1841. }
  1842. int
  1843. main (int argc, char *argv[])
  1844. {
  1845. const char *invocation_name = argv[0];
  1846. str_vector_init (&g_original_argv);
  1847. str_vector_add_vector (&g_original_argv, argv);
  1848. static struct option opts[] =
  1849. {
  1850. { "debug", no_argument, NULL, 'd' },
  1851. { "help", no_argument, NULL, 'h' },
  1852. { "version", no_argument, NULL, 'V' },
  1853. { "write-default-cfg", optional_argument, NULL, 'w' },
  1854. { NULL, 0, NULL, 0 }
  1855. };
  1856. while (1)
  1857. {
  1858. int c, opt_index;
  1859. c = getopt_long (argc, argv, "dhV", opts, &opt_index);
  1860. if (c == -1)
  1861. break;
  1862. switch (c)
  1863. {
  1864. case 'd':
  1865. g_debug_mode = true;
  1866. break;
  1867. case 'h':
  1868. print_usage (invocation_name);
  1869. exit (EXIT_SUCCESS);
  1870. case 'V':
  1871. printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
  1872. exit (EXIT_SUCCESS);
  1873. case 'w':
  1874. call_write_default_config (optarg, g_config_table);
  1875. exit (EXIT_SUCCESS);
  1876. default:
  1877. print_error ("wrong options");
  1878. exit (EXIT_FAILURE);
  1879. }
  1880. }
  1881. print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting");
  1882. setup_signal_handlers ();
  1883. SSL_library_init ();
  1884. atexit (EVP_cleanup);
  1885. SSL_load_error_strings ();
  1886. // XXX: ERR_load_BIO_strings()? Anything else?
  1887. atexit (ERR_free_strings);
  1888. struct bot_context ctx;
  1889. bot_context_init (&ctx);
  1890. struct error *e = NULL;
  1891. if (!read_config_file (&ctx.config, &e))
  1892. {
  1893. print_error ("error loading configuration: %s", e->message);
  1894. error_free (e);
  1895. exit (EXIT_FAILURE);
  1896. }
  1897. setup_recovery_handler (&ctx);
  1898. poller_set (&ctx.poller, g_signal_pipe[0], POLLIN,
  1899. (poller_dispatcher_fn) on_signal_pipe_readable, &ctx);
  1900. plugin_load_all_from_config (&ctx);
  1901. if (!parse_config (&ctx, &e)
  1902. || !irc_connect (&ctx, &e))
  1903. {
  1904. print_error ("%s", e->message);
  1905. error_free (e);
  1906. exit (EXIT_FAILURE);
  1907. }
  1908. // TODO: clean re-exec support; to save the state I can either use argv,
  1909. // argp, or I can create a temporary file, unlink it and use the FD
  1910. // (mkstemp() on a `struct str' constructed from XDG_RUNTIME_DIR, TMPDIR
  1911. // or /tmp as a last resort + PROGRAM_NAME + ".XXXXXX" -> unlink();
  1912. // remember to use O_CREAT | O_EXCL). The state needs to be versioned.
  1913. // Unfortunately I cannot de/serialize SSL state.
  1914. ctx.polling = true;
  1915. while (ctx.polling)
  1916. poller_run (&ctx.poller);
  1917. bot_context_free (&ctx);
  1918. str_vector_free (&g_original_argv);
  1919. return EXIT_SUCCESS;
  1920. }