fix
[oweals/gnunet.git] / src / vpn / gnunet-daemon-exit.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 Christian Grothoff
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 vpn/gnunet-daemon-exit.c
23  * @brief
24  * @author Philipp Toelke
25  */
26 #include <platform.h>
27 #include <gnunet_common.h>
28 #include <gnunet_program_lib.h>
29 #include <gnunet_protocols.h>
30 #include <gnunet_mesh_service.h>
31 #include <gnunet_constants.h>
32
33 #include "gnunet-vpn-packet.h"
34
35 /**
36  * Final status code.
37  */
38 static int ret;
39
40 /**
41  * The handle to mesh
42  */
43 static struct GNUNET_MESH_Handle *mesh_handle;
44
45 /**
46  * This hashmap contains the mapping from peer, service-descriptor,
47  * source-port and destination-port to a socket
48  */
49 static struct GNUNET_CONTAINER_MultiHashMap *udp_connections;
50
51 /**
52  * FIXME
53  */
54 struct udp_state
55 {
56   struct GNUNET_PeerIdentity peer;
57   struct GNUNET_MESH_Tunnel *tunnel;
58   GNUNET_HashCode desc;
59   short spt;
60   short dpt;
61 };
62
63 /**
64  * FIXME
65  */
66 struct send_cls
67 {
68   struct GNUNET_NETWORK_Handle *sock;
69   struct udp_state state;
70 };
71
72 /**
73  * Function scheduled as very last function, cleans up after us
74  */
75 static void
76 cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) {
77     GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
78
79     if (mesh_handle != NULL)
80       {
81         GNUNET_MESH_disconnect(mesh_handle);
82         mesh_handle = NULL;
83       }
84 }
85
86 static size_t
87 send_udp_service (void *cls, size_t size, void *buf)
88 {
89   struct GNUNET_MessageHeader *hdr = cls;
90   GNUNET_assert(size >= ntohs(hdr->size));
91
92   memcpy(buf, cls, ntohs(hdr->size));
93   size_t ret = ntohs(hdr->size);
94   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending %d bytes back!\n", ntohs(hdr->size));
95   GNUNET_free(cls);
96   return ret;
97 }
98
99 void
100 receive_from_network (void *cls,
101                       const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
104     {
105       GNUNET_free(cls);
106       return;
107     }
108   struct send_cls *data = cls;
109
110   char buf[1400];
111
112   struct sockaddr_in addr_in;
113   socklen_t addr_len = sizeof(struct sockaddr_in);
114   ssize_t len = GNUNET_NETWORK_socket_recvfrom (data->sock, buf, 1400, (struct sockaddr*)&addr_in, &addr_len);
115
116   if (len < 0) {
117     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Problem reading from socket: %m\n");
118     goto out;
119   }
120
121   size_t len_udp = len + sizeof (struct udp_pkt);
122   size_t len_pkt = len_udp + sizeof (struct GNUNET_MessageHeader) + sizeof(GNUNET_HashCode);
123   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending data back: data: %d; udp: %d, pkt:%d\n", len, len_udp, len_pkt);
124
125   struct GNUNET_MessageHeader *hdr = GNUNET_malloc (len_pkt);
126   GNUNET_HashCode *desc = (GNUNET_HashCode *) (hdr + 1);
127   struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1);
128
129   hdr->size = htons (len_pkt);
130   hdr->type = htons (GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK);
131
132   pkt->dpt = htons(data->state.spt);
133   pkt->spt = addr_in.sin_port;
134   pkt->len = htons (len_udp);
135   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "UDP from %d to %d\n", ntohs(pkt->spt), ntohs(pkt->dpt));
136   /* The chksm can only be computed knowing the ip-addresses */
137
138   memcpy (desc, &data->state.desc, sizeof (GNUNET_HashCode));
139   memcpy (pkt + 1, buf, len);
140
141   GNUNET_MESH_notify_transmit_ready (data->state.tunnel, 42,
142                                      GNUNET_NO,
143                                      GNUNET_TIME_relative_divide(GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
144                                      len_pkt,
145                                      send_udp_service, hdr);
146
147 out:
148   GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, data->sock,
149                                  receive_from_network, cls);
150 }
151
152 void
153 send_to_network (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
154 {
155   if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
156     return;
157   struct send_cls *data = cls;
158   struct udp_pkt *pkt = (struct udp_pkt *) (data + 1);
159
160   struct sockaddr_in a4;
161   memset(&a4, 0, sizeof(struct sockaddr_in));
162   a4.sin_family = AF_INET;
163   a4.sin_port = htons(data->state.dpt);
164   GNUNET_assert (1 == inet_pton (AF_INET, "127.0.0.1", &a4.sin_addr));
165   GNUNET_NETWORK_socket_sendto (data->sock, pkt + 1,
166                                 ntohs (pkt->len) - sizeof (struct udp_pkt),
167                                 (struct sockaddr*)&a4, sizeof a4);
168
169   GNUNET_free(cls);
170
171 }
172
173 /** 
174  * The messages are one GNUNET_HashCode for the service, followed by a struct udp_pkt
175  */
176 static int
177 receive_udp_service (void *cls,
178                      struct GNUNET_MESH_Tunnel *tunnel,
179                      void **tunnel_ctx,
180                      const struct GNUNET_MessageHeader *message,
181                      const struct GNUNET_TRANSPORT_ATS_Information *atsi)
182 {
183   GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
184   struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1);
185
186   /* FIXME -> check acl etc */
187   GNUNET_assert (ntohs (pkt->len) ==
188                  ntohs (message->size) -
189                  sizeof (struct GNUNET_MessageHeader) -
190                  sizeof (GNUNET_HashCode));
191
192   size_t state_size = sizeof (struct udp_state);
193   size_t cls_size = sizeof (struct send_cls) + ntohs (pkt->len);
194   struct send_cls *send = GNUNET_malloc (cls_size);
195   struct udp_state *state = &send->state;
196   unsigned int new = GNUNET_NO;
197
198   state->tunnel = tunnel;
199   memcpy (&state->desc, desc, sizeof (GNUNET_HashCode));
200   state->spt = ntohs (pkt->spt);
201
202   /* Hash without the dpt, so that eg tftp works */
203   state->dpt = 0;
204
205   memcpy (send + 1, pkt, ntohs (pkt->len));
206
207   GNUNET_HashCode hash;
208   GNUNET_CRYPTO_hash (state, state_size, &hash);
209
210   state->dpt = ntohs (pkt->dpt);
211
212   struct GNUNET_NETWORK_Handle *sock =
213     GNUNET_CONTAINER_multihashmap_get (udp_connections, &hash);
214
215   if (sock == NULL)
216     {
217       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new Socket!\n");
218       sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
219       GNUNET_assert(sock != NULL);
220       new = GNUNET_YES;
221     }
222
223   send->sock = sock;
224
225   GNUNET_CONTAINER_multihashmap_put (udp_connections, &hash, sock,
226                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
227
228
229   if (new)
230     {
231       struct send_cls *recv = GNUNET_malloc (sizeof (struct send_cls));
232       memcpy (recv, send, sizeof (struct send_cls));
233       GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
234                                      receive_from_network, recv);
235     }
236
237   GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
238                                   send_to_network, send);
239
240   return GNUNET_OK;
241 }
242
243 /**
244  * @brief Main function that will be run by the scheduler.
245  *
246  * @param cls closure
247  * @param args remaining command-line arguments
248  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
249  * @param cfg_ configuration
250  */
251 static void
252 run (void *cls,
253      char *const *args,
254      const char *cfgfile,
255      const struct GNUNET_CONFIGURATION_Handle *cfg_)
256 {
257   const static struct GNUNET_MESH_MessageHandler handlers[] = {
258         {receive_udp_service, GNUNET_MESSAGE_TYPE_SERVICE_UDP, 0},
259         {NULL, 0, 0}
260   };
261   mesh_handle = GNUNET_MESH_connect(cfg_,
262                                     NULL,
263                                     NULL, /* FIXME */
264                                     handlers);
265
266   udp_connections = GNUNET_CONTAINER_multihashmap_create(65536);
267   GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
268 }
269
270 /**
271  * The main function to obtain template from gnunetd.
272  *
273  * @param argc number of arguments from the command line
274  * @param argv command line arguments
275  * @return 0 ok, 1 on error
276  */
277 int
278 main (int argc, char *const *argv) {
279     static const struct GNUNET_GETOPT_CommandLineOption options[] = {
280         GNUNET_GETOPT_OPTION_END
281     };
282
283     return (GNUNET_OK ==
284             GNUNET_PROGRAM_run (argc,
285                                 argv,
286                                 "gnunet-daemon-exit",
287                                 gettext_noop ("help text"),
288                                 options, &run, NULL)) ? ret : 1;
289 }
290
291 /* end of gnunet-daemon-exit.c */
292