1 /* This code is partially based upon samples from the book
\r
2 * "Network Programming For Microsoft Windows, 2Nd Edition".
\r
9 #include <ws2tcpip.h>
\r
13 # define DEBUGLOG(s, ...)
\r
16 # define DEBUGLOG(s, ...) printf (s, ##__VA_ARGS__)
\r
23 #define __BYTE_ORDER _BYTE_ORDER
26 #define __BYTE_ORDER BYTE_ORDER
32 #define __BIG_ENDIAN _BIG_ENDIAN
35 #define __BIG_ENDIAN BIG_ENDIAN
39 #ifndef __LITTLE_ENDIAN
41 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
44 #define __LITTLE_ENDIAN LITTLE_ENDIAN
48 #include <gnunet_w32nsp_lib.h>
\r
49 #include <w32resolver.h>
\r
51 #define NSPAPI_VERSION_MAJOR 4
\r
52 #define NSPAPI_VERSION_MINOR 4
\r
54 #define REPLY_LIFETIME 60*5
\r
56 #define STATE_BEGIN 0x01
\r
57 #define STATE_END 0x02
\r
58 #define STATE_REPLY 0x04
\r
59 #define STATE_GHBN 0x08
\r
62 GNUNET_htonll (uint64_t n)
64 #if __BYTE_ORDER == __BIG_ENDIAN
66 #elif __BYTE_ORDER == __LITTLE_ENDIAN
67 return (((uint64_t) htonl (n)) << 32) + htonl (n >> 32);
69 #error byteorder undefined
73 CRITICAL_SECTION records_cs;
\r
84 static struct record *records = NULL;
\r
85 static size_t records_len = 0;
\r
86 static size_t records_size = 0;
\r
91 size_t new_size = records_len > 0 ? records_len * 2 : 5;
\r
92 struct record *new_records = malloc (new_size * sizeof (struct record));
\r
93 if (new_records == NULL)
\r
95 SetLastError (WSA_NOT_ENOUGH_MEMORY);
\r
98 memcpy (new_records, records, records_len * sizeof (struct record));
\r
99 memset (&new_records[records_len], 0, sizeof (struct record) * (new_size - records_len));
\r
100 records_size = new_size;
\r
102 records = new_records;
\r
107 add_record (SOCKET s, const wchar_t *name, DWORD flags)
\r
112 //EnterCriticalSection (&records_cs);
\r
113 for (i = 0; i < records_len; i++)
\r
114 if (records[i].state == 0)
\r
117 if (i == records_len)
\r
119 res = resize_records ();
\r
121 empty = records_len++;
\r
128 r.name = (wchar_t *) name;
\r
132 r.name = wcsdup (name);
\r
133 records[empty] = r;
\r
135 //LeaveCriticalSection (&records_cs);
\r
140 free_record (int i)
\r
142 if (records[i].name)
\r
143 free (records[i].name);
\r
144 records[i].state = 0;
\r
147 /* These are not defined by mingw.org headers at the moment*/
\r
148 typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);
\r
149 typedef struct _NSP_ROUTINE_XP {
\r
151 DWORD dwMajorVersion;
152 DWORD dwMinorVersion;
153 LPNSPCLEANUP NSPCleanup;
154 LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
155 LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
156 LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
157 LPNSPSETSERVICE NSPSetService;
158 LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
159 LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
160 LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
162 } NSP_ROUTINE_XP, *PNSP_ROUTINE_XP, *LPNSP_ROUTINE_XP;
165 connect_to_dns_resolver ()
\r
167 struct sockaddr_in addr;
\r
171 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
\r
172 if (INVALID_SOCKET == r)
\r
174 SetLastError (16004);
\r
178 addr.sin_family = AF_INET;
\r
179 addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */
\r
180 addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
\r
182 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
\r
183 if (SOCKET_ERROR == ret)
\r
185 DWORD err = GetLastError ();
\r
187 SetLastError (err);
\r
188 SetLastError (16005);
\r
189 r = INVALID_SOCKET;
\r
195 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
\r
196 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
\r
199 struct GNUNET_W32RESOLVER_GetMessage *msg;
206 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
\r
207 size_t namelen = 0;
\r
208 if (lpqsRestrictions->lpszServiceInstanceName)
\r
209 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
\r
211 buf = malloc (size);
\r
212 msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;
\r
213 msg->header.size = htons (size);
214 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
215 if (lpqsRestrictions->dwNumberOfProtocols > 0)
218 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
220 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
222 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
227 msg->af = htonl (AF_INET);
228 else if (af6 && !af4)
229 msg->af = htonl (AF_INET6);
231 msg->af = htonl (AF_UNSPEC);
232 if (lpqsRestrictions->lpszServiceInstanceName)
233 memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
234 msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
235 msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
236 msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
238 for (i = 0; i < 8; i++)
239 msg->sc_data4 |= ((uint64_t) lpqsRestrictions->lpServiceClassId->Data4[i]) << ((7 - i) * 8);
240 msg->sc_data4 = GNUNET_htonll (msg->sc_data4);
241 *resolver = connect_to_dns_resolver ();
242 if (*resolver != INVALID_SOCKET)
244 if (size != send (*resolver, buf, size, 0))
\r
246 DWORD err = GetLastError ();
\r
247 closesocket (*resolver);
\r
248 *resolver = INVALID_SOCKET;
\r
249 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
\r
250 SetLastError (WSATRY_AGAIN);
\r
261 NSPCleanup (LPGUID lpProviderId)
\r
263 DEBUGLOG ("NSPCleanup\n");
\r
264 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
\r
268 SetLastError (WSAEINVALIDPROVIDER);
\r
269 return SOCKET_ERROR;
\r
273 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
\r
277 case DLL_PROCESS_ATTACH:
\r
278 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
\r
283 case DLL_THREAD_ATTACH:
\r
285 case DLL_THREAD_DETACH:
\r
287 case DLL_PROCESS_DETACH:
\r
288 DeleteCriticalSection (&records_cs);
\r
298 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
\r
299 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
\r
300 LPHANDLE lphLookup)
\r
302 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
\r
303 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
\r
306 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
\r
308 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
\r
309 SetLastError (WSANO_DATA);
\r
310 return SOCKET_ERROR;
\r
312 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
\r
314 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
\r
315 size_t len = wcslen (s);
\r
316 if (len >= 4 && wcscmp (&s[len - 4], L"zkey") == 0)
\r
319 else if (len >= 6 && wcscmp (&s[len - 6], L"gnunet") == 0)
\r
324 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
\r
325 SetLastError (WSANO_DATA);
\r
326 return SOCKET_ERROR;
\r
330 if (send_name_to_ip_request (lpqsRestrictions,
\r
331 lpServiceClassInfo, dwControlFlags, &s))
\r
333 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
\r
335 DWORD err = GetLastError ();
\r
336 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
\r
338 SetLastError (err);
\r
339 return SOCKET_ERROR;
\r
341 *lphLookup = (HANDLE) s;
\r
342 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
\r
345 return SOCKET_ERROR;
\r
347 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
\r
348 SetLastError (WSAEINVALIDPROVIDER);
\r
349 return SOCKET_ERROR;
\r
352 #define UnmarshallPtr(ptr, ptrtype, base) \
\r
354 ptr = (ptrtype *) (base + (uintptr_t) ptr)
\r
357 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
\r
360 char *base = (char *) req;
\r
361 UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);
\r
362 UnmarshallPtr (req->lpServiceClassId, GUID, base);
\r
363 UnmarshallPtr (req->lpVersion, WSAVERSION, base);
\r
364 UnmarshallPtr (req->lpszComment, wchar_t, base);
\r
365 UnmarshallPtr (req->lpNSProviderId, GUID, base);
\r
366 UnmarshallPtr (req->lpszContext, wchar_t, base);
\r
367 UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);
\r
368 UnmarshallPtr (req->lpszQueryString, wchar_t, base);
\r
369 UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);
\r
370 for (i = 0; i < req->dwNumberOfCsAddrs; i++)
\r
372 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
\r
373 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
\r
375 UnmarshallPtr (req->lpBlob, BLOB, base);
\r
377 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
\r
381 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
\r
382 LPDWORD lpdwBufferLength, LPWSAQUERYSET lpqsResults)
\r
384 DWORD effective_flags;
\r
386 struct GNUNET_MessageHeader header = {0, 0};
393 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
\r
394 //EnterCriticalSection (&records_cs);
\r
395 for (i = 0; i < records_len; i++)
\r
397 if (records[i].s == (SOCKET) hLookup)
\r
405 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
\r
406 SetLastError (WSA_INVALID_HANDLE);
\r
407 //LeaveCriticalSection (&records_cs);
\r
408 return SOCKET_ERROR;
\r
410 if (records[rec].state & 4)
\r
412 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
\r
413 SetLastError (WSA_E_NO_MORE);
\r
414 //LeaveCriticalSection (&records_cs);
\r
415 return SOCKET_ERROR;
\r
417 effective_flags = dwControlFlags & records[rec].flags;
\r
418 if (records[rec].buf)
\r
420 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
\r
421 if (dwControlFlags & LUP_FLUSHCACHE)
\r
423 free (records[rec].buf);
\r
424 records[rec].buf = NULL;
\r
428 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
\r
430 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
\r
431 SetLastError (WSAEFAULT);
\r
432 //LeaveCriticalSection (&records_cs);
\r
433 return SOCKET_ERROR;
\r
435 memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
\r
436 free (records[rec].buf);
\r
437 records[rec].buf = NULL;
\r
438 //LeaveCriticalSection (&records_cs);
\r
439 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
\r
440 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
\r
444 records[rec].state |= 8;
\r
445 //LeaveCriticalSection (&records_cs);
\r
446 to_receive = sizeof (header);
\r
448 while (to_receive > 0)
\r
450 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
\r
459 //EnterCriticalSection (&records_cs);
\r
460 records[rec].state &= ~8;
\r
461 if (rc != sizeof (header))
\r
463 if (records[rec].state & 2)
\r
465 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
\r
466 SetLastError (WSA_E_CANCELLED);
\r
470 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
\r
471 SetLastError (WSA_E_NO_MORE);
\r
473 records[rec].state |= 4;
\r
474 //LeaveCriticalSection (&records_cs);
\r
475 return SOCKET_ERROR;
\r
477 records[rec].state &= ~8;
\r
478 header.type = ntohs (header.type);
\r
479 header.size = ntohs (header.size);
\r
480 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
\r
481 (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
\r
482 header.size == sizeof (header)))
\r
484 records[rec].state |= 4;
\r
485 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header is wrong or type is wrong or no data\n");
\r
486 //LeaveCriticalSection (&records_cs);
\r
487 SetLastError (WSA_E_NO_MORE);
\r
488 return SOCKET_ERROR;
\r
490 buf = malloc (header.size);
\r
493 records[rec].state |= 4;
\r
494 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
\r
495 //LeaveCriticalSection (&records_cs);
\r
496 SetLastError (WSA_E_NO_MORE);
\r
497 return SOCKET_ERROR;
\r
499 records[rec].state |= 8;
\r
500 //LeaveCriticalSection (&records_cs);
\r
501 memcpy (buf, &header, sizeof (header));
\r
502 to_receive = header.size - sizeof (header);
\r
504 while (to_receive > 0)
\r
506 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
\r
515 //EnterCriticalSection (&records_cs);
\r
516 records[rec].state &= ~8;
\r
517 if (rc != header.size - sizeof (header))
\r
520 if (records[rec].state & 2)
\r
522 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
\r
523 SetLastError (WSA_E_CANCELLED);
\r
527 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
\r
528 SetLastError (WSA_E_NO_MORE);
\r
530 records[rec].state |= 4;
\r
531 //LeaveCriticalSection (&records_cs);
\r
532 return SOCKET_ERROR;
\r
534 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
\r
536 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
\r
537 SetLastError (WSAEFAULT);
\r
538 records[rec].buf = buf;
\r
539 //LeaveCriticalSection (&records_cs);
\r
540 return SOCKET_ERROR;
\r
542 //LeaveCriticalSection (&records_cs);
\r
543 memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
\r
545 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
\r
546 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
\r
547 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
\r
552 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
\r
554 DWORD effective_flags;
\r
556 struct GNUNET_MessageHeader header = {0, 0};
561 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
\r
562 //EnterCriticalSection (&records_cs);
\r
563 for (i = 0; i < records_len; i++)
\r
565 if (records[i].s == (SOCKET) hLookup)
\r
573 SetLastError (WSA_INVALID_HANDLE);
\r
574 //LeaveCriticalSection (&records_cs);
\r
575 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
\r
576 return SOCKET_ERROR;
\r
578 records[rec].state |= 2;
\r
579 closesocket (records[rec].s);
\r
580 while (records[rec].state & 8)
\r
582 //LeaveCriticalSection (&records_cs);
\r
584 //EnterCriticalSection (&records_cs);
\r
586 if (records[rec].buf)
\r
587 free (records[rec].buf);
\r
588 records[rec].buf = NULL;
\r
589 records[rec].state = 0;
\r
590 if (records[rec].name)
\r
591 free (records[rec].name);
\r
592 //LeaveCriticalSection (&records_cs);
\r
593 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");
\r
598 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
\r
599 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
\r
600 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
\r
602 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
\r
603 SetLastError (WSAEOPNOTSUPP);
\r
604 return SOCKET_ERROR;
\r
608 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
\r
609 LPWSASERVICECLASSINFOW lpServiceClassInfo)
\r
611 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
\r
612 SetLastError (WSAEOPNOTSUPP);
\r
613 return SOCKET_ERROR;
\r
618 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
\r
620 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
\r
621 SetLastError (WSAEOPNOTSUPP);
\r
622 return SOCKET_ERROR;
\r
626 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
\r
627 LPWSASERVICECLASSINFOW lpServiceClassInfo)
\r
629 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
\r
630 SetLastError (WSAEOPNOTSUPP);
\r
631 return SOCKET_ERROR;
\r
635 GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
\r
636 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
\r
637 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
\r
638 LPWSATHREADID lpThreadId)
\r
640 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
\r
641 SetLastError (WSAEOPNOTSUPP);
\r
642 return SOCKET_ERROR;
\r
646 * This function is called by Winsock to hook up our provider.
\r
647 * It is the only function that [should be/is] exported by the
\r
648 * provider. All other routines are passed as pointers in lpnspRoutines.
\r
651 NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
\r
653 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
\r
655 if (!connect_to_dns_resolver ())
\r
657 return SOCKET_ERROR;
\r
659 /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
\r
660 * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
\r
661 * and use that offset as cbSize.
\r
663 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE_XP);
\r
665 lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
\r
666 lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
\r
667 lpnspRoutines->NSPCleanup = NSPCleanup;
\r
668 lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
\r
669 lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
\r
670 lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
\r
671 lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
\r
672 lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
\r
673 lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
\r
674 lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
\r
675 ((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;
\r
678 SetLastError (WSAEINVALIDPROVIDER);
\r
679 return SOCKET_ERROR;
\r