- changes
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 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 3, 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 transport/gnunet-service-transport.c
23  * @brief
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_statistics_service.h"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_ats_service.h"
33 #include "gnunet-service-transport.h"
34 #include "gnunet-service-transport_blacklist.h"
35 #include "gnunet-service-transport_clients.h"
36 #include "gnunet-service-transport_hello.h"
37 #include "gnunet-service-transport_neighbours.h"
38 #include "gnunet-service-transport_plugins.h"
39 #include "gnunet-service-transport_validation.h"
40 #include "transport.h"
41
42 /* globals */
43
44 /**
45  * Statistics handle.
46  */
47 struct GNUNET_STATISTICS_Handle *GST_stats;
48
49 /**
50  * Configuration handle.
51  */
52 const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
53
54 /**
55  * Configuration handle.
56  */
57 struct GNUNET_PeerIdentity GST_my_identity;
58
59 /**
60  * Handle to peerinfo service.
61  */
62 struct GNUNET_PEERINFO_Handle *GST_peerinfo;
63
64
65 /**
66  * Hostkey generation context
67  */
68 struct GNUNET_CRYPTO_RsaKeyGenerationContext *GST_keygen;
69
70 /**
71  * Closure for hostkey generation
72  */
73
74 struct KeyGenerationContext *GST_keygen_cls;
75
76
77 /**
78  * Our public key.
79  */
80 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
81
82 /**
83  * Our private key.
84  */
85 struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
86
87 /**
88  * ATS handle.
89  */
90 struct GNUNET_ATS_SchedulingHandle *GST_ats;
91
92 /**
93  * DEBUGGING connection counter
94  */
95 static int connections;
96
97
98 struct KeyGenerationContext
99 {
100   struct GNUNET_SERVER_Handle *server;
101   const struct GNUNET_CONFIGURATION_Handle *c;
102 };
103
104
105 /**
106  * Transmit our HELLO message to the given (connected) neighbour.
107  *
108  * @param cls the 'HELLO' message
109  * @param target a connected neighbour
110  * @param ats performance information (unused)
111  * @param ats_count number of records in ats (unused)
112  * @param address the address
113  * @param bandwidth_in inbound quota in NBO
114  * @param bandwidth_out outbound quota in NBO
115  */
116 static void
117 transmit_our_hello (void *cls, const struct GNUNET_PeerIdentity *target,
118                     const struct GNUNET_ATS_Information *ats,
119                     uint32_t ats_count,
120                     const struct GNUNET_HELLO_Address *address,
121                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
122                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
123 {
124   const struct GNUNET_MessageHeader *hello = cls;
125
126   GST_neighbours_send (target, (const char *) hello, ntohs (hello->size),
127                        GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION, NULL, NULL);
128 }
129
130
131 /**
132  * My HELLO has changed. Tell everyone who should know.
133  *
134  * @param cls unused
135  * @param hello new HELLO
136  */
137 static void
138 process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello)
139 {
140   GST_clients_broadcast (hello, GNUNET_NO);
141   GST_neighbours_iterate (&transmit_our_hello, (void *) hello);
142 }
143
144
145
146 /**
147  * We received some payload.  Prepare to pass it on to our clients.
148  *
149  * @param peer (claimed) identity of the other peer
150  * @param address the address
151  * @param session session used
152  * @param message the message to process
153  * @param ats performance information
154  * @param ats_count number of records in ats
155  * @return how long the plugin should wait until receiving more data
156  */
157 static struct GNUNET_TIME_Relative
158 process_payload (const struct GNUNET_PeerIdentity *peer,
159                  const struct GNUNET_HELLO_Address *address,
160                  struct Session *session,
161                  const struct GNUNET_MessageHeader *message,
162                  const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
163 {
164   struct GNUNET_TIME_Relative ret;
165   int do_forward;
166   struct InboundMessage *im;
167   size_t msg_size = ntohs (message->size);
168   size_t size =
169       sizeof (struct InboundMessage) + msg_size +
170       sizeof (struct GNUNET_ATS_Information) * (ats_count + 1);
171   char buf[size] GNUNET_ALIGN;
172   struct GNUNET_ATS_Information *ap;
173
174   ret = GNUNET_TIME_UNIT_ZERO;
175   do_forward = GNUNET_SYSERR;
176   ret = GST_neighbours_calculate_receive_delay (peer, msg_size, &do_forward);
177
178   if (!GST_neighbours_test_connected (peer))
179   {
180
181     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182                 "Discarded %u bytes type %u payload from peer `%s'\n", msg_size,
183                 ntohs (message->type), GNUNET_i2s (peer));
184
185     GNUNET_STATISTICS_update (GST_stats,
186                               gettext_noop
187                               ("# bytes payload discarded due to not connected peer "),
188                               msg_size, GNUNET_NO);
189     return ret;
190   }
191
192   if (do_forward != GNUNET_YES)
193     return ret;
194   im = (struct InboundMessage *) buf;
195   im->header.size = htons (size);
196   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
197   im->ats_count = htonl (ats_count + 1);
198   im->peer = *peer;
199   ap = (struct GNUNET_ATS_Information *) &im[1];
200   memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
201   ap[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
202   ap[ats_count].value =
203       htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
204   memcpy (&ap[ats_count + 1], message, ntohs (message->size));
205
206   GNUNET_ATS_address_add (GST_ats, address, session, ap, ats_count + 1);
207   GNUNET_ATS_address_update (GST_ats, address, session, ap, ats_count + 1);
208   GST_clients_broadcast (&im->header, GNUNET_YES);
209
210   return ret;
211 }
212
213
214 /**
215  * Function called by the transport for each received message.
216  * This function should also be called with "NULL" for the
217  * message to signal that the other peer disconnected.
218  *
219  * @param cls closure, const char* with the name of the plugin we received the message from
220  * @param peer (claimed) identity of the other peer
221  * @param message the message, NULL if we only care about
222  *                learning about the delay until we should receive again -- FIXME!
223  * @param ats performance information
224  * @param ats_count number of records in ats
225  * @param session identifier used for this session (NULL for plugins
226  *                that do not offer bi-directional communication to the sender
227  *                using the same "connection")
228  * @param sender_address binary address of the sender (if we established the
229  *                connection or are otherwise sure of it; should be NULL
230  *                for inbound TCP/UDP connections since it it not clear
231  *                that we could establish ourselves a connection to that
232  *                IP address and get the same system)
233  * @param sender_address_len number of bytes in sender_address
234  * @return how long the plugin should wait until receiving more data
235  *         (plugins that do not support this, can ignore the return value)
236  */
237 static struct GNUNET_TIME_Relative
238 plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
239                              const struct GNUNET_MessageHeader *message,
240                              const struct GNUNET_ATS_Information *ats,
241                              uint32_t ats_count, struct Session *session,
242                              const char *sender_address,
243                              uint16_t sender_address_len)
244 {
245   const char *plugin_name = cls;
246   struct GNUNET_TIME_Relative ret;
247   struct GNUNET_HELLO_Address address;
248   uint16_t type;
249
250   address.peer = *peer;
251   address.address = sender_address;
252   address.address_length = sender_address_len;
253   address.transport_name = plugin_name;
254   ret = GNUNET_TIME_UNIT_ZERO;
255   if (NULL == message)
256     goto end;
257   type = ntohs (message->type);
258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u from peer `%s'\n", type, GNUNET_i2s (peer));
259
260   GNUNET_STATISTICS_update (GST_stats,
261                         gettext_noop
262                         ("# bytes total received"),
263                             ntohs (message->size), GNUNET_NO);
264
265   switch (type)
266   {
267   case GNUNET_MESSAGE_TYPE_HELLO:
268     GST_validation_handle_hello (message);
269     return ret;
270   case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
271     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
272                 "Processing `%s' from `%s'\n", "PING",
273                 (sender_address !=
274                  NULL) ? GST_plugins_a2s (&address) : "<inbound>");
275     GST_validation_handle_ping (peer, message, &address, session);
276     break;
277   case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
278     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
279                 "Processing `%s' from `%s'\n", "PONG",
280                 (sender_address !=
281                  NULL) ? GST_plugins_a2s (&address) : "<inbound>");
282     GST_validation_handle_pong (peer, message);
283     break;
284   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT:
285     GST_neighbours_handle_connect (message, peer, &address, session, ats,
286                                    ats_count);
287     break;
288   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK:
289     GST_neighbours_handle_connect_ack (message, peer, &address, session, ats,
290                                        ats_count);
291     break;
292   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
293     GST_neighbours_handle_session_ack (message, peer, &address, session, ats,
294                                        ats_count);
295     break;
296   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
297     GST_neighbours_handle_disconnect_message (peer, message);
298     break;
299   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
300     GST_neighbours_keepalive (peer);
301     break;
302   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE:
303     GST_neighbours_keepalive_response (peer, ats, ats_count);
304     break;
305   default:
306     /* should be payload */
307     GNUNET_STATISTICS_update (GST_stats,
308                               gettext_noop
309                               ("# bytes payload received"),
310                               ntohs (message->size), GNUNET_NO);
311     ret = process_payload (peer, &address, session, message, ats, ats_count);
312     break;
313   }
314 end:
315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316               "Allowing receive from peer %s to continue in %llu ms\n",
317               GNUNET_i2s (peer), (unsigned long long) ret.rel_value);
318   return ret;
319 }
320
321
322 /**
323  * Function that will be called for each address the transport
324  * is aware that it might be reachable under.  Update our HELLO.
325  *
326  * @param cls name of the plugin (const char*)
327  * @param add_remove should the address added (YES) or removed (NO) from the
328  *                   set of valid addresses?
329  * @param addr one of the addresses of the host
330  *        the specific address format depends on the transport
331  * @param addrlen length of the address
332  */
333 static void
334 plugin_env_address_change_notification (void *cls, int add_remove,
335                                         const void *addr, size_t addrlen)
336 {
337   const char *plugin_name = cls;
338   struct GNUNET_HELLO_Address address;
339
340   address.peer = GST_my_identity;
341   address.transport_name = plugin_name;
342   address.address = addr;
343   address.address_length = addrlen;
344   GST_hello_modify_addresses (add_remove, &address);
345 }
346
347
348 /**
349  * Function that will be called whenever the plugin internally
350  * cleans up a session pointer and hence the service needs to
351  * discard all of those sessions as well.  Plugins that do not
352  * use sessions can simply omit calling this function and always
353  * use NULL wherever a session pointer is needed.  This function
354  * should be called BEFORE a potential "TransmitContinuation"
355  * from the "TransmitFunction".
356  *
357  * @param cls closure
358  * @param peer which peer was the session for
359  * @param session which session is being destoyed
360  */
361 static void
362 plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
363                         struct Session *session)
364 {
365   const char *transport_name = cls;
366   struct GNUNET_HELLO_Address address;
367
368   GNUNET_assert (strlen (transport_name) > 0);
369   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %p to peer `%s' ended \n",
370               session, GNUNET_i2s (peer));
371   if (NULL != session)
372     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
373                      "transport-ats",
374                      "Telling ATS to destroy session %p from peer %s\n",
375                      session, GNUNET_i2s (peer));
376   address.peer = *peer;
377   address.address = NULL;
378   address.address_length = 0;
379   address.transport_name = transport_name;
380   GST_neighbours_session_terminated (peer, session);
381
382   /* Tell ATS that session has ended */
383   GNUNET_ATS_address_destroyed (GST_ats, &address, session);
384 }
385
386
387 /**
388  * Function that will be called to figure if an address is an loopback,
389  * LAN, WAN etc. address
390  *
391  * @param cls closure
392  * @param addr binary address
393  * @param addrlen length of the address
394  * @return ATS Information containing the network type
395  */
396 static struct GNUNET_ATS_Information
397 plugin_env_address_to_type (void *cls,
398                             const struct sockaddr *addr,
399                             size_t addrlen)
400 {
401   struct GNUNET_ATS_Information ats;
402   ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
403   ats.value = htonl (GNUNET_ATS_NET_UNSPECIFIED);
404   if (GST_ats == NULL)
405   {
406     GNUNET_break (0);
407     return ats;
408   }
409   if (((addr->sa_family != AF_INET) && (addrlen != sizeof (struct sockaddr_in))) &&
410       ((addr->sa_family != AF_INET6) && (addrlen != sizeof (struct sockaddr_in6))) &&
411       (addr->sa_family != AF_UNIX))
412   {
413     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed address with length %u `%s'\n",
414                 addrlen,
415                 GNUNET_a2s(addr, addrlen));
416     GNUNET_break (0);
417     return (const struct GNUNET_ATS_Information) ats;
418   }
419   return GNUNET_ATS_address_get_type(GST_ats, addr, addrlen);
420 }
421
422
423 /**
424  * Function called by ATS to notify the callee that the
425  * assigned bandwidth or address for a given peer was changed.  If the
426  * callback is called with address/bandwidth assignments of zero, the
427  * ATS disconnect function will still be called once the disconnect
428  * actually happened.
429  *
430  * @param cls closure
431  * @param address address to use (for peer given in address)
432  * @param session session to use (if available)
433  * @param bandwidth_out assigned outbound bandwidth for the connection, 0 to disconnect from peer
434  * @param bandwidth_in assigned inbound bandwidth for the connection, 0 to disconnect from peer
435  * @param ats ATS information
436  * @param ats_count number of ATS elements
437  */
438 static void
439 ats_request_address_change (void *cls,
440                             const struct GNUNET_HELLO_Address *address,
441                             struct Session *session,
442                             struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
443                             struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
444                             const struct GNUNET_ATS_Information *ats,
445                             uint32_t ats_count)
446 {
447   uint32_t bw_in = ntohl (bandwidth_in.value__);
448   uint32_t bw_out = ntohl (bandwidth_out.value__);
449
450   /* ATS tells me to disconnect from peer */
451   if ((bw_in == 0) && (bw_out == 0))
452   {
453     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454                 "ATS tells me to disconnect from peer `%s'\n",
455                 GNUNET_i2s (&address->peer));
456     GST_neighbours_force_disconnect (&address->peer);
457     return;
458   }
459   GST_neighbours_switch_to_address (&address->peer, address, session, ats,
460                                          ats_count, bandwidth_in,
461                                          bandwidth_out);
462 }
463
464
465 /**
466  * Function called to notify transport users that another
467  * peer connected to us.
468  *
469  * @param cls closure
470  * @param peer the peer that connected
471  * @param ats performance data
472  * @param ats_count number of entries in ats
473  * @param bandwidth_in inbound bandwidth in NBO
474  * @param bandwidth_out outbound bandwidth in NBO
475  */
476 static void
477 neighbours_connect_notification (void *cls,
478                                  const struct GNUNET_PeerIdentity *peer,
479                                  const struct GNUNET_ATS_Information *ats,
480                                  uint32_t ats_count,
481                                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
482                                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
483 {
484   size_t len =
485       sizeof (struct ConnectInfoMessage) +
486       ats_count * sizeof (struct GNUNET_ATS_Information);
487   char buf[len] GNUNET_ALIGN;
488   struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
489   struct GNUNET_ATS_Information *ap;
490
491   connections++;
492   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
493               "We are now connected to peer `%s' and %u peers in total\n",
494               GNUNET_i2s (peer), connections);
495
496   connect_msg->header.size = htons (sizeof (buf));
497   connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
498   connect_msg->ats_count = htonl (ats_count);
499   connect_msg->id = *peer;
500   connect_msg->quota_in = bandwidth_in;
501   connect_msg->quota_out = bandwidth_out;
502   ap = (struct GNUNET_ATS_Information *) &connect_msg[1];
503   memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
504   GST_clients_broadcast (&connect_msg->header, GNUNET_NO);
505 }
506
507
508 /**
509  * Function called to notify transport users that another
510  * peer disconnected from us.
511  *
512  * @param cls closure
513  * @param peer the peer that disconnected
514  */
515 static void
516 neighbours_disconnect_notification (void *cls,
517                                     const struct GNUNET_PeerIdentity *peer)
518 {
519   struct DisconnectInfoMessage disconnect_msg;
520
521   connections--;
522   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
523               "Peer `%s' disconnected and we are connected to %u peers\n",
524               GNUNET_i2s (peer), connections);
525
526   disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage));
527   disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
528   disconnect_msg.reserved = htonl (0);
529   disconnect_msg.peer = *peer;
530   GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO);
531 }
532
533
534 /**
535  * Function called to notify transport users that a neighbour peer changed its
536  * active address.
537  *
538  * @param cls closure
539  * @param peer peer this update is about (never NULL)
540  * @param address address, NULL on disconnect
541  */
542 static void
543 neighbours_address_notification (void *cls,
544                                  const struct GNUNET_PeerIdentity *peer,
545                                  const struct GNUNET_HELLO_Address *address)
546 {
547   GST_clients_broadcast_address_notification (peer, address);
548 }
549
550
551 /**
552  * Function called when the service shuts down.  Unloads our plugins
553  * and cancels pending validations.
554  *
555  * @param cls closure, unused
556  * @param tc task context (unused)
557  */
558 static void
559 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
560 {
561   if (NULL != GST_keygen)
562   {
563     GNUNET_CRYPTO_rsa_key_create_stop (GST_keygen);
564     GST_keygen = NULL;
565   }
566
567   if (NULL != GST_keygen_cls)
568   {
569     GNUNET_free (GST_keygen_cls);
570     GST_keygen_cls = NULL;
571   }
572
573   GST_neighbours_stop ();
574   GST_validation_stop ();
575   GST_plugins_unload ();
576
577   GNUNET_ATS_scheduling_done (GST_ats);
578   GST_ats = NULL;
579   GST_clients_stop ();
580   GST_blacklist_stop ();
581   GST_hello_stop ();
582
583   if (GST_peerinfo != NULL)
584   {
585     GNUNET_PEERINFO_disconnect (GST_peerinfo);
586     GST_peerinfo = NULL;
587   }
588   if (GST_stats != NULL)
589   {
590     GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
591     GST_stats = NULL;
592   }
593   if (GST_my_private_key != NULL)
594   {
595     GNUNET_CRYPTO_rsa_key_free (GST_my_private_key);
596     GST_my_private_key = NULL;
597   }
598 }
599
600 /**
601  * Callback for hostkey read/generation
602  * @param cls NULL
603  * @param pk the privatekey
604  * @param emsg error message
605  */
606 static void
607 key_generation_cb (void *cls,
608                    struct GNUNET_CRYPTO_RsaPrivateKey *pk,
609                    const char *emsg)
610 {
611   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded tmp;
612   GNUNET_assert (NULL != GST_keygen_cls);
613   GST_keygen = NULL;
614   if (NULL == pk)
615   {
616     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
617                 _("Transport service could not access hostkey: %s. Exiting.\n"),
618                 emsg);
619     GNUNET_free (GST_keygen_cls);
620     GST_keygen_cls = NULL;
621     GNUNET_SCHEDULER_shutdown ();
622     return;
623   }
624   GST_my_private_key = pk;
625
626   GST_stats = GNUNET_STATISTICS_create ("transport", GST_keygen_cls->c);
627   GST_peerinfo = GNUNET_PEERINFO_connect (GST_keygen_cls->c);
628   memset (&GST_my_public_key, '\0', sizeof (GST_my_public_key));
629   memset (&tmp, '\0', sizeof (tmp));
630   GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key);
631   GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key),
632                       &GST_my_identity.hashPubKey);
633
634   GNUNET_assert (NULL != GST_my_private_key);
635   GNUNET_assert (0 != memcmp (&GST_my_public_key, &tmp, sizeof (GST_my_public_key)));
636
637   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
638                                 NULL);
639   if (GST_peerinfo == NULL)
640   {
641     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
642                 _("Could not access PEERINFO service.  Exiting.\n"));
643     GNUNET_SCHEDULER_shutdown ();
644     return;
645   }
646
647   /* start subsystems */
648   GST_hello_start (&process_hello_update, NULL);
649   GNUNET_assert (NULL != GST_hello_get());
650   GST_blacklist_start (GST_keygen_cls->server);
651   GST_ats =
652       GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL);
653   GST_plugins_load (&plugin_env_receive_callback,
654                     &plugin_env_address_change_notification,
655                     &plugin_env_session_end,
656                     &plugin_env_address_to_type);
657   GST_neighbours_start (NULL,
658                         &neighbours_connect_notification,
659                         &neighbours_disconnect_notification,
660                         &neighbours_address_notification);
661   GST_clients_start (GST_keygen_cls->server);
662   GST_validation_start ();
663   GNUNET_free (GST_keygen_cls);
664   GST_keygen_cls = NULL;
665 }
666
667
668 /**
669  * Initiate transport service.
670  *
671  * @param cls closure
672  * @param server the initialized server
673  * @param c configuration to use
674  */
675 static void
676 run (void *cls, struct GNUNET_SERVER_Handle *server,
677      const struct GNUNET_CONFIGURATION_Handle *c)
678 {
679   char *keyfile;
680
681   /* setup globals */
682   GST_cfg = c;
683   if (GNUNET_OK !=
684       GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
685                                                &keyfile))
686   {
687     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
688                 _
689                 ("Transport service is lacking key configuration settings.  Exiting.\n"));
690     GNUNET_SCHEDULER_shutdown ();
691     return;
692   }
693   GST_keygen_cls = GNUNET_malloc (sizeof (struct KeyGenerationContext));
694   GST_keygen_cls->c = c;
695   GST_keygen_cls->server = server;
696
697   GST_keygen = GNUNET_CRYPTO_rsa_key_create_start (keyfile, key_generation_cb, GST_keygen_cls);
698   GNUNET_free (keyfile);
699   if (NULL == GST_keygen)
700   {
701     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702                 _("Transport service is unable to access hostkey. Exiting.\n"));
703     GNUNET_SCHEDULER_shutdown ();
704   }
705 }
706
707
708 /**
709  * The main function for the transport service.
710  *
711  * @param argc number of arguments from the command line
712  * @param argv command line arguments
713  * @return 0 ok, 1 on error
714  */
715 int
716 main (int argc, char *const *argv)
717 {
718   return (GNUNET_OK ==
719           GNUNET_SERVICE_run (argc, argv, "transport",
720                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
721 }
722
723 /* end of file gnunet-service-transport.c */