paragraph for gnunet devs that don't know how to use the web
[oweals/gnunet.git] / src / gns / gnunet-gns-helper-service-w32.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2017 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 /**
19  * @file gnunet-gns-helper-service-w32.c
20  * @brief an intermediary service to access distributed GNS
21  * @author Christian Grothoff
22  * @author LRN
23  */
24 #include "platform.h"
25 #include <gnunet_util_lib.h>
26 #include <gnunet_identity_service.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_namestore_service.h>
29 #include <gnunet_gns_service.h>
30 #include <initguid.h>
31 #include "gnunet_w32nsp_lib.h"
32 #include "w32resolver.h"
33 #include <nspapi.h>
34 #include <unistr.h>
35
36 #define DEFINE_DNS_GUID(a,x) DEFINE_GUID(a, 0x00090035, 0x0000, x, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
37 DEFINE_DNS_GUID(SVCID_DNS_TYPE_A, 0x0001);
38 DEFINE_DNS_GUID(SVCID_DNS_TYPE_NS, 0x0002);
39 DEFINE_DNS_GUID(SVCID_DNS_TYPE_CNAME, 0x0005);
40 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SOA, 0x0006);
41 DEFINE_DNS_GUID(SVCID_DNS_TYPE_PTR, 0x000c);
42 DEFINE_DNS_GUID(SVCID_DNS_TYPE_MX, 0x000f);
43 DEFINE_DNS_GUID(SVCID_DNS_TYPE_TEXT, 0x0010);
44 DEFINE_DNS_GUID(SVCID_DNS_TYPE_AAAA, 0x001c);
45 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
46 DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
47 DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
48
49
50 struct request
51 {
52   /**
53    * We keep these in a doubly-linked list (for cleanup).
54    */
55   struct request *next;
56
57   /**
58    * We keep these in a doubly-linked list (for cleanup).
59    */
60   struct request *prev;
61
62   /**
63    * Client that issued the request
64    */
65   struct GNUNET_SERVICE_Client *client;
66
67   GUID sc;
68
69   int af;
70
71   wchar_t *name;
72
73   char *u8name;
74
75   struct GNUNET_GNS_LookupRequest *lookup_request;
76 };
77
78
79 /**
80  * Head of the doubly-linked list (for cleanup).
81  */
82 static struct request *rq_head;
83
84 /**
85  * Tail of the doubly-linked list (for cleanup).
86  */
87 static struct request *rq_tail;
88
89 /**
90  * Handle to GNS service.
91  */
92 static struct GNUNET_GNS_Handle *gns;
93
94 /**
95  * Active operation on identity service.
96  */
97 static struct GNUNET_IDENTITY_Operation *id_op;
98
99 /**
100  * Handle for identity service.
101  */
102 static struct GNUNET_IDENTITY_Handle *identity;
103
104 /**
105  * Public key of the gns-master ego
106  */
107 static struct GNUNET_CRYPTO_EcdsaPublicKey gns_master_pubkey;
108
109 /**
110  * Set to 1 once egos are obtained.
111  */
112 static int got_egos;
113
114
115 /**
116  * Task run on shutdown.  Cleans up everything.
117  *
118  * @param cls unused
119  */
120 static void
121 do_shutdown (void *cls)
122 {
123   struct request *rq;
124
125   if (NULL != id_op)
126   {
127     GNUNET_IDENTITY_cancel (id_op);
128     id_op = NULL;
129   }
130   if (NULL != identity)
131   {
132     GNUNET_IDENTITY_disconnect (identity);
133     identity = NULL;
134   }
135   while (NULL != (rq = rq_head))
136   {
137     if (NULL != rq->lookup_request)
138       GNUNET_GNS_lookup_cancel (rq->lookup_request);
139     GNUNET_CONTAINER_DLL_remove (rq_head,
140                                  rq_tail,
141                                  rq);
142     GNUNET_free_non_null (rq->name);
143     if (rq->u8name)
144       free (rq->u8name);
145     GNUNET_free (rq);
146   }
147   if (NULL != gns)
148   {
149     GNUNET_GNS_disconnect (gns);
150     gns = NULL;
151   }
152 }
153
154
155 #define MarshallPtr(ptr, base, type) \
156   if (ptr) \
157     ptr = (type *) ((char *) ptr - (char *) base)
158
159
160 void
161 MarshallWSAQUERYSETW (WSAQUERYSETW *qs, GUID *sc)
162 {
163   MarshallPtr (qs->lpszServiceInstanceName, qs, wchar_t);
164   MarshallPtr (qs->lpServiceClassId, qs, GUID);
165   MarshallPtr (qs->lpVersion, qs, WSAVERSION);
166   MarshallPtr (qs->lpNSProviderId, qs, GUID);
167   MarshallPtr (qs->lpszContext, qs, wchar_t);
168   MarshallPtr (qs->lpafpProtocols, qs, AFPROTOCOLS);
169   MarshallPtr (qs->lpszQueryString, qs, wchar_t);
170   for (int i = 0; i < qs->dwNumberOfCsAddrs; i++)
171   {
172     MarshallPtr (qs->lpcsaBuffer[i].LocalAddr.lpSockaddr, qs, SOCKADDR);
173     MarshallPtr (qs->lpcsaBuffer[i].RemoteAddr.lpSockaddr, qs, SOCKADDR);
174   }
175   MarshallPtr (qs->lpcsaBuffer, qs, CSADDR_INFO);
176   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, sc) && qs->lpBlob != NULL && qs->lpBlob->pBlobData != NULL)
177   {
178     struct hostent *he;
179
180     he = (struct hostent *) qs->lpBlob->pBlobData;
181     for (int i = 0; he->h_aliases[i] != NULL; i++)
182       MarshallPtr (he->h_aliases[i], he, char);
183     MarshallPtr (he->h_aliases, he, char *);
184     MarshallPtr (he->h_name, he, char);
185     for (int i = 0; he->h_addr_list[i] != NULL; i++)
186       MarshallPtr (he->h_addr_list[i], he, void);
187     MarshallPtr (he->h_addr_list, he, char *);
188     MarshallPtr (qs->lpBlob->pBlobData, qs, void);
189   }
190   MarshallPtr (qs->lpBlob, qs, BLOB);
191 }
192
193
194 static void
195 process_lookup_result (void *cls,
196                        uint32_t rd_count,
197                        const struct GNUNET_GNSRECORD_Data *rd)
198 {
199   struct request *rq = cls;
200   int i, j, csanum;
201   struct GNUNET_W32RESOLVER_GetMessage *msg;
202   struct GNUNET_MQ_Envelope *msg_env;
203   struct GNUNET_MessageHeader *msgend;
204   struct GNUNET_MQ_Envelope *msgend_env;
205   WSAQUERYSETW *qs;
206   size_t size;
207   size_t size_recalc;
208   char *ptr;
209   size_t blobsize = 0;
210   size_t blobaddrcount = 0;
211
212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213               "Got lookup result with count %u for rq %p with client %p\n",
214               rd_count,
215               rq,
216               rq->client);
217   rq->lookup_request = NULL;
218
219   if (0 == rd_count)
220   {
221     msgend_env = GNUNET_MQ_msg (msgend, GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
222     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (rq->client),
223                     msgend_env);
224     GNUNET_CONTAINER_DLL_remove (rq_head,
225                                  rq_tail,
226                                  rq);
227     GNUNET_free_non_null (rq->name);
228     if (rq->u8name)
229       free (rq->u8name);
230     GNUNET_free (rq);
231     return;
232   }
233
234   size = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
235   size += (wcslen (rq->name) + 1) * sizeof (wchar_t);
236   size += sizeof (GUID);
237   /* lpszComment ? a TXT record? */
238   size += sizeof (GUID);
239   /* lpszContext ? Not sure what it is */
240   csanum = 0;
241   for (i = 0; i < rd_count; i++)
242   {
243     switch (rd[i].record_type)
244     {
245     case GNUNET_DNSPARSER_TYPE_A:
246       if (rd[i].data_size != sizeof (struct in_addr))
247         continue;
248       size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
249       csanum++;
250       break;
251     case GNUNET_DNSPARSER_TYPE_AAAA:
252       if (rd[i].data_size != sizeof (struct in6_addr))
253         continue;
254       size += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
255       csanum++;
256       break;
257     }
258   }
259   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
260   {
261     size += sizeof (BLOB);
262     blobsize += sizeof (struct hostent);
263     blobsize += strlen (rq->u8name) + 1;
264     blobsize += sizeof (void *); /* For aliases */
265     blobsize += sizeof (void *); /* For addresses */
266     for (i = 0; i < rd_count; i++)
267     {
268       if ((rq->af == AF_INET || rq->af == AF_UNSPEC) && rd[i].record_type == GNUNET_DNSPARSER_TYPE_A)
269       {
270         blobsize += sizeof (void *);
271         blobsize += sizeof (struct in_addr);
272         blobaddrcount++;
273       }
274       else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_DNSPARSER_TYPE_AAAA)
275       {
276         blobsize += sizeof (void *);
277         blobsize += sizeof (struct in6_addr);
278         blobaddrcount++;
279       }
280     }
281     size += blobsize;
282   }
283   size_recalc = sizeof (struct GNUNET_W32RESOLVER_GetMessage) + sizeof (WSAQUERYSETW);
284   msg_env = GNUNET_MQ_msg_extra (msg,
285                                  size - sizeof (struct GNUNET_MessageHeader),
286                                  GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
287   msg->af = htonl (rq->af);
288   msg->sc_data1 = htonl (rq->sc.Data1);
289   msg->sc_data2 = htons (rq->sc.Data2);
290   msg->sc_data3 = htons (rq->sc.Data3);
291   for (i = 0; i < 8; i++)
292     msg->sc_data4[i] = rq->sc.Data4[i];
293   qs = (WSAQUERYSETW *) &msg[1];
294   ptr = (char *) &qs[1];
295   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
296   qs->dwSize = sizeof (WSAQUERYSETW);
297   qs->lpszServiceInstanceName = (wchar_t *) ptr;
298   ptr += (wcslen (rq->name) + 1) * sizeof (wchar_t);
299   size_recalc += (wcslen (rq->name) + 1) * sizeof (wchar_t);
300   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
301   wcscpy (qs->lpszServiceInstanceName, rq->name);
302   qs->lpServiceClassId = (GUID *) ptr;
303   ptr += sizeof (GUID);
304   size_recalc += sizeof (GUID);
305   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
306   GNUNET_memcpy (qs->lpServiceClassId, &rq->sc, sizeof (GUID));
307   qs->lpVersion = NULL;
308   qs->dwNameSpace = NS_DNS;
309   qs->lpNSProviderId = (GUID *) ptr;
310   ptr += sizeof (GUID);
311   size_recalc += sizeof (GUID);
312   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
313   GNUNET_memcpy (qs->lpNSProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS, sizeof (GUID));
314   qs->lpszContext = NULL;
315   qs->dwNumberOfProtocols = 0;
316   qs->lpafpProtocols = NULL;
317   /* Don't bother with this... */
318   qs->lpszQueryString = NULL;
319   qs->dwNumberOfCsAddrs = rd_count;
320   qs->lpcsaBuffer = (CSADDR_INFO *) ptr;
321   ptr += sizeof (CSADDR_INFO) * csanum;
322   j = 0;
323   for (i = 0; i < rd_count; i++)
324   {
325     switch (rd[i].record_type)
326     {
327     case GNUNET_DNSPARSER_TYPE_A:
328       if (rd[i].data_size != sizeof (struct in_addr))
329         continue;
330       qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
331       qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
332
333       qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in);
334       qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
335       ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
336       memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
337       ((struct sockaddr_in *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin_family = AF_INET;
338
339       qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in);
340       qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
341       ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
342       memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
343       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_family = AF_INET;
344       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_port = htonl (53); /* Don't ask why it's 53 */
345       ((struct sockaddr_in *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin_addr = *(struct in_addr *) rd[i].data;
346       size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in) * 2;
347       j++;
348       break;
349     case GNUNET_DNSPARSER_TYPE_AAAA:
350       if (rd[i].data_size != sizeof (struct in6_addr))
351         continue;
352       qs->lpcsaBuffer[j].iSocketType = SOCK_STREAM;
353       qs->lpcsaBuffer[j].iProtocol = IPPROTO_TCP;
354
355       qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
356       qs->lpcsaBuffer[j].LocalAddr.lpSockaddr = (SOCKADDR *) ptr;
357       ptr += qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength;
358       memset (qs->lpcsaBuffer[j].LocalAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].LocalAddr.iSockaddrLength);
359       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].LocalAddr.lpSockaddr)->sin6_family = AF_INET6;
360
361       qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_in6);
362       qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr = (SOCKADDR *) ptr;
363       ptr += qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength;
364       memset (qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr, 0, qs->lpcsaBuffer[j].RemoteAddr.iSockaddrLength);
365       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_family = AF_INET6;
366       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_port = htonl (53); /* Don't ask why it's 53 */
367       ((struct sockaddr_in6 *)qs->lpcsaBuffer[j].RemoteAddr.lpSockaddr)->sin6_addr = *(struct in6_addr *) rd[i].data;
368       size_recalc += sizeof (CSADDR_INFO) + sizeof (struct sockaddr_in6) * 2;
369       j++;
370       break;
371     default:
372       break;
373     }
374   }
375   GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
376   qs->dwOutputFlags = 0;
377   if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &rq->sc))
378   {
379     struct hostent *he;
380     qs->lpBlob = (BLOB *) ptr;
381     ptr += sizeof (BLOB);
382
383     size_recalc += sizeof (BLOB);
384     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
385
386     qs->lpBlob->cbSize = blobsize;
387     qs->lpBlob->pBlobData = (BYTE *) ptr;
388     ptr += sizeof (struct hostent);
389
390     size_recalc += sizeof (struct hostent);
391     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
392
393     he = (struct hostent *) qs->lpBlob->pBlobData;
394     he->h_name = (char *) ptr;
395     ptr += strlen (rq->u8name) + 1;
396
397     size_recalc += strlen (rq->u8name) + 1;
398     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
399
400     strcpy (he->h_name, rq->u8name);
401     he->h_aliases = (char **) ptr;
402     ptr += sizeof (void *);
403
404     size_recalc += sizeof (void *); /* For aliases */
405     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
406
407     he->h_aliases[0] = NULL;
408     he->h_addrtype = rq->af;
409     he->h_length = rq->af == AF_INET || rq->af == AF_UNSPEC ? sizeof (struct in_addr) : sizeof (struct in6_addr);
410     he->h_addr_list = (char **) ptr;
411     ptr += sizeof (void *) * (blobaddrcount + 1);
412
413     size_recalc += sizeof (void *) * (blobaddrcount + 1); /* For addresses */
414     GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
415
416     j = 0;
417     for (i = 0; i < rd_count; i++)
418     {
419       if ((rq->af == AF_INET || rq->af == AF_UNSPEC) &&
420           rd[i].record_type == GNUNET_DNSPARSER_TYPE_A)
421       {
422         he->h_addr_list[j] = (char *) ptr;
423         ptr += sizeof (struct in_addr);
424
425         size_recalc += sizeof (struct in_addr);
426         GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
427
428         GNUNET_memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in_addr));
429         j++;
430       }
431       else if (rq->af == AF_INET6 && rd[i].record_type == GNUNET_DNSPARSER_TYPE_AAAA)
432       {
433         he->h_addr_list[j] = (char *) ptr;
434         ptr += sizeof (struct in6_addr);
435
436         size_recalc += sizeof (struct in6_addr);
437         GNUNET_break (size_recalc == (size_t) ((char *) ptr - (char *) msg));
438
439         GNUNET_memcpy (he->h_addr_list[j], rd[i].data, sizeof (struct in6_addr));
440         j++;
441       }
442     }
443     he->h_addr_list[j] = NULL;
444   }
445   msgend_env = GNUNET_MQ_msg (msgend, GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE);
446
447   if ((char *) ptr - (char *) msg != size || size_recalc != size || size_recalc != ((char *) ptr - (char *) msg))
448   {
449     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
450                 "Error in WSAQUERYSETW size calc: expected %u, got %lu (recalc %u)\n",
451                 size,
452                 (unsigned long) ((char *) ptr - (char *) msg),
453                 size_recalc);
454   }
455   MarshallWSAQUERYSETW (qs, &rq->sc);
456   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (rq->client),
457                   msg_env);
458   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (rq->client),
459                   msgend_env);
460   GNUNET_CONTAINER_DLL_remove (rq_head,
461                                rq_tail,
462                                rq);
463   GNUNET_free_non_null (rq->name);
464   if (rq->u8name)
465     free (rq->u8name);
466   GNUNET_free (rq);
467 }
468
469
470 static void
471 get_ip_from_hostname (struct GNUNET_SERVICE_Client *client,
472                       const wchar_t *name,
473                       int af,
474                       GUID sc)
475 {
476   struct request *rq;
477   char *hostname;
478   size_t strl;
479   size_t namelen;
480   uint32_t rtype;
481
482   if (IsEqualGUID (&SVCID_DNS_TYPE_A, &sc))
483     rtype = GNUNET_DNSPARSER_TYPE_A;
484   else if (IsEqualGUID (&SVCID_DNS_TYPE_NS, &sc))
485     rtype = GNUNET_DNSPARSER_TYPE_NS;
486   else if (IsEqualGUID (&SVCID_DNS_TYPE_CNAME, &sc))
487     rtype = GNUNET_DNSPARSER_TYPE_CNAME;
488   else if (IsEqualGUID (&SVCID_DNS_TYPE_SOA, &sc))
489     rtype = GNUNET_DNSPARSER_TYPE_SOA;
490   else if (IsEqualGUID (&SVCID_DNS_TYPE_PTR, &sc))
491     rtype = GNUNET_DNSPARSER_TYPE_PTR;
492   else if (IsEqualGUID (&SVCID_DNS_TYPE_MX, &sc))
493     rtype = GNUNET_DNSPARSER_TYPE_MX;
494   else if (IsEqualGUID (&SVCID_DNS_TYPE_TEXT, &sc))
495     rtype = GNUNET_DNSPARSER_TYPE_TXT;
496   else if (IsEqualGUID (&SVCID_DNS_TYPE_AAAA, &sc))
497     rtype = GNUNET_DNSPARSER_TYPE_AAAA;
498   else if (IsEqualGUID (&SVCID_DNS_TYPE_SRV, &sc))
499     rtype = GNUNET_DNSPARSER_TYPE_SRV;
500   else if (IsEqualGUID (&SVCID_INET_HOSTADDRBYNAME, &sc))
501     rtype = GNUNET_DNSPARSER_TYPE_A;
502   else
503   {
504     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
505                 "Unknown GUID: %08lX-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
506                 sc.Data1,
507                 sc.Data2,
508                 sc.Data3,
509                 sc.Data4[0],
510                 sc.Data4[1],
511                 sc.Data4[2],
512                 sc.Data4[3],
513                 sc.Data4[4],
514                 sc.Data4[5],
515                 sc.Data4[6],
516                 sc.Data4[7]);
517     GNUNET_SERVICE_client_drop (client);
518     return;
519   }
520
521   if (name)
522     namelen = wcslen (name);
523   else
524     namelen = 0;
525   if (namelen > 0)
526     hostname = (char *) u16_to_u8 (name, namelen + 1, NULL, &strl);
527   else
528     hostname = NULL;
529
530   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531               "W32 DNS resolver asked to look up %s for `%s'.\n",
532               af == AF_INET ? "IPv4" : af == AF_INET6 ? "IPv6" : "anything",
533               hostname);
534
535   rq = GNUNET_new (struct request);
536   rq->sc = sc;
537   rq->client = client;
538   rq->af = af;
539   if (rq->af != AF_INET && rq->af != AF_INET6)
540     rq->af = AF_INET;
541   if (namelen)
542   {
543     rq->name = GNUNET_malloc ((namelen + 1) * sizeof (wchar_t));
544     GNUNET_memcpy (rq->name,
545                    name,
546                    (namelen + 1) * sizeof (wchar_t));
547     rq->u8name = hostname;
548   }
549
550   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551               "Launching a lookup for client %p with rq %p\n",
552               client,
553               rq);
554   rq->lookup_request = GNUNET_GNS_lookup (gns,
555                                           hostname,
556                                           &gns_master_pubkey,
557                                           rtype,
558                                           GNUNET_NO /* Use DHT */,
559                                           &process_lookup_result,
560                                           rq);
561   if (NULL != rq->lookup_request)
562   {
563     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564                 "Lookup launched, waiting for a reply\n");
565     GNUNET_SERVICE_client_continue (client);
566     GNUNET_CONTAINER_DLL_insert (rq_head,
567                                  rq_tail,
568                                  rq);
569   }
570   else
571   {
572     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
573                 "Lookup was not launched, disconnecting the client\n");
574     GNUNET_free_non_null (rq->name);
575     if (rq->u8name)
576       free (rq->u8name);
577     GNUNET_free (rq);
578     GNUNET_SERVICE_client_drop (client);
579   }
580 }
581
582
583 /**
584  * Check GET-message.
585  *
586  * @param cls identification of the client
587  * @param msg the actual message
588  * @return #GNUNET_OK if @a msg is well-formed
589  */
590 static int
591 check_get (void *cls,
592             const struct GNUNET_W32RESOLVER_GetMessage *msg)
593 {
594   uint16_t size;
595   const wchar_t *hostname;
596
597   if (! got_egos)
598   {
599     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
600                 _("Not ready to process requests, lacking ego data\n"));
601     return GNUNET_SYSERR;
602   }
603   size = ntohs (msg->header.size) - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
604   hostname = (const wchar_t *) &msg[1];
605   if (hostname[size / 2 - 1] != L'\0')
606   {
607     GNUNET_break (0);
608     return GNUNET_SYSERR;
609   }
610   return GNUNET_OK;
611 }
612
613
614 /**
615  * Handle GET-message.
616  *
617  * @param cls identification of the client
618  * @param msg the actual message
619  */
620 static void
621 handle_get (void *cls,
622             const struct GNUNET_W32RESOLVER_GetMessage *msg)
623 {
624   struct GNUNET_SERVICE_Client *client = cls;
625   GUID sc;
626   uint16_t size;
627   const wchar_t *hostname;
628   int af;
629
630   size = ntohs (msg->header.size) - sizeof (struct GNUNET_W32RESOLVER_GetMessage);
631   af = ntohl (msg->af);
632   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
633               "Got NBO GUID: %08X-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
634               msg->sc_data1,
635               msg->sc_data2,
636               msg->sc_data3,
637               msg->sc_data4[0],
638               msg->sc_data4[1],
639               msg->sc_data4[2],
640               msg->sc_data4[3],
641               msg->sc_data4[4],
642               msg->sc_data4[5],
643               msg->sc_data4[6],
644               msg->sc_data4[7]);
645   sc.Data1 = ntohl (msg->sc_data1);
646   sc.Data2 = ntohs (msg->sc_data2);
647   sc.Data3 = ntohs (msg->sc_data3);
648   for (int i = 0; i < 8; i++)
649     sc.Data4[i] = msg->sc_data4[i];
650   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651               "Got GUID: %08lX-%04X-%04X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
652               sc.Data1,
653               sc.Data2,
654               sc.Data3,
655               sc.Data4[0],
656               sc.Data4[1],
657               sc.Data4[2],
658               sc.Data4[3],
659               sc.Data4[4],
660               sc.Data4[5],
661               sc.Data4[6],
662               sc.Data4[7]);
663   hostname = (const wchar_t *) &msg[1];
664   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665               "Name of %u bytes (last word is 0x%0X): %*S\n",
666               size,
667               hostname[size / 2 - 2],
668               size / 2,
669               hostname);
670   get_ip_from_hostname (client,
671                         hostname,
672                         af,
673                         sc);
674 }
675
676
677 /**
678  * Method called to with the ego we are to use for the lookup,
679  * when the ego is the one for the default master zone.
680  *
681  * @param cls closure (NULL, unused)
682  * @param ego ego handle, NULL if not found
683  * @param ctx context for application to store data for this ego
684  *                 (during the lifetime of this process, initially NULL)
685  * @param name name assigned by the user for this ego,
686  *                   NULL if the user just deleted the ego and it
687  *                   must thus no longer be used
688  */
689 static void
690 identity_master_cb (void *cls,
691                     struct GNUNET_IDENTITY_Ego *ego,
692                     void **ctx,
693                     const char *name)
694 {
695   id_op = NULL;
696   if (NULL == ego)
697   {
698     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
699                 _("Ego for `gns-master' not found, cannot perform lookup.  Did you run gnunet-gns-import.sh?\n"));
700     GNUNET_SCHEDULER_shutdown ();
701     return;
702   }
703   GNUNET_IDENTITY_ego_get_public_key (ego,
704                                       &gns_master_pubkey);
705   got_egos = 1;
706 }
707
708
709 /**
710  * Start up gns-helper-w32 service.
711  *
712  * @param cls closure
713  * @param cfg configuration to use
714  * @param service the initialized service
715  */
716 static void
717 run (void *cls,
718      const struct GNUNET_CONFIGURATION_Handle *cfg,
719      struct GNUNET_SERVICE_Handle *service)
720 {
721   gns = GNUNET_GNS_connect (cfg);
722   if (NULL == gns)
723   {
724     fprintf (stderr,
725              _("Failed to connect to GNS\n"));
726     GNUNET_SCHEDULER_shutdown ();
727     return;
728   }
729   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
730                                  NULL);
731   identity = GNUNET_IDENTITY_connect (cfg,
732                                       NULL,
733                                       NULL);
734   if (NULL == identity)
735   {
736     fprintf (stderr,
737              _("Failed to connect to identity service\n"));
738     GNUNET_SCHEDULER_shutdown ();
739     return;
740   }
741   id_op = GNUNET_IDENTITY_get (identity,
742                                "gns-master",
743                                &identity_master_cb,
744                                NULL);
745   GNUNET_assert (NULL != id_op);
746 }
747
748
749 /**
750  * Handle client connecting to the service.
751  *
752  * @param cls NULL
753  * @param client the new client
754  * @param mq the message queue of @a client
755  * @return @a client
756  */
757 static void *
758 client_connect_cb (void *cls,
759                    struct GNUNET_SERVICE_Client *client,
760                    struct GNUNET_MQ_Handle *mq)
761 {
762   return client;
763 }
764
765
766 /**
767  * Callback called when a client disconnected from the service
768  *
769  * @param cls closure for the service
770  * @param c the client that disconnected
771  * @param internal_cls should be equal to @a c
772  */
773 static void
774 client_disconnect_cb (void *cls,
775                       struct GNUNET_SERVICE_Client *client,
776                       void *internal_cls)
777 {
778   GNUNET_assert (internal_cls == client);
779 }
780
781
782 /**
783  * Define "main" method using service macro.
784  */
785 GNUNET_SERVICE_MAIN
786 ("gns-helper-service-w32",
787  GNUNET_SERVICE_OPTION_NONE,
788  &run,
789  &client_connect_cb,
790  &client_disconnect_cb,
791  NULL,
792  GNUNET_MQ_hd_var_size (get,
793                         GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST,
794                         struct GNUNET_W32RESOLVER_GetMessage,
795                         NULL),
796  GNUNET_MQ_handler_end());
797
798
799 /* end of gnunet-gns-helper-service-w32.c */