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