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