aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_smtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/plugin_transport_smtp.c')
-rw-r--r--src/transport/plugin_transport_smtp.c906
1 files changed, 906 insertions, 0 deletions
diff --git a/src/transport/plugin_transport_smtp.c b/src/transport/plugin_transport_smtp.c
new file mode 100644
index 000000000..f7cc530e4
--- /dev/null
+++ b/src/transport/plugin_transport_smtp.c
@@ -0,0 +1,906 @@
1/*
2 This file is part of GNUnet
3 (C) 2003, 2004, 2005, 2006, 2007 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file transports/smtp.c
23 * @brief Implementation of the SMTP transport service
24 * @author Christian Grothoff
25 * @author Renaldo Ferreira
26 */
27
28#include "platform.h"
29#include "gnunet_util.h"
30#include "gnunet_directories.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport.h"
33#include "gnunet_stats_service.h"
34#include <libesmtp.h>
35#include <signal.h>
36
37
38/**
39 * The default maximum size of each outbound SMTP message.
40 */
41#define SMTP_MESSAGE_SIZE 65528
42
43#define DEBUG_SMTP GNUNET_NO
44
45#define FILTER_STRING_SIZE 64
46
47/* how long can a line in base64 encoded
48 mime text be? (in characters, excluding "\n") */
49#define MAX_CHAR_PER_LINE 76
50
51#define EBUF_LEN 128
52
53/**
54 * Host-Address in a SMTP network.
55 */
56typedef struct
57{
58
59 /**
60 * Filter line that every sender must include in the E-mails such
61 * that the receiver can effectively filter out the GNUnet traffic
62 * from the E-mail.
63 */
64 char filter[FILTER_STRING_SIZE];
65
66 /**
67 * Claimed E-mail address of the sender.
68 * Format is "foo@bar.com" with null termination, padded to be
69 * of a multiple of 8 bytes long.
70 */
71 char senderAddress[0];
72
73} EmailAddress;
74
75/**
76 * Encapsulation of a GNUnet message in the SMTP mail body (before
77 * base64 encoding).
78 */
79typedef struct
80{
81 GNUNET_MessageHeader header;
82
83 /**
84 * What is the identity of the sender (GNUNET_hash of public key)
85 */
86 GNUNET_PeerIdentity sender;
87
88} SMTPMessage;
89
90/* *********** globals ************* */
91
92/**
93 * apis (our advertised API and the core api )
94 */
95static GNUNET_CoreAPIForTransport *coreAPI;
96
97static struct GNUNET_GE_Context *ectx;
98
99/**
100 * Thread that listens for inbound messages
101 */
102static struct GNUNET_ThreadHandle *dispatchThread;
103
104/**
105 * Flag to indicate that server has been shut down.
106 */
107static int smtp_shutdown = GNUNET_YES;
108
109/**
110 * Set to the SMTP server hostname (and port) for outgoing messages.
111 */
112static char *smtp_server_name;
113
114static char *pipename;
115
116/**
117 * Lock for uses of libesmtp (not thread-safe).
118 */
119static struct GNUNET_Mutex *lock;
120
121/**
122 * Old handler for SIGPIPE (kept to be able to restore).
123 */
124static struct sigaction old_handler;
125
126static char *email;
127
128static GNUNET_TransportAPI smtpAPI;
129
130static GNUNET_Stats_ServiceAPI *stats;
131
132static int stat_bytesReceived;
133
134static int stat_bytesSent;
135
136static int stat_bytesDropped;
137
138/**
139 * How many e-mails are we allowed to send per hour?
140 */
141static unsigned long long rate_limit;
142
143static GNUNET_CronTime last_transmission;
144
145/** ******************** Base64 encoding ***********/
146
147#define FILLCHAR '='
148static char *cvt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
149 "abcdefghijklmnopqrstuvwxyz" "0123456789+/";
150
151/**
152 * Encode into Base64.
153 *
154 * @param data the data to encode
155 * @param len the length of the input
156 * @param output where to write the output (*output should be NULL,
157 * is allocated)
158 * @return the size of the output
159 */
160static unsigned int
161base64_encode (const char *data, unsigned int len, char **output)
162{
163 unsigned int i;
164 char c;
165 unsigned int ret;
166 char *opt;
167
168/* (*output)[ret++] = '\r'; \*/
169#define CHECKLINE \
170 if ( (ret % MAX_CHAR_PER_LINE) == 0) { \
171 (*output)[ret++] = '\n'; \
172 }
173 ret = 0;
174 opt = GNUNET_malloc (2 + (((len * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2)) /
175 MAX_CHAR_PER_LINE);
176 /* message must start with \r\n for libesmtp */
177 *output = opt;
178 opt[0] = '\r';
179 opt[1] = '\n';
180 ret += 2;
181 for (i = 0; i < len; ++i)
182 {
183 c = (data[i] >> 2) & 0x3f;
184 opt[ret++] = cvt[(int) c];
185 CHECKLINE;
186 c = (data[i] << 4) & 0x3f;
187 if (++i < len)
188 c |= (data[i] >> 4) & 0x0f;
189 opt[ret++] = cvt[(int) c];
190 CHECKLINE;
191 if (i < len)
192 {
193 c = (data[i] << 2) & 0x3f;
194 if (++i < len)
195 c |= (data[i] >> 6) & 0x03;
196 opt[ret++] = cvt[(int) c];
197 CHECKLINE;
198 }
199 else
200 {
201 ++i;
202 opt[ret++] = FILLCHAR;
203 CHECKLINE;
204 }
205 if (i < len)
206 {
207 c = data[i] & 0x3f;
208 opt[ret++] = cvt[(int) c];
209 CHECKLINE;
210 }
211 else
212 {
213 opt[ret++] = FILLCHAR;
214 CHECKLINE;
215 }
216 }
217 opt[ret++] = FILLCHAR;
218 return ret;
219}
220
221#define cvtfind(a)( (((a) >= 'A')&&((a) <= 'Z'))? (a)-'A'\
222 :(((a)>='a')&&((a)<='z')) ? (a)-'a'+26\
223 :(((a)>='0')&&((a)<='9')) ? (a)-'0'+52\
224 :((a) == '+') ? 62\
225 :((a) == '/') ? 63 : -1)
226/**
227 * Decode from Base64.
228 *
229 * @param data the data to encode
230 * @param len the length of the input
231 * @param output where to write the output (*output should be NULL,
232 * is allocated)
233 * @return the size of the output
234 */
235static unsigned int
236base64_decode (const char *data, unsigned int len, char **output)
237{
238 unsigned int i;
239 char c;
240 char c1;
241 unsigned int ret = 0;
242
243#define CHECK_CRLF while (data[i] == '\r' || data[i] == '\n') {\
244 GNUNET_GE_LOG(ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "ignoring CR/LF\n"); \
245 i++; \
246 if (i >= len) goto END; \
247 }
248
249 *output = GNUNET_malloc ((len * 3 / 4) + 8);
250#if DEBUG_SMTP
251 GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
252 "base64_decode decoding len=%d\n", len);
253#endif
254 for (i = 0; i < len; ++i)
255 {
256 CHECK_CRLF;
257 if (data[i] == FILLCHAR)
258 break;
259 c = (char) cvtfind (data[i]);
260 ++i;
261 CHECK_CRLF;
262 c1 = (char) cvtfind (data[i]);
263 c = (c << 2) | ((c1 >> 4) & 0x3);
264 (*output)[ret++] = c;
265 if (++i < len)
266 {
267 CHECK_CRLF;
268 c = data[i];
269 if (FILLCHAR == c)
270 break;
271 c = (char) cvtfind (c);
272 c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
273 (*output)[ret++] = c1;
274 }
275 if (++i < len)
276 {
277 CHECK_CRLF;
278 c1 = data[i];
279 if (FILLCHAR == c1)
280 break;
281
282 c1 = (char) cvtfind (c1);
283 c = ((c << 6) & 0xc0) | c1;
284 (*output)[ret++] = c;
285 }
286 }
287END:
288 return ret;
289}
290
291/* ********************* the real stuff ******************* */
292
293#define strAUTOncmp(a,b) strncmp(a,b,strlen(b))
294
295/**
296 * Listen to the pipe, decode messages and send to core.
297 */
298static void *
299listenAndDistribute (void *unused)
300{
301 char *line;
302 unsigned int linesize;
303 SMTPMessage *mp;
304 FILE *fdes;
305 char *retl;
306 char *out;
307 unsigned int size;
308 GNUNET_TransportPacket *coreMP;
309 int fd;
310 unsigned int pos;
311
312 linesize = ((GNUNET_MAX_BUFFER_SIZE * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2) / MAX_CHAR_PER_LINE; /* maximum size of a line supported */
313 line = GNUNET_malloc (linesize + 2); /* 2 bytes for off-by-one errors, just to be safe... */
314
315#define READLINE(l,limit) \
316 do { retl = fgets(l, (limit), fdes); \
317 if ( (retl == NULL) || (smtp_shutdown == GNUNET_YES)) {\
318 goto END; \
319 }\
320 if (coreAPI->load_monitor != NULL) \
321 GNUNET_network_monitor_notify_transmission(coreAPI->load_monitor, GNUNET_ND_DOWNLOAD, strlen(retl)); \
322 } while (0)
323
324
325 while (smtp_shutdown == GNUNET_NO)
326 {
327 fd = OPEN (pipename, O_RDONLY | O_ASYNC);
328 if (fd == -1)
329 {
330 if (smtp_shutdown == GNUNET_NO)
331 GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);
332 continue;
333 }
334 fdes = fdopen (fd, "r");
335 while (smtp_shutdown == GNUNET_NO)
336 {
337 /* skip until end of header */
338 do
339 {
340 READLINE (line, linesize);
341 }
342 while ((line[0] != '\r') && (line[0] != '\n')); /* expect newline */
343 READLINE (line, linesize); /* read base64 encoded message; decode, process */
344 pos = 0;
345 while (1)
346 {
347 pos = strlen (line) - 1; /* ignore new line */
348 READLINE (&line[pos], linesize - pos); /* read base64 encoded message; decode, process */
349 if ((line[pos] == '\r') || (line[pos] == '\n'))
350 break; /* empty line => end of message! */
351 }
352 size = base64_decode (line, pos, &out);
353 if (size < sizeof (SMTPMessage))
354 {
355 GNUNET_GE_BREAK (ectx, 0);
356 GNUNET_free (out);
357 goto END;
358 }
359
360 mp = (SMTPMessage *) & out[size - sizeof (SMTPMessage)];
361 if (ntohs (mp->header.size) != size)
362 {
363 GNUNET_GE_LOG (ectx,
364 GNUNET_GE_WARNING | GNUNET_GE_BULK |
365 GNUNET_GE_USER,
366 _
367 ("Received malformed message via %s. Ignored.\n"),
368 "SMTP");
369#if DEBUG_SMTP
370 GNUNET_GE_LOG (ectx,
371 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST |
372 GNUNET_GE_USER,
373 "Size returned by base64=%d, in the msg=%d.\n",
374 size, ntohl (mp->size));
375#endif
376 GNUNET_free (out);
377 goto END;
378 }
379 if (stats != NULL)
380 stats->change (stat_bytesReceived, size);
381 coreMP = GNUNET_malloc (sizeof (GNUNET_TransportPacket));
382 coreMP->msg = out;
383 coreMP->size = size - sizeof (SMTPMessage);
384 coreMP->tsession = NULL;
385 coreMP->sender = mp->sender;
386#if DEBUG_SMTP
387 GNUNET_GE_LOG (ectx,
388 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
389 "SMTP message passed to the core.\n");
390#endif
391
392 coreAPI->receive (coreMP);
393 }
394 END:
395#if DEBUG_SMTP
396 GNUNET_GE_LOG (ectx,
397 GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
398 "SMTP message processed.\n");
399#endif
400 if (fdes != NULL)
401 fclose (fdes);
402 }
403 GNUNET_free (line);
404 return NULL;
405}
406
407/* *************** API implementation *************** */
408
409/**
410 * Verify that a hello-Message is correct (a node is reachable at that
411 * address). Since the reply will be asynchronous, a method must be
412 * called on success.
413 *
414 * @param hello the hello message to verify
415 * (the signature/crc have been verified before)
416 * @return GNUNET_OK on success, GNUNET_SYSERR on error
417 */
418static int
419api_verify_hello (const GNUNET_MessageHello * hello)
420{
421 const EmailAddress *maddr;
422
423 maddr = (const EmailAddress *) &hello[1];
424 if ((ntohs (hello->header.size) !=
425 sizeof (GNUNET_MessageHello) + ntohs (hello->senderAddressSize)) ||
426 (maddr->senderAddress[ntohs (hello->senderAddressSize) - 1 -
427 FILTER_STRING_SIZE] != '\0'))
428 {
429 GNUNET_GE_BREAK (ectx, 0);
430 return GNUNET_SYSERR; /* obviously invalid */
431 }
432 if (NULL == strstr (maddr->filter, ": "))
433 return GNUNET_SYSERR;
434 return GNUNET_OK;
435}
436
437/**
438 * Create a hello-Message for the current node. The hello is created
439 * without signature and without a timestamp. The GNUnet core will
440 * GNUNET_RSA_sign the message and add an expiration time.
441 *
442 * @return hello on success, NULL on error
443 */
444static GNUNET_MessageHello *
445api_create_hello ()
446{
447 GNUNET_MessageHello *msg;
448 char *filter;
449 EmailAddress *haddr;
450 int i;
451
452 GNUNET_GC_get_configuration_value_string (coreAPI->cfg,
453 "SMTP", "FILTER",
454 "X-mailer: GNUnet", &filter);
455 if (NULL == strstr (filter, ": "))
456 {
457 GNUNET_GE_LOG (ectx,
458 GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
459 _("SMTP filter string to invalid, lacks ': '\n"));
460 GNUNET_free (filter);
461 return NULL;
462 }
463
464 if (strlen (filter) > FILTER_STRING_SIZE)
465 {
466 filter[FILTER_STRING_SIZE] = '\0';
467 GNUNET_GE_LOG (ectx,
468 GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
469 _("SMTP filter string to long, capped to `%s'\n"),
470 filter);
471 }
472 i = (strlen (email) + 8) & (~7); /* make multiple of 8 */
473 msg =
474 GNUNET_malloc (sizeof (GNUNET_MessageHello) + sizeof (EmailAddress) + i);
475 memset (msg, 0, sizeof (GNUNET_MessageHello) + sizeof (EmailAddress) + i);
476 haddr = (EmailAddress *) & msg[1];
477 memset (&haddr->filter[0], 0, FILTER_STRING_SIZE);
478 strcpy (&haddr->filter[0], filter);
479 memcpy (&haddr->senderAddress[0], email, strlen (email) + 1);
480 msg->senderAddressSize = htons (strlen (email) + 1 + sizeof (EmailAddress));
481 msg->protocol = htons (GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP);
482 msg->MTU = htonl (smtpAPI.mtu);
483 msg->header.size = htons (GNUNET_sizeof_hello (msg));
484 if (api_verify_hello (msg) == GNUNET_SYSERR)
485 GNUNET_GE_ASSERT (ectx, 0);
486 GNUNET_free (filter);
487 return msg;
488}
489
490struct GetMessageClosure
491{
492 unsigned int esize;
493 unsigned int pos;
494 char *ebody;
495};
496
497static const char *
498get_message (void **buf, int *len, void *cls)
499{
500 struct GetMessageClosure *gmc = cls;
501
502 *buf = NULL;
503 if (len == NULL)
504 {
505 gmc->pos = 0;
506 return NULL;
507 }
508 if (gmc->pos == gmc->esize)
509 return NULL; /* done */
510 *len = gmc->esize;
511 gmc->pos = gmc->esize;
512 return gmc->ebody;
513}
514
515/**
516 * Send a message to the specified remote node.
517 *
518 * @param tsession the GNUNET_MessageHello identifying the remote node
519 * @param message what to send
520 * @param size the size of the message
521 * @return GNUNET_SYSERR on error, GNUNET_OK on success
522 */
523static int
524api_send (GNUNET_TSession * tsession,
525 const void *msg, const unsigned int size, int important)
526{
527 const GNUNET_MessageHello *hello;
528 const EmailAddress *haddr;
529 char *m;
530 char *filter;
531 char *fvalue;
532 SMTPMessage *mp;
533 struct GetMessageClosure gm_cls;
534 smtp_session_t session;
535 smtp_message_t message;
536 smtp_recipient_t recipient;
537#define EBUF_LEN 128
538 char ebuf[EBUF_LEN];
539 GNUNET_CronTime now;
540
541 if (smtp_shutdown == GNUNET_YES)
542 return GNUNET_SYSERR;
543 if ((size == 0) || (size > smtpAPI.mtu))
544 {
545 GNUNET_GE_BREAK (ectx, 0);
546 return GNUNET_SYSERR;
547 }
548 now = GNUNET_get_time ();
549 if ((important != GNUNET_YES) &&
550 ((now - last_transmission) * rate_limit) < GNUNET_CRON_HOURS)
551 return GNUNET_NO; /* rate too high */
552 last_transmission = now;
553
554 hello = (const GNUNET_MessageHello *) tsession->internal;
555 if (hello == NULL)
556 return GNUNET_SYSERR;
557 GNUNET_mutex_lock (lock);
558 session = smtp_create_session ();
559 if (session == NULL)
560 {
561 GNUNET_GE_LOG (ectx,
562 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER |
563 GNUNET_GE_IMMEDIATE,
564 _("SMTP: `%s' failed: %s.\n"),
565 "smtp_create_session",
566 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
567 GNUNET_mutex_unlock (lock);
568 return GNUNET_SYSERR;
569 }
570 if (0 == smtp_set_server (session, smtp_server_name))
571 {
572 GNUNET_GE_LOG (ectx,
573 GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER |
574 GNUNET_GE_IMMEDIATE,
575 _("SMTP: `%s' failed: %s.\n"),
576 "smtp_set_server",
577 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
578 smtp_destroy_session (session);
579 GNUNET_mutex_unlock (lock);
580 return GNUNET_SYSERR;
581 }
582 haddr = (const EmailAddress *) &hello[1];
583 message = smtp_add_message (session);
584 if (message == NULL)
585 {
586 GNUNET_GE_LOG (ectx,
587 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
588 GNUNET_GE_BULK,
589 _("SMTP: `%s' failed: %s.\n"),
590 "smtp_add_message",
591 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
592 smtp_destroy_session (session);
593 GNUNET_mutex_unlock (lock);
594 return GNUNET_SYSERR;
595 }
596 smtp_set_header (message, "To", NULL, haddr->senderAddress);
597 smtp_set_header (message, "From", NULL, email);
598
599 filter = GNUNET_strdup (haddr->filter);
600 fvalue = strstr (filter, ": ");
601 GNUNET_GE_ASSERT (NULL, NULL != fvalue);
602 fvalue[0] = '\0';
603 fvalue += 2;
604 if (0 == smtp_set_header (message, filter, fvalue))
605 {
606 GNUNET_GE_LOG (ectx,
607 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
608 GNUNET_GE_BULK,
609 _("SMTP: `%s' failed: %s.\n"),
610 "smtp_set_header",
611 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
612 smtp_destroy_session (session);
613 GNUNET_mutex_unlock (lock);
614 GNUNET_free (filter);
615 return GNUNET_SYSERR;
616 }
617 GNUNET_free (filter);
618 m = GNUNET_malloc (size + sizeof (SMTPMessage));
619 memcpy (m, msg, size);
620 mp = (SMTPMessage *) & m[size];
621 mp->header.size = htons (size + sizeof (SMTPMessage));
622 mp->header.type = htons (0);
623 mp->sender = *coreAPI->my_identity;
624 gm_cls.ebody = NULL;
625 gm_cls.pos = 0;
626 gm_cls.esize =
627 base64_encode (m, size + sizeof (SMTPMessage), &gm_cls.ebody);
628 GNUNET_free (m);
629 if (0 == smtp_size_set_estimate (message, gm_cls.esize))
630 {
631 GNUNET_GE_LOG (ectx,
632 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
633 GNUNET_GE_BULK,
634 _("SMTP: `%s' failed: %s.\n"),
635 "smtp_size_set_estimate",
636 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
637 }
638 if (0 == smtp_set_messagecb (message, &get_message, &gm_cls))
639 {
640 GNUNET_GE_LOG (ectx,
641 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
642 GNUNET_GE_BULK,
643 _("SMTP: `%s' failed: %s.\n"),
644 "smtp_set_messagecb",
645 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
646 smtp_destroy_session (session);
647 GNUNET_mutex_unlock (lock);
648 GNUNET_free (gm_cls.ebody);
649 return GNUNET_SYSERR;
650 }
651 recipient = smtp_add_recipient (message, haddr->senderAddress);
652 if (recipient == NULL)
653 {
654 GNUNET_GE_LOG (ectx,
655 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
656 GNUNET_GE_BULK,
657 _("SMTP: `%s' failed: %s.\n"),
658 "smtp_add_recipient",
659 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
660 smtp_destroy_session (session);
661 GNUNET_mutex_unlock (lock);
662 return GNUNET_SYSERR;
663 }
664 if (0 == smtp_start_session (session))
665 {
666 GNUNET_GE_LOG (ectx,
667 GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
668 GNUNET_GE_BULK,
669 _("SMTP: `%s' failed: %s.\n"),
670 "smtp_start_session",
671 smtp_strerror (smtp_errno (), ebuf, EBUF_LEN));
672 smtp_destroy_session (session);
673 GNUNET_mutex_unlock (lock);
674 GNUNET_free (gm_cls.ebody);
675 return GNUNET_SYSERR;
676 }
677 if (stats != NULL)
678 stats->change (stat_bytesSent, size);
679 if (coreAPI->load_monitor != NULL)
680 GNUNET_network_monitor_notify_transmission (coreAPI->load_monitor,
681 GNUNET_ND_UPLOAD,
682 gm_cls.esize);
683 smtp_message_reset_status (message); /* this is needed to plug a 28-byte/message memory leak in libesmtp */
684 smtp_destroy_session (session);
685 GNUNET_mutex_unlock (lock);
686 GNUNET_free (gm_cls.ebody);
687 return GNUNET_OK;
688}
689
690/**
691 * Establish a connection to a remote node.
692 * @param helo the hello-Message for the target node
693 * @param tsessionPtr the session handle that is to be set
694 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
695 */
696static int
697api_connect (const GNUNET_MessageHello * hello,
698 GNUNET_TSession ** tsessionPtr, int may_reuse)
699{
700 GNUNET_TSession *tsession;
701
702 tsession = GNUNET_malloc (sizeof (GNUNET_TSession));
703 tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello));
704 tsession->peer = hello->senderIdentity;
705 memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello));
706 tsession->ttype = smtpAPI.protocol_number;
707 (*tsessionPtr) = tsession;
708 return GNUNET_OK;
709}
710
711/**
712 * Disconnect from a remote node.
713 *
714 * @param tsession the session that is closed
715 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
716 */
717static int
718api_disconnect (GNUNET_TSession * tsession)
719{
720 if (tsession != NULL)
721 {
722 if (tsession->internal != NULL)
723 GNUNET_free (tsession->internal);
724 GNUNET_free (tsession);
725 }
726 return GNUNET_OK;
727}
728
729/**
730 * Start the server process to receive inbound traffic.
731 * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
732 */
733static int
734api_start_transport_server ()
735{
736 smtp_shutdown = GNUNET_NO;
737 /* initialize SMTP network */
738 dispatchThread =
739 GNUNET_thread_create (&listenAndDistribute, NULL, 1024 * 4);
740 if (dispatchThread == NULL)
741 {
742 GNUNET_GE_DIE_STRERROR (ectx,
743 GNUNET_GE_ADMIN | GNUNET_GE_BULK |
744 GNUNET_GE_FATAL, "pthread_create");
745 return GNUNET_SYSERR;
746 }
747 return GNUNET_OK;
748}
749
750/**
751 * Shutdown the server process (stop receiving inbound traffic). Maybe
752 * restarted later!
753 */
754static int
755api_stop_transport_server ()
756{
757 void *unused;
758
759 smtp_shutdown = GNUNET_YES;
760 GNUNET_thread_stop_sleep (dispatchThread);
761 GNUNET_thread_join (dispatchThread, &unused);
762 return GNUNET_OK;
763}
764
765/**
766 * Convert SMTP hello to an IP address (always fails).
767 */
768static int
769api_hello_to_address (const GNUNET_MessageHello * hello,
770 void **sa, unsigned int *sa_len)
771{
772 return GNUNET_SYSERR;
773}
774
775/**
776 * Always fails.
777 */
778static int
779api_associate (GNUNET_TSession * tsession)
780{
781 return GNUNET_SYSERR; /* SMTP connections can never be associated */
782}
783
784/**
785 * Always succeeds (for now; we should look at adding
786 * frequency limits to SMTP in the future!).
787 */
788static int
789api_test_would_try (GNUNET_TSession * tsession, const unsigned int size,
790 int important)
791{
792 return GNUNET_OK; /* we always try... */
793}
794
795/**
796 * The exported method. Makes the core api available via a global and
797 * returns the smtp transport API.
798 */
799GNUNET_TransportAPI *
800inittransport_smtp (GNUNET_CoreAPIForTransport * core)
801{
802
803
804 unsigned long long mtu;
805 struct sigaction sa;
806
807 coreAPI = core;
808 ectx = core->ectx;
809 if (!GNUNET_GC_have_configuration_value (coreAPI->cfg, "SMTP", "EMAIL"))
810 {
811 GNUNET_GE_LOG (ectx,
812 GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
813 _
814 ("No email-address specified, can not start SMTP transport.\n"));
815 return NULL;
816 }
817 GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
818 "SMTP",
819 "MTU",
820 1200,
821 SMTP_MESSAGE_SIZE,
822 SMTP_MESSAGE_SIZE, &mtu);
823 GNUNET_GC_get_configuration_value_number (coreAPI->cfg,
824 "SMTP",
825 "RATELIMIT",
826 0, 0, 1024 * 1024, &rate_limit);
827 stats = coreAPI->service_request ("stats");
828 if (stats != NULL)
829 {
830 stat_bytesReceived
831 = stats->create (gettext_noop ("# bytes received via SMTP"));
832 stat_bytesSent = stats->create (gettext_noop ("# bytes sent via SMTP"));
833 stat_bytesDropped
834 = stats->create (gettext_noop ("# bytes dropped by SMTP (outgoing)"));
835 }
836 GNUNET_GC_get_configuration_value_filename (coreAPI->cfg,
837 "SMTP",
838 "PIPE",
839 GNUNET_DEFAULT_DAEMON_VAR_DIRECTORY
840 "/smtp-pipe", &pipename);
841 UNLINK (pipename);
842 if (0 != mkfifo (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
843 {
844 GNUNET_GE_LOG_STRERROR (ectx,
845 GNUNET_GE_ADMIN | GNUNET_GE_BULK |
846 GNUNET_GE_FATAL, "mkfifo");
847 GNUNET_free (pipename);
848 coreAPI->service_release (stats);
849 stats = NULL;
850 return NULL;
851 }
852 /* we need to allow the mailer program to send us messages;
853 easiest done by giving it write permissions (see Mantis #1142) */
854 if (0 != chmod (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
855 GNUNET_GE_LOG_STRERROR (ectx,
856 GNUNET_GE_ADMIN | GNUNET_GE_BULK |
857 GNUNET_GE_WARNING, "chmod");
858 GNUNET_GC_get_configuration_value_string (coreAPI->cfg,
859 "SMTP", "EMAIL", NULL, &email);
860 lock = GNUNET_mutex_create (GNUNET_NO);
861 GNUNET_GC_get_configuration_value_string (coreAPI->cfg,
862 "SMTP",
863 "SERVER",
864 "localhost:25",
865 &smtp_server_name);
866 sa.sa_handler = SIG_IGN;
867 sigemptyset (&sa.sa_mask);
868 sa.sa_flags = 0;
869 sigaction (SIGPIPE, &sa, &old_handler);
870
871 smtpAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP;
872 smtpAPI.mtu = mtu - sizeof (SMTPMessage);
873 smtpAPI.cost = 50;
874 smtpAPI.hello_verify = &api_verify_hello;
875 smtpAPI.hello_create = &api_create_hello;
876 smtpAPI.connect = &api_connect;
877 smtpAPI.send = &api_send;
878 smtpAPI.associate = &api_associate;
879 smtpAPI.disconnect = &api_disconnect;
880 smtpAPI.server_start = &api_start_transport_server;
881 smtpAPI.server_stop = &api_stop_transport_server;
882 smtpAPI.hello_to_address = &api_hello_to_address;
883 smtpAPI.send_now_test = &api_test_would_try;
884 return &smtpAPI;
885}
886
887void
888donetransport_smtp ()
889{
890 sigaction (SIGPIPE, &old_handler, NULL);
891 GNUNET_free (smtp_server_name);
892 if (stats != NULL)
893 {
894 coreAPI->service_release (stats);
895 stats = NULL;
896 }
897 GNUNET_mutex_destroy (lock);
898 lock = NULL;
899 UNLINK (pipename);
900 GNUNET_free (pipename);
901 pipename = NULL;
902 GNUNET_free (email);
903 email = NULL;
904}
905
906/* end of smtp.c */