plugin_transport_smtp.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2003-2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file transport/plugin_transport_smtp.c
  18. * @brief Implementation of the SMTP transport service
  19. * @author Christian Grothoff
  20. * @author Renaldo Ferreira
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_protocols.h"
  26. #include "gnunet_transport.h"
  27. #include "gnunet_stats_service.h"
  28. #include <libesmtp.h>
  29. #include <signal.h>
  30. /**
  31. * The default maximum size of each outbound SMTP message.
  32. */
  33. #define SMTP_MESSAGE_SIZE 65528
  34. #define DEBUG_SMTP GNUNET_EXTRA_LOGGING
  35. #define FILTER_STRING_SIZE 64
  36. /* how long can a line in base64 encoded
  37. mime text be? (in characters, excluding "\n") */
  38. #define MAX_CHAR_PER_LINE 76
  39. #define EBUF_LEN 128
  40. /**
  41. * Host-Address in a SMTP network.
  42. */
  43. typedef struct
  44. {
  45. /**
  46. * Filter line that every sender must include in the E-mails such
  47. * that the receiver can effectively filter out the GNUnet traffic
  48. * from the E-mail.
  49. */
  50. char filter[FILTER_STRING_SIZE];
  51. /**
  52. * Claimed E-mail address of the sender.
  53. * Format is "foo@bar.com" with null termination, padded to be
  54. * of a multiple of 8 bytes long.
  55. */
  56. char senderAddress[0];
  57. } EmailAddress;
  58. GNUNET_NETWORK_STRUCT_BEGIN
  59. /**
  60. * Encapsulation of a GNUnet message in the SMTP mail body (before
  61. * base64 encoding).
  62. */
  63. typedef struct
  64. {
  65. GNUNET_MessageHeader header;
  66. /**
  67. * What is the identity of the sender (GNUNET_hash of public key)
  68. */
  69. GNUNET_PeerIdentity sender;
  70. } SMTPMessage;
  71. GNUNET_NETWORK_STRUCT_END
  72. /* *********** globals ************* */
  73. /**
  74. * apis (our advertised API and the core api )
  75. */
  76. static GNUNET_CoreAPIForTransport *core_api;
  77. static struct GNUNET_GE_Context *ectx;
  78. /**
  79. * Thread that listens for inbound messages
  80. */
  81. static struct GNUNET_ThreadHandle *dispatchThread;
  82. /**
  83. * Flag to indicate that server has been shut down.
  84. */
  85. static int smtp_shutdown = GNUNET_YES;
  86. /**
  87. * Set to the SMTP server hostname (and port) for outgoing messages.
  88. */
  89. static char *smtp_server_name;
  90. static char *pipename;
  91. /**
  92. * Lock for uses of libesmtp (not thread-safe).
  93. */
  94. static struct GNUNET_Mutex *lock;
  95. /**
  96. * Old handler for SIGPIPE (kept to be able to restore).
  97. */
  98. static struct sigaction old_handler;
  99. static char *email;
  100. static GNUNET_TransportAPI smtpAPI;
  101. static GNUNET_Stats_ServiceAPI *stats;
  102. static int stat_bytesReceived;
  103. static int stat_bytesSent;
  104. static int stat_bytesDropped;
  105. /**
  106. * How many e-mails are we allowed to send per hour?
  107. */
  108. static unsigned long long rate_limit;
  109. static GNUNET_CronTime last_transmission;
  110. /* ********************* the real stuff ******************* */
  111. #define strAUTOncmp(a, b) strncmp (a, b, strlen (b))
  112. /**
  113. * Listen to the pipe, decode messages and send to core.
  114. */
  115. static void *
  116. listenAndDistribute (void *unused)
  117. {
  118. char *line;
  119. unsigned int linesize;
  120. SMTPMessage *mp;
  121. FILE *fdes;
  122. char *retl;
  123. char *out;
  124. unsigned int size;
  125. GNUNET_TransportPacket *coreMP;
  126. int fd;
  127. unsigned int pos;
  128. linesize = ((GNUNET_MAX_BUFFER_SIZE * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2)
  129. / MAX_CHAR_PER_LINE; /* maximum size of a line supported */
  130. line = GNUNET_malloc (linesize + 2); /* 2 bytes for off-by-one errors, just to be safe... */
  131. #define READLINE(l, limit) \
  132. do { retl = fgets (l, (limit), fdes); \
  133. if ((retl == NULL) || (smtp_shutdown == GNUNET_YES)) { \
  134. goto END; \
  135. } \
  136. if (core_api->load_monitor != NULL) \
  137. GNUNET_network_monitor_notify_transmission (core_api->load_monitor, \
  138. GNUNET_ND_DOWNLOAD, \
  139. strlen (retl)); \
  140. } while (0)
  141. while (smtp_shutdown == GNUNET_NO)
  142. {
  143. fd = OPEN (pipename, O_RDONLY | O_ASYNC);
  144. if (fd == -1)
  145. {
  146. if (smtp_shutdown == GNUNET_NO)
  147. GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);
  148. continue;
  149. }
  150. fdes = fdopen (fd, "r");
  151. while (smtp_shutdown == GNUNET_NO)
  152. {
  153. /* skip until end of header */
  154. do
  155. {
  156. READLINE (line, linesize);
  157. }
  158. while ((line[0] != '\r') && (line[0] != '\n')); /* expect newline */
  159. READLINE (line, linesize); /* read base64 encoded message; decode, process */
  160. pos = 0;
  161. while (1)
  162. {
  163. pos = strlen (line) - 1; /* ignore new line */
  164. READLINE (&line[pos], linesize - pos); /* read base64 encoded message; decode, process */
  165. if ((line[pos] == '\r') || (line[pos] == '\n'))
  166. break; /* empty line => end of message! */
  167. }
  168. size = GNUNET_STRINGS_base64_decode (line, pos, &out);
  169. if (size < sizeof(SMTPMessage))
  170. {
  171. GNUNET_GE_BREAK (ectx, 0);
  172. GNUNET_free (out);
  173. goto END;
  174. }
  175. mp = (SMTPMessage *) &out[size - sizeof(SMTPMessage)];
  176. if (ntohs (mp->header.size) != size)
  177. {
  178. GNUNET_GE_LOG (ectx,
  179. GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
  180. _ ("Received malformed message via %s. Ignored.\n"),
  181. "SMTP");
  182. #if DEBUG_SMTP
  183. GNUNET_GE_LOG (ectx,
  184. GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
  185. "Size returned by base64=%d, in the msg=%d.\n", size,
  186. ntohl (mp->size));
  187. #endif
  188. GNUNET_free (out);
  189. goto END;
  190. }
  191. if (stats != NULL)
  192. stats->change (stat_bytesReceived, size);
  193. coreMP = GNUNET_new (GNUNET_TransportPacket);
  194. coreMP->msg = out;
  195. coreMP->size = size - sizeof(SMTPMessage);
  196. coreMP->tsession = NULL;
  197. coreMP->sender = mp->sender;
  198. #if DEBUG_SMTP
  199. GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
  200. "SMTP message passed to the core.\n");
  201. #endif
  202. core_api->receive (coreMP);
  203. }
  204. END:
  205. #if DEBUG_SMTP
  206. GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
  207. "SMTP message processed.\n");
  208. #endif
  209. if (fdes != NULL)
  210. fclose (fdes);
  211. }
  212. GNUNET_free (line);
  213. return NULL;
  214. }
  215. /* *************** API implementation *************** */
  216. /**
  217. * Verify that a hello-Message is correct (a node is reachable at that
  218. * address). Since the reply will be asynchronous, a method must be
  219. * called on success.
  220. *
  221. * @param hello the hello message to verify
  222. * (the signature/crc have been verified before)
  223. * @return GNUNET_OK on success, GNUNET_SYSERR on error
  224. */
  225. static int
  226. api_verify_hello (const GNUNET_MessageHello *hello)
  227. {
  228. const EmailAddress *maddr;
  229. maddr = (const EmailAddress *) &hello[1];
  230. if ((ntohs (hello->header.size) !=
  231. sizeof(GNUNET_MessageHello) + ntohs (hello->senderAddressSize)) ||
  232. (maddr->senderAddress
  233. [ntohs (hello->senderAddressSize) - 1 - FILTER_STRING_SIZE] != '\0'))
  234. {
  235. GNUNET_GE_BREAK (ectx, 0);
  236. return GNUNET_SYSERR; /* obviously invalid */
  237. }
  238. if (NULL == strstr (maddr->filter, ": "))
  239. return GNUNET_SYSERR;
  240. return GNUNET_OK;
  241. }
  242. /**
  243. * Create a hello-Message for the current node. The hello is created
  244. * without signature and without a timestamp. The GNUnet core will
  245. * GNUNET_RSA_sign the message and add an expiration time.
  246. *
  247. * @return hello on success, NULL on error
  248. */
  249. static GNUNET_MessageHello *
  250. api_create_hello ()
  251. {
  252. GNUNET_MessageHello *msg;
  253. char *filter;
  254. EmailAddress *haddr;
  255. int i;
  256. GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "FILTER",
  257. "X-mailer: GNUnet", &filter);
  258. if (NULL == strstr (filter, ": "))
  259. {
  260. GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
  261. _ ("SMTP filter string to invalid, lacks ': '\n"));
  262. GNUNET_free (filter);
  263. return NULL;
  264. }
  265. if (strlen (filter) > FILTER_STRING_SIZE)
  266. {
  267. filter[FILTER_STRING_SIZE] = '\0';
  268. GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
  269. _ ("SMTP filter string to long, capped to `%s'\n"), filter);
  270. }
  271. i = (strlen (email) + 8) & (~7); /* make multiple of 8 */
  272. msg =
  273. GNUNET_malloc (sizeof(GNUNET_MessageHello) + sizeof(EmailAddress) + i);
  274. memset (msg, 0, sizeof(GNUNET_MessageHello) + sizeof(EmailAddress) + i);
  275. haddr = (EmailAddress *) &msg[1];
  276. memset (&haddr->filter[0], 0, FILTER_STRING_SIZE);
  277. strcpy (&haddr->filter[0], filter);
  278. GNUNET_memcpy (&haddr->senderAddress[0], email, strlen (email) + 1);
  279. msg->senderAddressSize = htons (strlen (email) + 1 + sizeof(EmailAddress));
  280. msg->protocol = htons (GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP);
  281. msg->MTU = htonl (smtpAPI.mtu);
  282. msg->header.size = htons (GNUNET_sizeof_hello (msg));
  283. if (api_verify_hello (msg) == GNUNET_SYSERR)
  284. GNUNET_GE_ASSERT (ectx, 0);
  285. GNUNET_free (filter);
  286. return msg;
  287. }
  288. struct GetMessageClosure
  289. {
  290. unsigned int esize;
  291. unsigned int pos;
  292. char *ebody;
  293. };
  294. static const char *
  295. get_message (void **buf, int *len, void *cls)
  296. {
  297. struct GetMessageClosure *gmc = cls;
  298. *buf = NULL;
  299. if (len == NULL)
  300. {
  301. gmc->pos = 0;
  302. return NULL;
  303. }
  304. if (gmc->pos == gmc->esize)
  305. return NULL; /* done */
  306. *len = gmc->esize;
  307. gmc->pos = gmc->esize;
  308. return gmc->ebody;
  309. }
  310. /**
  311. * Send a message to the specified remote node.
  312. *
  313. * @param tsession the GNUNET_MessageHello identifying the remote node
  314. * @param msg what to send
  315. * @param size the size of the message
  316. * @param important is this message important enough to override typical limits?
  317. * @return GNUNET_SYSERR on error, GNUNET_OK on success
  318. */
  319. static int
  320. api_send (GNUNET_TSession *tsession, const void *msg, const unsigned int size,
  321. int important)
  322. {
  323. const GNUNET_MessageHello *hello;
  324. const EmailAddress *haddr;
  325. char *m;
  326. char *filter;
  327. char *fvalue;
  328. SMTPMessage *mp;
  329. struct GetMessageClosure gm_cls;
  330. smtp_session_t session;
  331. smtp_message_t message;
  332. smtp_recipient_t recipient;
  333. #define EBUF_LEN 128
  334. char ebuf[EBUF_LEN];
  335. GNUNET_CronTime now;
  336. if (smtp_shutdown == GNUNET_YES)
  337. return GNUNET_SYSERR;
  338. if ((size == 0) || (size > smtpAPI.mtu))
  339. {
  340. GNUNET_GE_BREAK (ectx, 0);
  341. return GNUNET_SYSERR;
  342. }
  343. now = GNUNET_get_time ();
  344. if ((important != GNUNET_YES) &&
  345. ( ((now - last_transmission) * rate_limit) < GNUNET_CRON_HOURS) )
  346. return GNUNET_NO; /* rate too high */
  347. last_transmission = now;
  348. hello = (const GNUNET_MessageHello *) tsession->internal;
  349. if (hello == NULL)
  350. return GNUNET_SYSERR;
  351. GNUNET_mutex_lock (lock);
  352. session = smtp_create_session ();
  353. if (session == NULL)
  354. {
  355. GNUNET_GE_LOG (ectx,
  356. GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER
  357. | GNUNET_GE_IMMEDIATE, _ ("SMTP: `%s' failed: %s.\n"),
  358. "smtp_create_session", smtp_strerror (smtp_errno (), ebuf,
  359. EBUF_LEN));
  360. GNUNET_mutex_unlock (lock);
  361. return GNUNET_SYSERR;
  362. }
  363. if (0 == smtp_set_server (session, smtp_server_name))
  364. {
  365. GNUNET_GE_LOG (ectx,
  366. GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER
  367. | GNUNET_GE_IMMEDIATE, _ ("SMTP: `%s' failed: %s.\n"),
  368. "smtp_set_server", smtp_strerror (smtp_errno (), ebuf,
  369. EBUF_LEN));
  370. smtp_destroy_session (session);
  371. GNUNET_mutex_unlock (lock);
  372. return GNUNET_SYSERR;
  373. }
  374. haddr = (const EmailAddress *) &hello[1];
  375. message = smtp_add_message (session);
  376. if (message == NULL)
  377. {
  378. GNUNET_GE_LOG (ectx,
  379. GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
  380. | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
  381. "smtp_add_message", smtp_strerror (smtp_errno (), ebuf,
  382. EBUF_LEN));
  383. smtp_destroy_session (session);
  384. GNUNET_mutex_unlock (lock);
  385. return GNUNET_SYSERR;
  386. }
  387. smtp_set_header (message, "To", NULL, haddr->senderAddress);
  388. smtp_set_header (message, "From", NULL, email);
  389. filter = GNUNET_strdup (haddr->filter);
  390. fvalue = strstr (filter, ": ");
  391. GNUNET_GE_ASSERT (NULL, NULL != fvalue);
  392. fvalue[0] = '\0';
  393. fvalue += 2;
  394. if (0 == smtp_set_header (message, filter, fvalue))
  395. {
  396. GNUNET_GE_LOG (ectx,
  397. GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
  398. | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
  399. "smtp_set_header", smtp_strerror (smtp_errno (), ebuf,
  400. EBUF_LEN));
  401. smtp_destroy_session (session);
  402. GNUNET_mutex_unlock (lock);
  403. GNUNET_free (filter);
  404. return GNUNET_SYSERR;
  405. }
  406. GNUNET_free (filter);
  407. m = GNUNET_malloc (size + sizeof(SMTPMessage));
  408. GNUNET_memcpy (m, msg, size);
  409. mp = (SMTPMessage *) &m[size];
  410. mp->header.size = htons (size + sizeof(SMTPMessage));
  411. mp->header.type = htons (0);
  412. mp->sender = *core_api->my_identity;
  413. gm_cls.ebody = NULL;
  414. gm_cls.pos = 0;
  415. gm_cls.esize = GNUNET_STRINGS_base64_encode (m, size + sizeof(SMTPMessage),
  416. &gm_cls.ebody);
  417. GNUNET_free (m);
  418. if (0 == smtp_size_set_estimate (message, gm_cls.esize))
  419. {
  420. GNUNET_GE_LOG (ectx,
  421. GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
  422. | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
  423. "smtp_size_set_estimate", smtp_strerror (smtp_errno (), ebuf,
  424. EBUF_LEN));
  425. }
  426. if (0 == smtp_set_messagecb (message, &get_message, &gm_cls))
  427. {
  428. GNUNET_GE_LOG (ectx,
  429. GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
  430. | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
  431. "smtp_set_messagecb", smtp_strerror (smtp_errno (), ebuf,
  432. EBUF_LEN));
  433. smtp_destroy_session (session);
  434. GNUNET_mutex_unlock (lock);
  435. GNUNET_free (gm_cls.ebody);
  436. return GNUNET_SYSERR;
  437. }
  438. recipient = smtp_add_recipient (message, haddr->senderAddress);
  439. if (recipient == NULL)
  440. {
  441. GNUNET_GE_LOG (ectx,
  442. GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
  443. | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
  444. "smtp_add_recipient", smtp_strerror (smtp_errno (), ebuf,
  445. EBUF_LEN));
  446. smtp_destroy_session (session);
  447. GNUNET_mutex_unlock (lock);
  448. return GNUNET_SYSERR;
  449. }
  450. if (0 == smtp_start_session (session))
  451. {
  452. GNUNET_GE_LOG (ectx,
  453. GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
  454. | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
  455. "smtp_start_session", smtp_strerror (smtp_errno (), ebuf,
  456. EBUF_LEN));
  457. smtp_destroy_session (session);
  458. GNUNET_mutex_unlock (lock);
  459. GNUNET_free (gm_cls.ebody);
  460. return GNUNET_SYSERR;
  461. }
  462. if (stats != NULL)
  463. stats->change (stat_bytesSent, size);
  464. if (core_api->load_monitor != NULL)
  465. GNUNET_network_monitor_notify_transmission (core_api->load_monitor,
  466. GNUNET_ND_UPLOAD, gm_cls.esize);
  467. smtp_message_reset_status (message); /* this is needed to plug a 28-byte/message memory leak in libesmtp */
  468. smtp_destroy_session (session);
  469. GNUNET_mutex_unlock (lock);
  470. GNUNET_free (gm_cls.ebody);
  471. return GNUNET_OK;
  472. }
  473. /**
  474. * Establish a connection to a remote node.
  475. * @param hello the hello-Message for the target node
  476. * @param tsessionPtr the session handle that is to be set
  477. * @param may_reuse can we re-use an existing connection?
  478. * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
  479. */
  480. static int
  481. api_connect (const GNUNET_MessageHello *hello, GNUNET_TSession **tsessionPtr,
  482. int may_reuse)
  483. {
  484. GNUNET_TSession *tsession;
  485. tsession = GNUNET_new (GNUNET_TSession);
  486. tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello));
  487. tsession->peer = hello->senderIdentity;
  488. GNUNET_memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello));
  489. tsession->ttype = smtpAPI.protocol_number;
  490. (*tsessionPtr) = tsession;
  491. return GNUNET_OK;
  492. }
  493. /**
  494. * Disconnect from a remote node.
  495. *
  496. * @param tsession the session that is closed
  497. * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
  498. */
  499. static int
  500. api_disconnect (GNUNET_TSession *tsession)
  501. {
  502. if (tsession != NULL)
  503. {
  504. if (tsession->internal != NULL)
  505. GNUNET_free (tsession->internal);
  506. GNUNET_free (tsession);
  507. }
  508. return GNUNET_OK;
  509. }
  510. /**
  511. * Start the server process to receive inbound traffic.
  512. * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
  513. */
  514. static int
  515. api_start_transport_server ()
  516. {
  517. smtp_shutdown = GNUNET_NO;
  518. /* initialize SMTP network */
  519. dispatchThread = GNUNET_thread_create (&listenAndDistribute, NULL, 1024 * 4);
  520. if (dispatchThread == NULL)
  521. {
  522. GNUNET_GE_DIE_STRERROR (ectx,
  523. GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
  524. "pthread_create");
  525. return GNUNET_SYSERR;
  526. }
  527. return GNUNET_OK;
  528. }
  529. /**
  530. * Shutdown the server process (stop receiving inbound traffic). Maybe
  531. * restarted later!
  532. */
  533. static int
  534. api_stop_transport_server ()
  535. {
  536. void *unused;
  537. smtp_shutdown = GNUNET_YES;
  538. GNUNET_thread_stop_sleep (dispatchThread);
  539. GNUNET_thread_join (dispatchThread, &unused);
  540. return GNUNET_OK;
  541. }
  542. /**
  543. * Convert SMTP hello to an IP address (always fails).
  544. */
  545. static int
  546. api_hello_to_address (const GNUNET_MessageHello *hello, void **sa,
  547. unsigned int *sa_len)
  548. {
  549. return GNUNET_SYSERR;
  550. }
  551. /**
  552. * Always fails.
  553. */
  554. static int
  555. api_associate (GNUNET_TSession *tsession)
  556. {
  557. return GNUNET_SYSERR; /* SMTP connections can never be associated */
  558. }
  559. /**
  560. * Always succeeds (for now; we should look at adding
  561. * frequency limits to SMTP in the future!).
  562. */
  563. static int
  564. api_test_would_try (GNUNET_TSession *tsession, unsigned int size,
  565. int important)
  566. {
  567. return GNUNET_OK; /* we always try... */
  568. }
  569. /**
  570. * The exported method. Makes the core api available via a global and
  571. * returns the smtp transport API.
  572. */
  573. GNUNET_TransportAPI *
  574. inittransport_smtp (struct GNUNET_CoreAPIForTransport *core)
  575. {
  576. unsigned long long mtu;
  577. struct sigaction sa;
  578. core_api = core;
  579. ectx = core->ectx;
  580. if (! GNUNET_GC_have_configuration_value (core_api->cfg, "SMTP", "EMAIL"))
  581. {
  582. GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
  583. _
  584. (
  585. "No email-address specified, can not start SMTP transport.\n"));
  586. return NULL;
  587. }
  588. GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "MTU", 1200,
  589. SMTP_MESSAGE_SIZE,
  590. SMTP_MESSAGE_SIZE, &mtu);
  591. GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "RATELIMIT",
  592. 0, 0, 1024 * 1024, &rate_limit);
  593. stats = core_api->service_request ("stats");
  594. if (stats != NULL)
  595. {
  596. stat_bytesReceived =
  597. stats->create (gettext_noop ("# bytes received via SMTP"));
  598. stat_bytesSent = stats->create (gettext_noop ("# bytes sent via SMTP"));
  599. stat_bytesDropped =
  600. stats->create (gettext_noop ("# bytes dropped by SMTP (outgoing)"));
  601. }
  602. GNUNET_GC_get_configuration_value_filename (core_api->cfg, "SMTP", "PIPE",
  603. &pipename);
  604. unlink (pipename);
  605. if (0 != mkfifo (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
  606. {
  607. GNUNET_GE_LOG_STRERROR (ectx,
  608. GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
  609. "mkfifo");
  610. GNUNET_free (pipename);
  611. core_api->service_release (stats);
  612. stats = NULL;
  613. return NULL;
  614. }
  615. /* we need to allow the mailer program to send us messages;
  616. * easiest done by giving it write permissions (see Mantis #1142) */
  617. if (0 != chmod (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
  618. GNUNET_GE_LOG_STRERROR (ectx,
  619. GNUNET_GE_ADMIN | GNUNET_GE_BULK
  620. | GNUNET_GE_WARNING, "chmod");
  621. GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "EMAIL",
  622. NULL,
  623. &email);
  624. lock = GNUNET_mutex_create (GNUNET_NO);
  625. GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "SERVER",
  626. "localhost:25", &smtp_server_name);
  627. sa.sa_handler = SIG_IGN;
  628. sigemptyset (&sa.sa_mask);
  629. sa.sa_flags = 0;
  630. sigaction (SIGPIPE, &sa, &old_handler);
  631. smtpAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP;
  632. smtpAPI.mtu = mtu - sizeof(SMTPMessage);
  633. smtpAPI.cost = 50;
  634. smtpAPI.hello_verify = &api_verify_hello;
  635. smtpAPI.hello_create = &api_create_hello;
  636. smtpAPI.connect = &api_connect;
  637. smtpAPI.send = &api_send;
  638. smtpAPI.associate = &api_associate;
  639. smtpAPI.disconnect = &api_disconnect;
  640. smtpAPI.server_start = &api_start_transport_server;
  641. smtpAPI.server_stop = &api_stop_transport_server;
  642. smtpAPI.hello_to_address = &api_hello_to_address;
  643. smtpAPI.send_now_test = &api_test_would_try;
  644. return &smtpAPI;
  645. }
  646. void
  647. donetransport_smtp ()
  648. {
  649. sigaction (SIGPIPE, &old_handler, NULL);
  650. GNUNET_free (smtp_server_name);
  651. if (stats != NULL)
  652. {
  653. core_api->service_release (stats);
  654. stats = NULL;
  655. }
  656. GNUNET_mutex_destroy (lock);
  657. lock = NULL;
  658. unlink (pipename);
  659. GNUNET_free (pipename);
  660. pipename = NULL;
  661. GNUNET_free (email);
  662. email = NULL;
  663. }
  664. /* end of smtp.c */