http plugin revisited
[oweals/gnunet.git] / src / transport / plugin_transport_http_server.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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/plugin_transport_http.c
23  * @brief http transport service plugin
24  * @author Matthias Wachs
25  */
26
27 #include "plugin_transport_http.h"
28
29 static void
30 server_log (void *arg, const char *fmt, va_list ap)
31 {
32   char text[1024];
33
34   vsnprintf (text, sizeof (text), fmt, ap);
35   va_end (ap);
36   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "server: %s\n", text);
37 }
38
39 /**
40  * Check if incoming connection is accepted.
41  * NOTE: Here every connection is accepted
42  * @param cls plugin as closure
43  * @param addr address of incoming connection
44  * @param addr_len address length of incoming connection
45  * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
46  *
47  */
48 static int
49 server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len)
50 {
51   return 0;
52 }
53
54
55 /**
56  * Callback called by MHD when it needs data to send
57  * @param cls current session
58  * @param pos position in buffer
59  * @param buf the buffer to write data to
60  * @param max max number of bytes available in buffer
61  * @return bytes written to buffer
62  */
63 #if 0
64 static ssize_t
65 server_send_cb (void *cls, uint64_t pos, char *buf, size_t max)
66 {
67
68   return 0;
69 }
70 #endif
71
72
73 #if BUILD_HTTPS
74 static char *
75 server_load_file (const char *file)
76 {
77   struct GNUNET_DISK_FileHandle *gn_file;
78   struct stat fstat;
79   char *text = NULL;
80
81   if (0 != STAT (file, &fstat))
82     return NULL;
83   text = GNUNET_malloc (fstat.st_size + 1);
84   gn_file =
85       GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
86                              GNUNET_DISK_PERM_USER_READ);
87   if (gn_file == NULL)
88   {
89     GNUNET_free (text);
90     return NULL;
91   }
92   if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size))
93   {
94     GNUNET_free (text);
95     GNUNET_DISK_file_close (gn_file);
96     return NULL;
97   }
98   text[fstat.st_size] = '\0';
99   GNUNET_DISK_file_close (gn_file);
100   return text;
101 }
102 #endif
103
104
105 #if BUILD_HTTPS
106
107 static int
108 server_load_certificate (struct Plugin *plugin)
109 {
110   int res = GNUNET_OK;
111
112   char *key_file;
113   char *cert_file;
114
115   /* Get crypto init string from config
116    * If not present just use default values */
117   GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
118                                          "CRYPTO_INIT", &plugin->crypto_init);
119
120   if (GNUNET_OK !=
121       GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
122                                                "KEY_FILE", &key_file))
123   {
124     key_file = "https_key.key";
125   }
126
127   if (GNUNET_OK !=
128       GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
129                                                "CERT_FILE", &cert_file))
130   {
131     cert_file = "https_cert.crt";
132   }
133
134   /* read key & certificates from file */
135 #if VERBOSE_SERVER
136   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
137               "Loading TLS certificate from key-file `%s' cert-file`%s'\n",
138               key_file, cert_file);
139 #endif
140
141   plugin->key = server_load_file (key_file);
142   plugin->cert = server_load_file (cert_file);
143
144   if ((plugin->key == NULL) || (plugin->cert == NULL))
145   {
146     struct GNUNET_OS_Process *cert_creation;
147
148     GNUNET_free_non_null (plugin->key);
149     plugin->key = NULL;
150     GNUNET_free_non_null (plugin->cert);
151     plugin->cert = NULL;
152
153 #if VERBOSE_SERVER
154     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155                 "No usable TLS certificate found, creating certificate\n");
156 #endif
157     errno = 0;
158     cert_creation =
159         GNUNET_OS_start_process (NULL, NULL,
160                                  "gnunet-transport-certificate-creation",
161                                  "gnunet-transport-certificate-creation",
162                                  key_file, cert_file, NULL);
163     if (cert_creation == NULL)
164     {
165       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
166                        _
167                        ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
168       GNUNET_free (key_file);
169       GNUNET_free (cert_file);
170
171       GNUNET_free_non_null (plugin->key);
172       GNUNET_free_non_null (plugin->cert);
173       GNUNET_free_non_null (plugin->crypto_init);
174
175       return GNUNET_SYSERR;
176     }
177     GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
178     GNUNET_OS_process_close (cert_creation);
179
180     plugin->key = server_load_file (key_file);
181     plugin->cert = server_load_file (cert_file);
182   }
183
184   if ((plugin->key == NULL) || (plugin->cert == NULL))
185   {
186     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
187                      _
188                      ("No usable TLS certificate found and creating one failed!\n"),
189                      "transport-https");
190     GNUNET_free (key_file);
191     GNUNET_free (cert_file);
192
193     GNUNET_free_non_null (plugin->key);
194     GNUNET_free_non_null (plugin->cert);
195     GNUNET_free_non_null (plugin->crypto_init);
196
197     return GNUNET_SYSERR;
198   }
199   GNUNET_free (key_file);
200   GNUNET_free (cert_file);
201 #if DEBUG_HTTP
202   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n");
203 #endif
204
205   return res;
206 }
207 #endif
208
209
210 /**
211  * Process GET or PUT request received via MHD.  For
212  * GET, queue response that will send back our pending
213  * messages.  For PUT, process incoming data and send
214  * to GNUnet core.  In either case, check if a session
215  * already exists and create a new one if not.
216  */
217 static int
218 server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
219                   const char *url, const char *method, const char *version,
220                   const char *upload_data, size_t * upload_data_size,
221                   void **httpSessionCache)
222 {
223   return 0;
224 }
225
226 static void
227 server_disconnect_cb (void *cls, struct MHD_Connection *connection,
228                       void **httpSessionCache)
229 {
230 }
231
232 int
233 server_disconnect (struct Session *s)
234 {
235   return GNUNET_OK;
236 }
237
238 int
239 server_send (struct Session *s, const char *msgbuf, size_t msgbuf_size)
240 {
241   return GNUNET_OK;
242 }
243
244 int
245 server_start (struct Plugin *plugin)
246 {
247   int res = GNUNET_OK;
248
249 #if BUILD_HTTPS
250   res = server_load_certificate (plugin);
251   if (res == GNUNET_SYSERR)
252   {
253     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TABORT\n");
254     return res;
255   }
256 #endif
257
258   plugin->server_v4 = NULL;
259   if (plugin->ipv4 == GNUNET_YES)
260   {
261     plugin->server_v4 = MHD_start_daemon (
262 #if VERBOSE_SERVER
263                                            MHD_USE_DEBUG |
264 #endif
265 #if BUILD_HTTPS
266                                            MHD_USE_SSL |
267 #endif
268                                            MHD_NO_FLAG, plugin->port,
269                                            &server_accept_cb, plugin,
270                                            &server_access_cb, plugin,
271                                            //MHD_OPTION_SOCK_ADDR,
272                                            //(struct sockaddr_in *)
273                                            //plugin->bind4_address,
274                                            MHD_OPTION_CONNECTION_LIMIT,
275                                            (unsigned int)
276                                            plugin->max_connections,
277 #if BUILD_HTTPS
278                                            MHD_OPTION_HTTPS_PRIORITIES,
279                                            plugin->crypto_init,
280                                            MHD_OPTION_HTTPS_MEM_KEY,
281                                            plugin->key,
282                                            MHD_OPTION_HTTPS_MEM_CERT,
283                                            plugin->cert,
284 #endif
285                                            MHD_OPTION_CONNECTION_TIMEOUT,
286                                            (unsigned int) 3,
287                                            MHD_OPTION_CONNECTION_MEMORY_LIMIT,
288                                            (size_t) (2 *
289                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE),
290                                            MHD_OPTION_NOTIFY_COMPLETED,
291                                            &server_disconnect_cb, plugin,
292                                            MHD_OPTION_EXTERNAL_LOGGER,
293                                            server_log, NULL, MHD_OPTION_END);
294     if (plugin->server_v4 == NULL)
295       res = GNUNET_SYSERR;
296   }
297   plugin->server_v6 = NULL;
298   if (plugin->ipv6 == GNUNET_YES)
299   {
300     plugin->server_v6 = MHD_start_daemon (
301 #if VERBOSE_SERVER
302                                            MHD_USE_DEBUG |
303 #endif
304 #if BUILD_HTTPS
305                                            MHD_USE_SSL |
306 #endif
307                                            MHD_USE_IPv6, plugin->port,
308                                            &server_accept_cb, plugin,
309                                            &server_access_cb, plugin,
310                                            //MHD_OPTION_SOCK_ADDR,
311                                            //tmp,
312                                            MHD_OPTION_CONNECTION_LIMIT,
313                                            (unsigned int)
314                                            plugin->max_connections,
315 #if BUILD_HTTPS
316                                            MHD_OPTION_HTTPS_PRIORITIES,
317                                            plugin->crypto_init,
318                                            MHD_OPTION_HTTPS_MEM_KEY,
319                                            plugin->key,
320                                            MHD_OPTION_HTTPS_MEM_CERT,
321                                            plugin->cert,
322 #endif
323                                            MHD_OPTION_CONNECTION_TIMEOUT,
324                                            (unsigned int) 3,
325                                            MHD_OPTION_CONNECTION_MEMORY_LIMIT,
326                                            (size_t) (2 *
327                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE),
328                                            MHD_OPTION_NOTIFY_COMPLETED,
329                                            &server_disconnect_cb, plugin,
330                                            MHD_OPTION_EXTERNAL_LOGGER,
331                                            server_log, NULL, MHD_OPTION_END);
332
333     if (plugin->server_v6 == NULL)
334       res = GNUNET_SYSERR;
335   }
336
337 #if DEBUG_HTTP
338   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
339                    "%s server component started on port %u\n", plugin->name,
340                    plugin->port);
341 #endif
342   return res;
343 }
344
345 void
346 server_stop (struct Plugin *plugin)
347 {
348
349   if (plugin->server_v4 != NULL)
350   {
351     MHD_stop_daemon (plugin->server_v4);
352     plugin->server_v4 = NULL;
353   }
354   if (plugin->server_v6 != NULL)
355   {
356     MHD_stop_daemon (plugin->server_v6);
357     plugin->server_v6 = NULL;
358   }
359
360 #if BUILD_HTTPS
361   GNUNET_free_non_null (plugin->crypto_init);
362   GNUNET_free_non_null (plugin->cert);
363   GNUNET_free_non_null (plugin->key);
364 #endif
365
366 #if DEBUG_HTTP
367   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
368                    "%s server component stopped\n", plugin->name);
369 #endif
370 }
371
372
373
374 /* end of plugin_transport_http.c */