try new method for sending find peer requests
[oweals/gnunet.git] / src / upnp / upnp_init.c
1 /*
2      This file is part of GNUnet
3      (C) 2006 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 upnp/upnp_init.c
23  * @brief API for UPnP access
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_util.h"
29 #include "upnp.h"
30 #include "gnunet_upnp_service.h"
31 #include "gnunet_core.h"
32
33 static struct GNUNET_GE_Context *ectx;
34
35 static struct GNUNET_GC_Configuration *cfg;
36
37 static struct GNUNET_CronManager *cron;
38
39 static struct GNUNET_Mutex *lock;
40
41 typedef struct
42 {
43   unsigned short port;
44   const char *proto;
45 } PMap;
46
47 static PMap *maps;
48
49 static unsigned int maps_size;
50
51 static struct GNUNET_ThreadHandle *discovery;
52
53 static struct GNUNET_NETWORK_Handle *discovery_socket;
54
55 /**
56  * Obtain the public/external IP address.
57  *
58  * @return GNUNET_SYSERR on error, GNUNET_OK on success
59  */
60 static int
61 gnunet_upnp_get_public_ip (struct in_addr *address)
62 {
63   const char *ip;
64   socklen_t socklen;
65   struct sockaddr *sa;
66   struct sockaddr_in s4;
67   int ret;
68
69   ip = gaim_upnp_get_public_ip ();
70   if (ip == NULL)
71     return GNUNET_SYSERR;
72   socklen = sizeof (struct sockaddr_in);
73   sa = (struct sockaddr *) &s4;
74   ret = GNUNET_get_ip_from_hostname (NULL, ip, AF_INET, &sa, &socklen);
75   if (ret == GNUNET_OK)
76     *address = s4.sin_addr;
77   return ret;
78 }
79
80 static void
81 kill_discovery ()
82 {
83   void *unused;
84
85   if (discovery != NULL)
86     {
87       GNUNET_IO_shutdown (discovery_socket, SHUT_RDWR);
88       GNUNET_IO_close (&discovery_socket);
89       GNUNET_thread_join (discovery, &unused);
90       discovery = NULL;
91     }
92 }
93
94 static void *
95 discover_thread ()
96 {
97   gaim_upnp_discover (ectx, cfg, discovery_socket);
98   return NULL;
99 }
100
101 /**
102  * Periodically try to (re)discover UPnP access points.
103  */
104 static void
105 discover (void *unused)
106 {
107   kill_discovery ();
108   discovery_socket = GNUNET_IO_socket (PF_INET, SOCK_DGRAM, 0);
109   if (NULL == discovery_socket)
110     return;
111   discovery = GNUNET_thread_create (&discover_thread, NULL, 1024 * 128);
112 }
113
114 /**
115  * Periodically repeat our requests for port mappings.
116  */
117 static void
118 portmap (void *unused)
119 {
120   unsigned int i;
121
122   GNUNET_mutex_lock (lock);
123   for (i = 0; i < maps_size; i++)
124     gaim_upnp_change_port_mapping (ectx,
125                                    cfg, GNUNET_NO, maps[i].port,
126                                    maps[i].proto);
127   GNUNET_mutex_unlock (lock);
128 }
129
130
131 /**
132  * Get the external IP address for the local machine.
133  *
134  * @return GNUNET_SYSERR on error, GNUNET_OK on success
135  */
136 static int
137 gnunet_upnp_get_ip (unsigned short port,
138                     const char *protocol, struct in_addr *address)
139 {
140   unsigned int i;
141
142   GNUNET_mutex_lock (lock);
143   for (i = 0; i < maps_size; i++)
144     if ((0 == strcmp (maps[i].proto, protocol)) && (maps[i].port == port))
145       break;
146   if (i == maps_size)
147     {
148       /* new entry! */
149       GNUNET_array_grow (maps, maps_size, maps_size + 1);
150       maps[i].proto = protocol;
151       maps[i].port = port;
152       gaim_upnp_change_port_mapping (ectx, cfg, GNUNET_YES, port, protocol);
153     }
154   GNUNET_mutex_unlock (lock);
155   return gnunet_upnp_get_public_ip (address);
156 }
157
158
159 /**
160  * Get the external IP address for the local machine.
161  */
162 GNUNET_UPnP_ServiceAPI *
163 provide_module_upnp (GNUNET_CoreAPIForPlugins * capi)
164 {
165   static GNUNET_UPnP_ServiceAPI api;
166
167   ectx = capi->ectx;
168   cfg = capi->cfg;
169   cron = GNUNET_cron_create (ectx);
170   lock = GNUNET_mutex_create (GNUNET_NO);
171   GNUNET_cron_start (cron);
172   GNUNET_cron_add_job (cron, &discover, 0, 5 * GNUNET_CRON_MINUTES, NULL);
173   GNUNET_cron_add_job (cron, &portmap, 150 * GNUNET_CRON_SECONDS,
174                        5 * GNUNET_CRON_MINUTES, NULL);
175   api.get_ip = gnunet_upnp_get_ip;
176   return &api;
177 }
178
179 /**
180  * Shutdown UPNP.
181  */
182 int
183 release_module_upnp ()
184 {
185   unsigned int i;
186
187   if (cron == NULL)
188     return GNUNET_SYSERR;       /* not loaded! */
189   for (i = 0; i < maps_size; i++)
190     gaim_upnp_change_port_mapping (ectx,
191                                    cfg, GNUNET_NO, maps[i].port,
192                                    maps[i].proto);
193   GNUNET_cron_stop (cron);
194   GNUNET_cron_del_job (cron, &discover, 5 * GNUNET_CRON_MINUTES, NULL);
195   GNUNET_cron_del_job (cron, &portmap, 5 * GNUNET_CRON_MINUTES, NULL);
196   GNUNET_cron_destroy (cron);
197   kill_discovery ();
198   cron = NULL;
199   GNUNET_mutex_destroy (lock);
200   lock = NULL;
201   GNUNET_array_grow (maps, maps_size, 0);
202   ectx = NULL;
203   cfg = NULL;
204   return GNUNET_OK;
205 }
206
207
208 /* end of init.c */