- New winsock (part 2 of x)
[reactos.git] / dll / win32 / mswsock / rnr20 / nsp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winsock 2 SPI
4 * FILE: lib/mswsock/lib/init.c
5 * PURPOSE: DLL Initialization
6 */
7
8 /* INCLUDES ******************************************************************/
9 #include "msafd.h"
10
11 #define ALL_LUP_FLAGS (0x0BFFF)
12
13 /* DATA **********************************************************************/
14
15 LPWSTR g_pszHostName;
16 LPWSTR g_pszHostFqdn;
17 LONG g_NspRefCount;
18 GUID NbtProviderId = {0};
19 GUID DNSProviderId = {0};
20 DWORD MaskOfGuids;
21
22 NSP_ROUTINE g_NspVector = {sizeof(NSP_ROUTINE),
23 1,
24 1,
25 Dns_NSPCleanup,
26 Dns_NSPLookupServiceBegin,
27 Dns_NSPLookupServiceNext,
28 Dns_NSPLookupServiceEnd,
29 Dns_NSPSetService,
30 Dns_NSPInstallServiceClass,
31 Dns_NSPRemoveServiceClass,
32 Dns_NSPGetServiceClassInfo};
33
34 /* FUNCTIONS *****************************************************************/
35
36 INT
37 WINAPI
38 Dns_NSPStartup(IN LPGUID lpProviderId,
39 IN OUT LPNSP_ROUTINE lpsnpRoutines)
40 {
41 INT ErrorCode;
42 BOOLEAN Prolog;
43
44 /* Validate the size */
45 if (lpsnpRoutines->cbSize != sizeof(NSP_ROUTINE))
46 {
47 /* Fail */
48 SetLastError(WSAEINVALIDPROCTABLE);
49 return SOCKET_ERROR;
50 }
51
52 /* Enter the prolog */
53 Prolog = RNRPROV_SockEnterApi();
54 if (Prolog)
55 {
56 /* Increase our reference count */
57 InterlockedIncrement(&g_NspRefCount);
58
59 /* Check if we don't have the hostname */
60 if (!g_pszHostName)
61 {
62 /* Query it from DNS */
63 DnsQueryConfig(DnsConfigHostName_W,
64 DNS_CONFIG_FLAG_ALLOC,
65 NULL,
66 NULL,
67 &g_pszHostName,
68 0);
69 }
70
71 /* Check if we have a hostname now, but not a Fully-Qualified Domain */
72 if (g_pszHostName && !(g_pszHostFqdn))
73 {
74 /* Get the domain from DNS */
75 DnsQueryConfig(DnsConfigFullHostName_W,
76 DNS_CONFIG_FLAG_ALLOC,
77 NULL,
78 NULL,
79 &g_pszHostFqdn,
80 0);
81 }
82
83 /* If we don't have both of them, then set error */
84 if (!(g_pszHostName) || !(g_pszHostFqdn)) ErrorCode = SOCKET_ERROR;
85 }
86
87 /* Check if the Prolog or DNS Local Queries failed */
88 if (!(Prolog) || (ErrorCode != NO_ERROR))
89 {
90 /* Fail */
91 SetLastError(WSASYSNOTREADY);
92 return SOCKET_ERROR;
93 }
94
95 /* Copy the Routines */
96 RtlMoveMemory(lpsnpRoutines, &g_NspVector, sizeof(NSP_ROUTINE));
97
98 /* Check if this is NBT or DNS */
99 if (!memcmp(lpProviderId, &NbtProviderId, sizeof(GUID)))
100 {
101 /* Enable the NBT Mask */
102 MaskOfGuids |= NBT_MASK;
103 }
104 else if (!memcmp(lpProviderId, &DNSProviderId, sizeof(GUID)))
105 {
106 /* Enable the DNS Mask */
107 MaskOfGuids |= DNS_MASK;
108 }
109
110 /* Return success */
111 return NO_ERROR;
112 }
113
114 VOID
115 WSPAPI
116 Nsp_GlobalCleanup(VOID)
117 {
118 /* Cleanup the RnR Contexts */
119 RnrCtx_ListCleanup();
120
121 /* Free the hostnames, if we have them */
122 if (g_pszHostName) DnsApiFree(g_pszHostName);
123 if (g_pszHostFqdn) DnsApiFree(g_pszHostFqdn);
124 g_pszHostFqdn = g_pszHostName = NULL;
125 }
126
127 INT
128 WINAPI
129 NSPStartup(IN LPGUID lpProviderId,
130 IN OUT LPNSP_ROUTINE lpsnpRoutines)
131 {
132 INT ErrorCode;
133
134 /* Initialize the DLL */
135 ErrorCode = MSWSOCK_Initialize();
136 if (ErrorCode != NO_ERROR)
137 {
138 /* Fail */
139 SetLastError(WSANOTINITIALISED);
140 return SOCKET_ERROR;
141 }
142
143 /* Check if this is Winsock Mobile or DNS */
144 if (!memcmp(lpProviderId, &gNLANamespaceGuid, sizeof(GUID)))
145 {
146 /* Initialize WSM */
147 return WSM_NSPStartup(lpProviderId, lpsnpRoutines);
148 }
149
150 /* Initialize DNS */
151 return Dns_NSPStartup(lpProviderId, lpsnpRoutines);
152 }
153
154 INT
155 WINAPI
156 Dns_NSPCleanup(IN LPGUID lpProviderId)
157 {
158 /* Decrement our reference count and do global cleanup if it's reached 0 */
159 if (!(InterlockedDecrement(&g_NspRefCount))) Nsp_GlobalCleanup();
160
161 /* Return success */
162 return NO_ERROR;
163 }
164
165 INT
166 WINAPI
167 Dns_NSPSetService(IN LPGUID lpProviderId,
168 IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
169 IN LPWSAQUERYSETW lpqsRegInfo,
170 IN WSAESETSERVICEOP essOperation,
171 IN DWORD dwControlFlags)
172 {
173 /* Unlike NLA, DNS Services cannot be dynmically modified */
174 SetLastError(ERROR_NOT_SUPPORTED);
175 return SOCKET_ERROR;
176 }
177
178 INT
179 WINAPI
180 Dns_NSPInstallServiceClass(IN LPGUID lpProviderId,
181 IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
182 {
183 /* Unlike NLA, DNS Services cannot be dynmically modified */
184 SetLastError(WSAEOPNOTSUPP);
185 return SOCKET_ERROR;
186 };
187
188 INT
189 WINAPI
190 Dns_NSPRemoveServiceClass(IN LPGUID lpProviderId,
191 IN LPGUID lpServiceCallId)
192 {
193 /* Unlike NLA, DNS Services cannot be dynmically modified */
194 SetLastError(WSAEOPNOTSUPP);
195 return SOCKET_ERROR;
196 }
197 INT
198 WINAPI
199 Dns_NSPGetServiceClassInfo(IN LPGUID lpProviderId,
200 IN OUT LPDWORD lpdwBufSize,
201 IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
202 {
203 /* Unlike NLA, DNS Services cannot be dynmically modified */
204 SetLastError(WSAEOPNOTSUPP);
205 return SOCKET_ERROR;
206 }
207
208 INT
209 WINAPI
210 Dns_NSPLookupServiceEnd(IN HANDLE hLookup)
211 {
212 PRNR_CONTEXT RnrContext;
213
214 /* Get this handle's context */
215 RnrContext = RnrCtx_Get(hLookup, 0, NULL);
216
217 /* Mark it as completed */
218 RnrContext->LookupFlags |= DONE;
219
220 /* Dereference it once for our _Get */
221 RnrCtx_Release(RnrContext);
222
223 /* And once last to delete it */
224 RnrCtx_Release(RnrContext);
225
226 /* return */
227 return NO_ERROR;
228 }
229
230 INT
231 WINAPI
232 rnr_IdForGuid(IN LPGUID Guid)
233 {
234
235 if (memcmp(Guid, &InetHostName, sizeof(GUID))) return 0x10000002;
236 if (memcmp(Guid, &Ipv6Guid, sizeof(GUID))) return 0x10000023;
237 if (memcmp(Guid, &HostnameGuid, sizeof(GUID))) return 0x1;
238 if (memcmp(Guid, &AddressGuid, sizeof(GUID))) return 0x80000000;
239 if (memcmp(Guid, &IANAGuid, sizeof(GUID))) return 0x2;
240 if IS_SVCID_DNS(Guid) return 0x5000000;
241 if IS_SVCID_TCP(Guid) return 0x1000000;
242 if IS_SVCID_UDP(Guid) return 0x2000000;
243 return 0;
244 }
245
246 PVOID
247 WSPAPI
248 FlatBuf_ReserveAlignDword(IN PFLATBUFF FlatBuffer,
249 IN ULONG Size)
250 {
251 /* Let DNSLIB do the grunt work */
252 return FlatBuf_Arg_Reserve((PVOID)FlatBuffer->BufferPos,
253 &FlatBuffer->BufferFreeSize,
254 Size,
255 sizeof(PVOID));
256 }
257
258 PVOID
259 WSPAPI
260 FlatBuf_WriteString(IN PFLATBUFF FlatBuffer,
261 IN PVOID String,
262 IN BOOLEAN IsUnicode)
263 {
264 /* Let DNSLIB do the grunt work */
265 return FlatBuf_Arg_WriteString((PVOID)FlatBuffer->BufferPos,
266 &FlatBuffer->BufferFreeSize,
267 String,
268 IsUnicode);
269 }
270
271 PVOID
272 WSPAPI
273 FlatBuf_CopyMemory(IN PFLATBUFF FlatBuffer,
274 IN PVOID Buffer,
275 IN ULONG Size,
276 IN ULONG Align)
277 {
278 /* Let DNSLIB do the grunt work */
279 return FlatBuf_Arg_CopyMemory((PVOID)FlatBuffer->BufferPos,
280 &FlatBuffer->BufferFreeSize,
281 Buffer,
282 Size,
283 Align);
284 }
285
286 INT
287 WINAPI
288 Dns_NSPLookupServiceBegin(LPGUID lpProviderId,
289 LPWSAQUERYSETW lpqsRestrictions,
290 LPWSASERVICECLASSINFOW lpServiceClassInfo,
291 DWORD dwControlFlags,
292 LPHANDLE lphLookup)
293 {
294 INT ErrorCode = SOCKET_ERROR;
295 PWCHAR ServiceName = lpqsRestrictions->lpszServiceInstanceName;
296 LPGUID ServiceClassId;
297 INT RnrId;
298 ULONG LookupFlags = 0;
299 BOOL NameRequested = FALSE;
300 WCHAR StringBuffer[48];
301 ULONG i;
302 DWORD LocalProtocols;
303 ULONG ProtocolFlags;
304 PSERVENT LookupServent;
305 DWORD UdpPort, TcpPort;
306 PRNR_CONTEXT RnrContext;
307 PSOCKADDR_IN ReverseSock;
308
309 /* Check if the Size isn't weird */
310 if(lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW))
311 {
312 ErrorCode = WSAEFAULT;
313 goto Quickie;
314 }
315
316 /* Get the GUID */
317 ServiceClassId = lpqsRestrictions->lpServiceClassId;
318 if(!ServiceClassId)
319 {
320 /* No GUID, fail */
321 ErrorCode = WSA_INVALID_PARAMETER;
322 goto Quickie;
323 }
324
325 /* Get the RNR ID */
326 RnrId = rnr_IdForGuid(ServiceClassId);
327
328 /* Make sure that the control flags are valid */
329 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
330 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
331 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
332 {
333 /* Either non-recognized flags or invalid combos were passed */
334 ErrorCode = WSA_INVALID_PARAMETER;
335 goto Quickie;
336 }
337
338 /* Make sure that we have no context, and that LUP_CONTAINERS is not on */
339 if(((lpqsRestrictions->lpszContext) &&
340 (*lpqsRestrictions->lpszContext) &&
341 (wcscmp(lpqsRestrictions->lpszContext, L"\\"))) ||
342 (dwControlFlags & LUP_CONTAINERS))
343 {
344 /* We don't support contexts or LUP_CONTAINERS */
345 ErrorCode = WSANO_DATA;
346 goto Quickie;
347 }
348
349 /* Is this a Reverse Lookup? */
350 if (RnrId == 0x80000000)
351 {
352 /* Remember for later */
353 LookupFlags = REVERSE;
354 }
355 else
356 {
357 /* Is this a IANA Lookup? */
358 if (RnrId == 0x2)
359 {
360 /* Mask out this flag since it's of no use now */
361 dwControlFlags &= ~(LUP_RETURN_ADDR);
362
363 /* This is a IANA lookup, remember for later */
364 LookupFlags |= IANA;
365 }
366
367 /* Check if we need a name or not */
368 if ((RnrId == 0x1) ||
369 (RnrId == 0x10000002) ||
370 (RnrId == 0x10000023) ||
371 (RnrId == 0x10000022))
372 {
373 /* We do */
374 NameRequested = TRUE;
375 }
376 }
377
378 /* Final check to make sure if we need a name or not */
379 if (RnrId & 0x3000000) NameRequested = TRUE;
380
381 /* No Service Name was specified */
382 if(!(ServiceName) || !(*ServiceName))
383 {
384 /*
385 * A name was requested but no Service Name was given,
386 * so this is a local lookup
387 */
388 if(NameRequested)
389 {
390 /* A local Lookup */
391 LookupFlags |= LOCAL;
392 ServiceName = L"";
393 }
394 else if((LookupFlags & REVERSE) &&
395 (lpqsRestrictions->lpcsaBuffer) &&
396 (lpqsRestrictions->dwNumberOfCsAddrs == 1))
397 {
398 /* Reverse lookup, make sure a CS Address is there */
399 ReverseSock = (struct sockaddr_in*)
400 lpqsRestrictions->lpcsaBuffer->RemoteAddr.lpSockaddr;
401
402 /* Convert address to Unicode */
403 MultiByteToWideChar(CP_ACP,
404 0,
405 inet_ntoa(ReverseSock->sin_addr),
406 -1,
407 StringBuffer,
408 16);
409
410 /* Set it as the new name */
411 ServiceName = StringBuffer;
412 }
413 else
414 {
415 /* We can't do anything without a service name at this point */
416 ErrorCode = WSA_INVALID_PARAMETER;
417 goto Quickie;
418 }
419 }
420 else if(NameRequested)
421 {
422 /* Check for meaningful DNS Names */
423 if (DnsNameCompare_W(ServiceName, L"localhost") ||
424 DnsNameCompare_W(ServiceName, L"loopback"))
425 {
426 /* This is the local and/or loopback DNS name */
427 LookupFlags |= (LOCAL | LOOPBACK);
428 }
429 else if (DnsNameCompare_W(ServiceName, g_pszHostName) ||
430 DnsNameCompare_W(ServiceName, g_pszHostFqdn))
431 {
432 /* This is the local name of the computer */
433 LookupFlags |= LOCAL;
434 }
435 }
436
437 /* Check if any restrictions were made on the protocols */
438 if(lpqsRestrictions->lpafpProtocols)
439 {
440 /* Save our local copy to speed up the loop */
441 LocalProtocols = lpqsRestrictions->dwNumberOfProtocols;
442 ProtocolFlags = 0;
443
444 /* Loop the protocols */
445 for(i = 0; LocalProtocols--;)
446 {
447 /* Make sure it's a family that we recognize */
448 if ((lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET) ||
449 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET6) ||
450 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_UNSPEC) ||
451 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_ATM))
452 {
453 /* Find which one is used */
454 switch(lpqsRestrictions->lpafpProtocols[i].iProtocol)
455 {
456 case IPPROTO_UDP:
457 ProtocolFlags |= UDP;
458 break;
459 case IPPROTO_TCP:
460 ProtocolFlags |= TCP;
461 break;
462 case PF_ATM:
463 ProtocolFlags |= ATM;
464 break;
465 default:
466 break;
467 }
468 }
469 }
470 /* Make sure we have at least a valid protocol */
471 if (!ProtocolFlags)
472 {
473 /* Fail */
474 ErrorCode = WSANO_DATA;
475 goto Quickie;
476 }
477 }
478 else
479 {
480 /* No restrictions, assume TCP/UDP */
481 ProtocolFlags = (TCP | UDP);
482 }
483
484 /* Create the Servent from the Service String */
485 UdpPort = TcpPort = -1;
486 ProtocolFlags |= GetServerAndProtocolsFromString(lpqsRestrictions->lpszQueryString,
487 ServiceClassId,
488 &LookupServent);
489
490 /* Extract the port numbers */
491 if(LookupServent)
492 {
493 /* Are we using UDP? */
494 if(ProtocolFlags & UDP)
495 {
496 /* Get the UDP Port, disable the TCP Port */
497 UdpPort = ntohs(LookupServent->s_port);
498 TcpPort = -1;
499 }
500 else if(ProtocolFlags & TCP)
501 {
502 /* Get the TCP Port, disable the UDP Port */
503 TcpPort = ntohs(LookupServent->s_port);
504 UdpPort = -1;
505 }
506 }
507 else
508 {
509 /* No servent, so use the Service ID to check */
510 if(ProtocolFlags & UDP)
511 {
512 /* Get the Port from the Service ID */
513 UdpPort = FetchPortFromClassInfo(UDP,
514 ServiceClassId,
515 lpServiceClassInfo);
516 }
517 else
518 {
519 /* No UDP */
520 UdpPort = -1;
521 }
522
523 /* No servent, so use the Service ID to check */
524 if(ProtocolFlags & TCP)
525 {
526 /* Get the Port from the Service ID */
527 UdpPort = FetchPortFromClassInfo(TCP,
528 ServiceClassId,
529 lpServiceClassInfo);
530 }
531 else
532 {
533 /* No TCP */
534 TcpPort = -1;
535 }
536 }
537
538 /* Check if we still don't have a valid port by now */
539 if((TcpPort == -1) && (UdpPort == -1))
540 {
541 /* Check if this is TCP */
542 if ((ProtocolFlags & TCP) || !(ProtocolFlags & UDP))
543 {
544 /* Set the UDP Port to 0 */
545 UdpPort = 0;
546 }
547 else
548 {
549 /* Set the TCP Port to 0 */
550 TcpPort = 0;
551 }
552 }
553
554 /* Allocate a Context for this Query */
555 RnrContext = RnrCtx_Create(NULL, ServiceName);
556 RnrContext->lpServiceClassId = *ServiceClassId;
557 RnrContext->RnrId = RnrId;
558 RnrContext->dwControlFlags = dwControlFlags;
559 RnrContext->TcpPort = TcpPort;
560 RnrContext->UdpPort = UdpPort;
561 RnrContext->LookupFlags = LookupFlags;
562 RnrContext->lpProviderId = *lpProviderId;
563 RnrContext->dwNameSpace = lpqsRestrictions->dwNameSpace;
564 RnrCtx_Release(RnrContext);
565
566 /* Return the context as a handle */
567 *lphLookup = (HANDLE)RnrContext;
568
569 /* Check if this was a TCP, UDP or DNS Query */
570 if(RnrId & 0x3000000)
571 {
572 /* Get the RR Type from the Service ID */
573 RnrContext->RrType = RR_FROM_SVCID(ServiceClassId);
574 }
575
576 /* Return Success */
577 ErrorCode = ERROR_SUCCESS;
578
579 Quickie:
580 /* Check if we got here through a failure path */
581 if (ErrorCode != ERROR_SUCCESS)
582 {
583 /* Set the last error and fail */
584 SetLastError(ErrorCode);
585 return SOCKET_ERROR;
586 }
587
588 /* Return success */
589 return ERROR_SUCCESS;
590 }
591
592 INT
593 WSPAPI
594 BuildCsAddr(IN LPWSAQUERYSETW QuerySet,
595 IN PFLATBUFF FlatBuffer,
596 IN PDNS_BLOB Blob,
597 IN DWORD UdpPort,
598 IN DWORD TcpPort,
599 IN BOOLEAN ReverseLookup)
600 {
601 return WSANO_DATA;
602 }
603
604 INT
605 WINAPI
606 Dns_NSPLookupServiceNext(IN HANDLE hLookup,
607 IN DWORD dwControlFlags,
608 IN OUT LPDWORD lpdwBufferLength,
609 OUT LPWSAQUERYSETW lpqsResults)
610 {
611 INT ErrorCode;
612 WSAQUERYSETW LocalResults;
613 LONG Instance;
614 PRNR_CONTEXT RnrContext = NULL;
615 FLATBUFF FlatBuffer;
616 PVOID Name;
617 PDNS_BLOB Blob = NULL;
618 DWORD PortNumber;
619 PSERVENT ServEntry = NULL;
620 PDNS_ARRAY DnsArray;
621 BOOLEAN IsUnicode = TRUE;
622 SIZE_T FreeSize;
623 ULONG BlobSize;
624 ULONG_PTR Position;
625 PVOID BlobData = NULL;
626 ULONG StringLength;
627 LPWSTR UnicodeName;
628
629 /* Make sure that the control flags are valid */
630 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
631 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
632 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
633 {
634 /* Either non-recognized flags or invalid combos were passed */
635 ErrorCode = WSA_INVALID_PARAMETER;
636 goto Quickie;
637 }
638
639 /* Get the Context */
640 RnrContext = RnrCtx_Get(hLookup, dwControlFlags, &Instance);
641 if (!RnrContext)
642 {
643 /* This lookup handle must be invalid */
644 SetLastError(WSA_INVALID_HANDLE);
645 return SOCKET_ERROR;
646 }
647
648 /* Assume success for now */
649 SetLastError(NO_ERROR);
650
651 /* Validate the query set size */
652 if (*lpdwBufferLength < sizeof(WSAQUERYSETW))
653 {
654 /* Windows doesn't fail, but sets up a local QS for you... */
655 lpqsResults = &LocalResults;
656 ErrorCode = WSAEFAULT;
657 }
658
659 /* Zero out the buffer and fill out basic data */
660 RtlZeroMemory(lpqsResults, sizeof(WSAQUERYSETW));
661 lpqsResults->dwNameSpace = NS_DNS;
662 lpqsResults->dwSize = sizeof(WSAQUERYSETW);
663
664 /* Initialize the Buffer */
665 FlatBuf_Init(&FlatBuffer,
666 lpqsResults + 1,
667 (ULONG)(*lpdwBufferLength - sizeof(WSAQUERYSETW)));
668
669 /* Check if this is an IANA Lookup */
670 if(RnrContext->LookupFlags & IANA)
671 {
672 /* Service Lookup */
673 GetServerAndProtocolsFromString(RnrContext->ServiceName,
674 (LPGUID)&HostnameGuid,
675 &ServEntry);
676
677 /* Get the Port */
678 PortNumber = ntohs(ServEntry->s_port);
679
680 /* Use this as the name */
681 Name = ServEntry->s_name;
682 IsUnicode = FALSE;
683
684 /* Override some parts of the Context and check for TCP/UDP */
685 if(!_stricmp("tcp", ServEntry->s_proto))
686 {
687 /* Set the TCP Guid */
688 SET_TCP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
689 RnrContext->TcpPort = PortNumber;
690 RnrContext->UdpPort = -1;
691 }
692 else
693 {
694 /* Set the UDP Guid */
695 SET_UDP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
696 RnrContext->UdpPort = PortNumber;
697 RnrContext->TcpPort = -1;
698 }
699 }
700 else
701 {
702 /* Check if the caller requested for RES_SERVICE */
703 if(RnrContext->dwControlFlags & LUP_RES_SERVICE)
704 {
705 /* Make sure that this is the first instance */
706 if (Instance)
707 {
708 /* Fail */
709 ErrorCode = WSA_E_NO_MORE;
710 goto Quickie;
711 }
712
713 #if 0
714 /* Create the blob */
715 DnsArray = NULL;
716 Blob = SaBlob_CreateFromIp4(RnrContext->ServiceName,
717 1,
718 &DnsArray);
719 #else
720 /* FIXME */
721 Blob = NULL;
722 DnsArray = NULL;
723 ErrorCode = WSAEFAULT;
724 goto Quickie;
725 #endif
726 }
727 else if(!(Blob = RnrContext->CachedSaBlob))
728 {
729 /* An actual Host Lookup, but we don't have a cached HostEntry yet */
730 if (!memcmp(&RnrContext->lpServiceClassId,
731 &HostnameGuid,
732 sizeof(GUID)) && !(RnrContext->ServiceName))
733 {
734 /* Do a Regular DNS Lookup */
735 Blob = Rnr_DoHostnameLookup(RnrContext);
736 }
737 else if (RnrContext->LookupFlags & REVERSE)
738 {
739 /* Do a Reverse DNS Lookup */
740 Blob = Rnr_GetHostByAddr(RnrContext);
741 }
742 else
743 {
744 /* Do a Hostname Lookup */
745 Blob = Rnr_DoDnsLookup(RnrContext);
746 }
747
748 /* Check if we got a blob, and cache it */
749 if (Blob) RnrContext->CachedSaBlob = Blob;
750 }
751
752 /* We should have a blob by now */
753 if (!Blob)
754 {
755 /* We dont, fail */
756 if (ErrorCode == NO_ERROR)
757 {
758 /* Supposedly no error, so find it out */
759 ErrorCode = GetLastError();
760 if (ErrorCode == NO_ERROR) ErrorCode = WSASERVICE_NOT_FOUND;
761 }
762
763 /* Fail */
764 goto Quickie;
765 }
766 }
767
768 /* Check if this is the first instance or not */
769 if(!RnrContext->Instance)
770 {
771 /* It is, get the name from the blob */
772 Name = Blob->Name;
773 }
774 else
775 {
776 /* Only accept this scenario if the caller wanted Aliases */
777 if((RnrContext->dwControlFlags & LUP_RETURN_ALIASES) &&
778 (Blob->AliasCount > RnrContext->Instance))
779 {
780 /* Get the name from the Alias */
781 Name = Blob->Aliases[RnrContext->Instance];
782
783 /* Let the caller know that this is an Alias */
784 /* lpqsResults->dwOutputFlags |= RESULT_IS_ALIAS; */
785 }
786 else
787 {
788 /* Fail */
789 ErrorCode = WSA_E_NO_MORE;
790 goto Quickie;
791 }
792 }
793
794 /* Lookups are complete... time to return the right stuff! */
795 lpqsResults->dwNameSpace = NS_DNS;
796
797 /* Caller wants the Type back */
798 if(RnrContext->dwControlFlags & LUP_RETURN_TYPE)
799 {
800 /* Copy into the flat buffer and point to it */
801 lpqsResults->lpServiceClassId = FlatBuf_CopyMemory(&FlatBuffer,
802 &RnrContext->lpServiceClassId,
803 sizeof(GUID),
804 sizeof(PVOID));
805 }
806
807 /* Caller wants the Addreses Back */
808 if((RnrContext->dwControlFlags & LUP_RETURN_ADDR) && (Blob))
809 {
810 /* Build the CS Addr for the caller */
811 ErrorCode = BuildCsAddr(lpqsResults,
812 &FlatBuffer,
813 Blob,
814 RnrContext->UdpPort,
815 RnrContext->TcpPort,
816 (RnrContext->LookupFlags & REVERSE) == 1);
817 }
818
819 /* Caller wants a Blob */
820 if(RnrContext->dwControlFlags & LUP_RETURN_BLOB)
821 {
822 /* Save the current size and position */
823 FreeSize = FlatBuffer.BufferFreeSize;
824 Position = FlatBuffer.BufferPos;
825
826 /* Allocate some space for the Public Blob */
827 lpqsResults->lpBlob = FlatBuf_ReserveAlignDword(&FlatBuffer,
828 sizeof(BLOB));
829
830 /* Check for a Cached Blob */
831 if((RnrContext->RrType) && (RnrContext->CachedBlob.pBlobData))
832 {
833 /* We have a Cached Blob, use it */
834 BlobSize = RnrContext->CachedBlob.cbSize;
835 BlobData = FlatBuf_ReserveAlignDword(&FlatBuffer, BlobSize);
836
837 /* Copy into the blob */
838 RtlCopyMemory(RnrContext->CachedBlob.pBlobData,
839 BlobData,
840 BlobSize);
841 }
842 else if (!Blob)
843 {
844 /* Create an ANSI Host Entry */
845 BlobData = SaBlob_CreateHostent(&FlatBuffer.BufferPos,
846 &FlatBuffer.BufferFreeSize,
847 &BlobSize,
848 Blob,
849 AnsiString,
850 TRUE,
851 FALSE);
852 }
853 else if ((RnrContext->LookupFlags & IANA) && (ServEntry))
854 {
855 /* Get Servent */
856 BlobData = CopyServEntry(ServEntry,
857 &FlatBuffer.BufferPos,
858 &FlatBuffer.BufferFreeSize,
859 &BlobSize,
860 TRUE);
861
862 /* Manually update the buffer (no SaBlob function for servents) */
863 FlatBuffer.BufferPos += BlobSize;
864 FlatBuffer.BufferFreeSize -= BlobSize;
865 }
866 else
867 {
868 /* We have nothing to return! */
869 BlobSize = 0;
870 lpqsResults->lpBlob = NULL;
871 FlatBuffer.BufferPos = Position;
872 FlatBuffer.BufferFreeSize = FreeSize;
873 }
874
875 /* Make sure we have a blob by here */
876 if (Blob)
877 {
878 /* Set it */
879 lpqsResults->lpBlob->pBlobData = BlobData;
880 lpqsResults->lpBlob->cbSize = BlobSize;
881 }
882 else
883 {
884 /* Set the error code */
885 ErrorCode = WSAEFAULT;
886 }
887 }
888
889 /* Caller wants a name, and we have one */
890 if((RnrContext->dwControlFlags & LUP_RETURN_NAME) && (Name))
891 {
892 /* Check if we have an ANSI name */
893 if (!IsUnicode)
894 {
895 /* Convert it */
896 StringLength = 512;
897 Dns_StringCopy(&UnicodeName,
898 &StringLength,
899 Name,
900 0,
901 AnsiString,
902 UnicodeString);
903 }
904 else
905 {
906 /* Keep the name as is */
907 UnicodeName = (LPWSTR)Name;
908 }
909
910 /* Write it to the buffer */
911 Name = FlatBuf_WriteString(&FlatBuffer, UnicodeName, TRUE);
912
913 /* Return it to the caller */
914 lpqsResults->lpszServiceInstanceName = Name;
915 }
916
917 Quickie:
918 /* Check which path got us here */
919 if (ErrorCode != NO_ERROR)
920 {
921 /* Set error */
922 SetLastError(ErrorCode);
923
924 /* Check if was a memory error */
925 if (ErrorCode == WSAEFAULT)
926 {
927 /* Update buffer length */
928 *lpdwBufferLength -= (DWORD)FlatBuffer.BufferFreeSize;
929
930 /* Decrease an instance */
931 RnrCtx_DecInstance(RnrContext);
932 }
933
934 /* Set the normalized error code */
935 ErrorCode = SOCKET_ERROR;
936 }
937
938 /* Release the RnR Context */
939 RnrCtx_Release(RnrContext);
940
941 /* Return error code */
942 return ErrorCode;
943 }
944
945 /*
946 * COPYRIGHT: See COPYING in the top level directory
947 * PROJECT: ReactOS Winsock 2 SPI
948 * FILE: lib/mswsock/lib/init.c
949 * PURPOSE: DLL Initialization
950 */
951
952 /* INCLUDES ******************************************************************/
953 #include "msafd.h"
954
955 #define ALL_LUP_FLAGS (0x0BFFF)
956
957 /* DATA **********************************************************************/
958
959 LPWSTR g_pszHostName;
960 LPWSTR g_pszHostFqdn;
961 LONG g_NspRefCount;
962 GUID NbtProviderId = {0};
963 GUID DNSProviderId = {0};
964 DWORD MaskOfGuids;
965
966 NSP_ROUTINE g_NspVector = {sizeof(NSP_ROUTINE),
967 1,
968 1,
969 Dns_NSPCleanup,
970 Dns_NSPLookupServiceBegin,
971 Dns_NSPLookupServiceNext,
972 Dns_NSPLookupServiceEnd,
973 Dns_NSPSetService,
974 Dns_NSPInstallServiceClass,
975 Dns_NSPRemoveServiceClass,
976 Dns_NSPGetServiceClassInfo};
977
978 /* FUNCTIONS *****************************************************************/
979
980 INT
981 WINAPI
982 Dns_NSPStartup(IN LPGUID lpProviderId,
983 IN OUT LPNSP_ROUTINE lpsnpRoutines)
984 {
985 INT ErrorCode;
986 BOOLEAN Prolog;
987
988 /* Validate the size */
989 if (lpsnpRoutines->cbSize != sizeof(NSP_ROUTINE))
990 {
991 /* Fail */
992 SetLastError(WSAEINVALIDPROCTABLE);
993 return SOCKET_ERROR;
994 }
995
996 /* Enter the prolog */
997 Prolog = RNRPROV_SockEnterApi();
998 if (Prolog)
999 {
1000 /* Increase our reference count */
1001 InterlockedIncrement(&g_NspRefCount);
1002
1003 /* Check if we don't have the hostname */
1004 if (!g_pszHostName)
1005 {
1006 /* Query it from DNS */
1007 DnsQueryConfig(DnsConfigHostName_W,
1008 DNS_CONFIG_FLAG_ALLOC,
1009 NULL,
1010 NULL,
1011 &g_pszHostName,
1012 0);
1013 }
1014
1015 /* Check if we have a hostname now, but not a Fully-Qualified Domain */
1016 if (g_pszHostName && !(g_pszHostFqdn))
1017 {
1018 /* Get the domain from DNS */
1019 DnsQueryConfig(DnsConfigFullHostName_W,
1020 DNS_CONFIG_FLAG_ALLOC,
1021 NULL,
1022 NULL,
1023 &g_pszHostFqdn,
1024 0);
1025 }
1026
1027 /* If we don't have both of them, then set error */
1028 if (!(g_pszHostName) || !(g_pszHostFqdn)) ErrorCode = SOCKET_ERROR;
1029 }
1030
1031 /* Check if the Prolog or DNS Local Queries failed */
1032 if (!(Prolog) || (ErrorCode != NO_ERROR))
1033 {
1034 /* Fail */
1035 SetLastError(WSASYSNOTREADY);
1036 return SOCKET_ERROR;
1037 }
1038
1039 /* Copy the Routines */
1040 RtlMoveMemory(lpsnpRoutines, &g_NspVector, sizeof(NSP_ROUTINE));
1041
1042 /* Check if this is NBT or DNS */
1043 if (!memcmp(lpProviderId, &NbtProviderId, sizeof(GUID)))
1044 {
1045 /* Enable the NBT Mask */
1046 MaskOfGuids |= NBT_MASK;
1047 }
1048 else if (!memcmp(lpProviderId, &DNSProviderId, sizeof(GUID)))
1049 {
1050 /* Enable the DNS Mask */
1051 MaskOfGuids |= DNS_MASK;
1052 }
1053
1054 /* Return success */
1055 return NO_ERROR;
1056 }
1057
1058 VOID
1059 WSPAPI
1060 Nsp_GlobalCleanup(VOID)
1061 {
1062 /* Cleanup the RnR Contexts */
1063 RnrCtx_ListCleanup();
1064
1065 /* Free the hostnames, if we have them */
1066 if (g_pszHostName) DnsApiFree(g_pszHostName);
1067 if (g_pszHostFqdn) DnsApiFree(g_pszHostFqdn);
1068 g_pszHostFqdn = g_pszHostName = NULL;
1069 }
1070
1071 INT
1072 WINAPI
1073 NSPStartup(IN LPGUID lpProviderId,
1074 IN OUT LPNSP_ROUTINE lpsnpRoutines)
1075 {
1076 INT ErrorCode;
1077
1078 /* Initialize the DLL */
1079 ErrorCode = MSWSOCK_Initialize();
1080 if (ErrorCode != NO_ERROR)
1081 {
1082 /* Fail */
1083 SetLastError(WSANOTINITIALISED);
1084 return SOCKET_ERROR;
1085 }
1086
1087 /* Check if this is Winsock Mobile or DNS */
1088 if (!memcmp(lpProviderId, &gNLANamespaceGuid, sizeof(GUID)))
1089 {
1090 /* Initialize WSM */
1091 return WSM_NSPStartup(lpProviderId, lpsnpRoutines);
1092 }
1093
1094 /* Initialize DNS */
1095 return Dns_NSPStartup(lpProviderId, lpsnpRoutines);
1096 }
1097
1098 INT
1099 WINAPI
1100 Dns_NSPCleanup(IN LPGUID lpProviderId)
1101 {
1102 /* Decrement our reference count and do global cleanup if it's reached 0 */
1103 if (!(InterlockedDecrement(&g_NspRefCount))) Nsp_GlobalCleanup();
1104
1105 /* Return success */
1106 return NO_ERROR;
1107 }
1108
1109 INT
1110 WINAPI
1111 Dns_NSPSetService(IN LPGUID lpProviderId,
1112 IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
1113 IN LPWSAQUERYSETW lpqsRegInfo,
1114 IN WSAESETSERVICEOP essOperation,
1115 IN DWORD dwControlFlags)
1116 {
1117 /* Unlike NLA, DNS Services cannot be dynmically modified */
1118 SetLastError(ERROR_NOT_SUPPORTED);
1119 return SOCKET_ERROR;
1120 }
1121
1122 INT
1123 WINAPI
1124 Dns_NSPInstallServiceClass(IN LPGUID lpProviderId,
1125 IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
1126 {
1127 /* Unlike NLA, DNS Services cannot be dynmically modified */
1128 SetLastError(WSAEOPNOTSUPP);
1129 return SOCKET_ERROR;
1130 };
1131
1132 INT
1133 WINAPI
1134 Dns_NSPRemoveServiceClass(IN LPGUID lpProviderId,
1135 IN LPGUID lpServiceCallId)
1136 {
1137 /* Unlike NLA, DNS Services cannot be dynmically modified */
1138 SetLastError(WSAEOPNOTSUPP);
1139 return SOCKET_ERROR;
1140 }
1141 INT
1142 WINAPI
1143 Dns_NSPGetServiceClassInfo(IN LPGUID lpProviderId,
1144 IN OUT LPDWORD lpdwBufSize,
1145 IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
1146 {
1147 /* Unlike NLA, DNS Services cannot be dynmically modified */
1148 SetLastError(WSAEOPNOTSUPP);
1149 return SOCKET_ERROR;
1150 }
1151
1152 INT
1153 WINAPI
1154 Dns_NSPLookupServiceEnd(IN HANDLE hLookup)
1155 {
1156 PRNR_CONTEXT RnrContext;
1157
1158 /* Get this handle's context */
1159 RnrContext = RnrCtx_Get(hLookup, 0, NULL);
1160
1161 /* Mark it as completed */
1162 RnrContext->LookupFlags |= DONE;
1163
1164 /* Dereference it once for our _Get */
1165 RnrCtx_Release(RnrContext);
1166
1167 /* And once last to delete it */
1168 RnrCtx_Release(RnrContext);
1169
1170 /* return */
1171 return NO_ERROR;
1172 }
1173
1174 INT
1175 WINAPI
1176 rnr_IdForGuid(IN LPGUID Guid)
1177 {
1178
1179 if (memcmp(Guid, &InetHostName, sizeof(GUID))) return 0x10000002;
1180 if (memcmp(Guid, &Ipv6Guid, sizeof(GUID))) return 0x10000023;
1181 if (memcmp(Guid, &HostnameGuid, sizeof(GUID))) return 0x1;
1182 if (memcmp(Guid, &AddressGuid, sizeof(GUID))) return 0x80000000;
1183 if (memcmp(Guid, &IANAGuid, sizeof(GUID))) return 0x2;
1184 if IS_SVCID_DNS(Guid) return 0x5000000;
1185 if IS_SVCID_TCP(Guid) return 0x1000000;
1186 if IS_SVCID_UDP(Guid) return 0x2000000;
1187 return 0;
1188 }
1189
1190 PVOID
1191 WSPAPI
1192 FlatBuf_ReserveAlignDword(IN PFLATBUFF FlatBuffer,
1193 IN ULONG Size)
1194 {
1195 /* Let DNSLIB do the grunt work */
1196 return FlatBuf_Arg_Reserve((PVOID)FlatBuffer->BufferPos,
1197 &FlatBuffer->BufferFreeSize,
1198 Size,
1199 sizeof(PVOID));
1200 }
1201
1202 PVOID
1203 WSPAPI
1204 FlatBuf_WriteString(IN PFLATBUFF FlatBuffer,
1205 IN PVOID String,
1206 IN BOOLEAN IsUnicode)
1207 {
1208 /* Let DNSLIB do the grunt work */
1209 return FlatBuf_Arg_WriteString((PVOID)FlatBuffer->BufferPos,
1210 &FlatBuffer->BufferFreeSize,
1211 String,
1212 IsUnicode);
1213 }
1214
1215 PVOID
1216 WSPAPI
1217 FlatBuf_CopyMemory(IN PFLATBUFF FlatBuffer,
1218 IN PVOID Buffer,
1219 IN ULONG Size,
1220 IN ULONG Align)
1221 {
1222 /* Let DNSLIB do the grunt work */
1223 return FlatBuf_Arg_CopyMemory((PVOID)FlatBuffer->BufferPos,
1224 &FlatBuffer->BufferFreeSize,
1225 Buffer,
1226 Size,
1227 Align);
1228 }
1229
1230 INT
1231 WINAPI
1232 Dns_NSPLookupServiceBegin(LPGUID lpProviderId,
1233 LPWSAQUERYSETW lpqsRestrictions,
1234 LPWSASERVICECLASSINFOW lpServiceClassInfo,
1235 DWORD dwControlFlags,
1236 LPHANDLE lphLookup)
1237 {
1238 INT ErrorCode = SOCKET_ERROR;
1239 PWCHAR ServiceName = lpqsRestrictions->lpszServiceInstanceName;
1240 LPGUID ServiceClassId;
1241 INT RnrId;
1242 ULONG LookupFlags = 0;
1243 BOOL NameRequested = FALSE;
1244 WCHAR StringBuffer[48];
1245 ULONG i;
1246 DWORD LocalProtocols;
1247 ULONG ProtocolFlags;
1248 PSERVENT LookupServent;
1249 DWORD UdpPort, TcpPort;
1250 PRNR_CONTEXT RnrContext;
1251 PSOCKADDR_IN ReverseSock;
1252
1253 /* Check if the Size isn't weird */
1254 if(lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW))
1255 {
1256 ErrorCode = WSAEFAULT;
1257 goto Quickie;
1258 }
1259
1260 /* Get the GUID */
1261 ServiceClassId = lpqsRestrictions->lpServiceClassId;
1262 if(!ServiceClassId)
1263 {
1264 /* No GUID, fail */
1265 ErrorCode = WSA_INVALID_PARAMETER;
1266 goto Quickie;
1267 }
1268
1269 /* Get the RNR ID */
1270 RnrId = rnr_IdForGuid(ServiceClassId);
1271
1272 /* Make sure that the control flags are valid */
1273 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
1274 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
1275 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
1276 {
1277 /* Either non-recognized flags or invalid combos were passed */
1278 ErrorCode = WSA_INVALID_PARAMETER;
1279 goto Quickie;
1280 }
1281
1282 /* Make sure that we have no context, and that LUP_CONTAINERS is not on */
1283 if(((lpqsRestrictions->lpszContext) &&
1284 (*lpqsRestrictions->lpszContext) &&
1285 (wcscmp(lpqsRestrictions->lpszContext, L"\\"))) ||
1286 (dwControlFlags & LUP_CONTAINERS))
1287 {
1288 /* We don't support contexts or LUP_CONTAINERS */
1289 ErrorCode = WSANO_DATA;
1290 goto Quickie;
1291 }
1292
1293 /* Is this a Reverse Lookup? */
1294 if (RnrId == 0x80000000)
1295 {
1296 /* Remember for later */
1297 LookupFlags = REVERSE;
1298 }
1299 else
1300 {
1301 /* Is this a IANA Lookup? */
1302 if (RnrId == 0x2)
1303 {
1304 /* Mask out this flag since it's of no use now */
1305 dwControlFlags &= ~(LUP_RETURN_ADDR);
1306
1307 /* This is a IANA lookup, remember for later */
1308 LookupFlags |= IANA;
1309 }
1310
1311 /* Check if we need a name or not */
1312 if ((RnrId == 0x1) ||
1313 (RnrId == 0x10000002) ||
1314 (RnrId == 0x10000023) ||
1315 (RnrId == 0x10000022))
1316 {
1317 /* We do */
1318 NameRequested = TRUE;
1319 }
1320 }
1321
1322 /* Final check to make sure if we need a name or not */
1323 if (RnrId & 0x3000000) NameRequested = TRUE;
1324
1325 /* No Service Name was specified */
1326 if(!(ServiceName) || !(*ServiceName))
1327 {
1328 /*
1329 * A name was requested but no Service Name was given,
1330 * so this is a local lookup
1331 */
1332 if(NameRequested)
1333 {
1334 /* A local Lookup */
1335 LookupFlags |= LOCAL;
1336 ServiceName = L"";
1337 }
1338 else if((LookupFlags & REVERSE) &&
1339 (lpqsRestrictions->lpcsaBuffer) &&
1340 (lpqsRestrictions->dwNumberOfCsAddrs == 1))
1341 {
1342 /* Reverse lookup, make sure a CS Address is there */
1343 ReverseSock = (struct sockaddr_in*)
1344 lpqsRestrictions->lpcsaBuffer->RemoteAddr.lpSockaddr;
1345
1346 /* Convert address to Unicode */
1347 MultiByteToWideChar(CP_ACP,
1348 0,
1349 inet_ntoa(ReverseSock->sin_addr),
1350 -1,
1351 StringBuffer,
1352 16);
1353
1354 /* Set it as the new name */
1355 ServiceName = StringBuffer;
1356 }
1357 else
1358 {
1359 /* We can't do anything without a service name at this point */
1360 ErrorCode = WSA_INVALID_PARAMETER;
1361 goto Quickie;
1362 }
1363 }
1364 else if(NameRequested)
1365 {
1366 /* Check for meaningful DNS Names */
1367 if (DnsNameCompare_W(ServiceName, L"localhost") ||
1368 DnsNameCompare_W(ServiceName, L"loopback"))
1369 {
1370 /* This is the local and/or loopback DNS name */
1371 LookupFlags |= (LOCAL | LOOPBACK);
1372 }
1373 else if (DnsNameCompare_W(ServiceName, g_pszHostName) ||
1374 DnsNameCompare_W(ServiceName, g_pszHostFqdn))
1375 {
1376 /* This is the local name of the computer */
1377 LookupFlags |= LOCAL;
1378 }
1379 }
1380
1381 /* Check if any restrictions were made on the protocols */
1382 if(lpqsRestrictions->lpafpProtocols)
1383 {
1384 /* Save our local copy to speed up the loop */
1385 LocalProtocols = lpqsRestrictions->dwNumberOfProtocols;
1386 ProtocolFlags = 0;
1387
1388 /* Loop the protocols */
1389 for(i = 0; LocalProtocols--;)
1390 {
1391 /* Make sure it's a family that we recognize */
1392 if ((lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET) ||
1393 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET6) ||
1394 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_UNSPEC) ||
1395 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_ATM))
1396 {
1397 /* Find which one is used */
1398 switch(lpqsRestrictions->lpafpProtocols[i].iProtocol)
1399 {
1400 case IPPROTO_UDP:
1401 ProtocolFlags |= UDP;
1402 break;
1403 case IPPROTO_TCP:
1404 ProtocolFlags |= TCP;
1405 break;
1406 case PF_ATM:
1407 ProtocolFlags |= ATM;
1408 break;
1409 default:
1410 break;
1411 }
1412 }
1413 }
1414 /* Make sure we have at least a valid protocol */
1415 if (!ProtocolFlags)
1416 {
1417 /* Fail */
1418 ErrorCode = WSANO_DATA;
1419 goto Quickie;
1420 }
1421 }
1422 else
1423 {
1424 /* No restrictions, assume TCP/UDP */
1425 ProtocolFlags = (TCP | UDP);
1426 }
1427
1428 /* Create the Servent from the Service String */
1429 UdpPort = TcpPort = -1;
1430 ProtocolFlags |= GetServerAndProtocolsFromString(lpqsRestrictions->lpszQueryString,
1431 ServiceClassId,
1432 &LookupServent);
1433
1434 /* Extract the port numbers */
1435 if(LookupServent)
1436 {
1437 /* Are we using UDP? */
1438 if(ProtocolFlags & UDP)
1439 {
1440 /* Get the UDP Port, disable the TCP Port */
1441 UdpPort = ntohs(LookupServent->s_port);
1442 TcpPort = -1;
1443 }
1444 else if(ProtocolFlags & TCP)
1445 {
1446 /* Get the TCP Port, disable the UDP Port */
1447 TcpPort = ntohs(LookupServent->s_port);
1448 UdpPort = -1;
1449 }
1450 }
1451 else
1452 {
1453 /* No servent, so use the Service ID to check */
1454 if(ProtocolFlags & UDP)
1455 {
1456 /* Get the Port from the Service ID */
1457 UdpPort = FetchPortFromClassInfo(UDP,
1458 ServiceClassId,
1459 lpServiceClassInfo);
1460 }
1461 else
1462 {
1463 /* No UDP */
1464 UdpPort = -1;
1465 }
1466
1467 /* No servent, so use the Service ID to check */
1468 if(ProtocolFlags & TCP)
1469 {
1470 /* Get the Port from the Service ID */
1471 UdpPort = FetchPortFromClassInfo(TCP,
1472 ServiceClassId,
1473 lpServiceClassInfo);
1474 }
1475 else
1476 {
1477 /* No TCP */
1478 TcpPort = -1;
1479 }
1480 }
1481
1482 /* Check if we still don't have a valid port by now */
1483 if((TcpPort == -1) && (UdpPort == -1))
1484 {
1485 /* Check if this is TCP */
1486 if ((ProtocolFlags & TCP) || !(ProtocolFlags & UDP))
1487 {
1488 /* Set the UDP Port to 0 */
1489 UdpPort = 0;
1490 }
1491 else
1492 {
1493 /* Set the TCP Port to 0 */
1494 TcpPort = 0;
1495 }
1496 }
1497
1498 /* Allocate a Context for this Query */
1499 RnrContext = RnrCtx_Create(NULL, ServiceName);
1500 RnrContext->lpServiceClassId = *ServiceClassId;
1501 RnrContext->RnrId = RnrId;
1502 RnrContext->dwControlFlags = dwControlFlags;
1503 RnrContext->TcpPort = TcpPort;
1504 RnrContext->UdpPort = UdpPort;
1505 RnrContext->LookupFlags = LookupFlags;
1506 RnrContext->lpProviderId = *lpProviderId;
1507 RnrContext->dwNameSpace = lpqsRestrictions->dwNameSpace;
1508 RnrCtx_Release(RnrContext);
1509
1510 /* Return the context as a handle */
1511 *lphLookup = (HANDLE)RnrContext;
1512
1513 /* Check if this was a TCP, UDP or DNS Query */
1514 if(RnrId & 0x3000000)
1515 {
1516 /* Get the RR Type from the Service ID */
1517 RnrContext->RrType = RR_FROM_SVCID(ServiceClassId);
1518 }
1519
1520 /* Return Success */
1521 ErrorCode = ERROR_SUCCESS;
1522
1523 Quickie:
1524 /* Check if we got here through a failure path */
1525 if (ErrorCode != ERROR_SUCCESS)
1526 {
1527 /* Set the last error and fail */
1528 SetLastError(ErrorCode);
1529 return SOCKET_ERROR;
1530 }
1531
1532 /* Return success */
1533 return ERROR_SUCCESS;
1534 }
1535
1536 INT
1537 WSPAPI
1538 BuildCsAddr(IN LPWSAQUERYSETW QuerySet,
1539 IN PFLATBUFF FlatBuffer,
1540 IN PDNS_BLOB Blob,
1541 IN DWORD UdpPort,
1542 IN DWORD TcpPort,
1543 IN BOOLEAN ReverseLookup)
1544 {
1545 return WSANO_DATA;
1546 }
1547
1548 INT
1549 WINAPI
1550 Dns_NSPLookupServiceNext(IN HANDLE hLookup,
1551 IN DWORD dwControlFlags,
1552 IN OUT LPDWORD lpdwBufferLength,
1553 OUT LPWSAQUERYSETW lpqsResults)
1554 {
1555 INT ErrorCode;
1556 WSAQUERYSETW LocalResults;
1557 LONG Instance;
1558 PRNR_CONTEXT RnrContext = NULL;
1559 FLATBUFF FlatBuffer;
1560 PVOID Name;
1561 PDNS_BLOB Blob = NULL;
1562 DWORD PortNumber;
1563 PSERVENT ServEntry = NULL;
1564 PDNS_ARRAY DnsArray;
1565 BOOLEAN IsUnicode = TRUE;
1566 SIZE_T FreeSize;
1567 ULONG BlobSize;
1568 ULONG_PTR Position;
1569 PVOID BlobData = NULL;
1570 ULONG StringLength;
1571 LPWSTR UnicodeName;
1572
1573 /* Make sure that the control flags are valid */
1574 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
1575 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
1576 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
1577 {
1578 /* Either non-recognized flags or invalid combos were passed */
1579 ErrorCode = WSA_INVALID_PARAMETER;
1580 goto Quickie;
1581 }
1582
1583 /* Get the Context */
1584 RnrContext = RnrCtx_Get(hLookup, dwControlFlags, &Instance);
1585 if (!RnrContext)
1586 {
1587 /* This lookup handle must be invalid */
1588 SetLastError(WSA_INVALID_HANDLE);
1589 return SOCKET_ERROR;
1590 }
1591
1592 /* Assume success for now */
1593 SetLastError(NO_ERROR);
1594
1595 /* Validate the query set size */
1596 if (*lpdwBufferLength < sizeof(WSAQUERYSETW))
1597 {
1598 /* Windows doesn't fail, but sets up a local QS for you... */
1599 lpqsResults = &LocalResults;
1600 ErrorCode = WSAEFAULT;
1601 }
1602
1603 /* Zero out the buffer and fill out basic data */
1604 RtlZeroMemory(lpqsResults, sizeof(WSAQUERYSETW));
1605 lpqsResults->dwNameSpace = NS_DNS;
1606 lpqsResults->dwSize = sizeof(WSAQUERYSETW);
1607
1608 /* Initialize the Buffer */
1609 FlatBuf_Init(&FlatBuffer,
1610 lpqsResults + 1,
1611 (ULONG)(*lpdwBufferLength - sizeof(WSAQUERYSETW)));
1612
1613 /* Check if this is an IANA Lookup */
1614 if(RnrContext->LookupFlags & IANA)
1615 {
1616 /* Service Lookup */
1617 GetServerAndProtocolsFromString(RnrContext->ServiceName,
1618 (LPGUID)&HostnameGuid,
1619 &ServEntry);
1620
1621 /* Get the Port */
1622 PortNumber = ntohs(ServEntry->s_port);
1623
1624 /* Use this as the name */
1625 Name = ServEntry->s_name;
1626 IsUnicode = FALSE;
1627
1628 /* Override some parts of the Context and check for TCP/UDP */
1629 if(!_stricmp("tcp", ServEntry->s_proto))
1630 {
1631 /* Set the TCP Guid */
1632 SET_TCP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
1633 RnrContext->TcpPort = PortNumber;
1634 RnrContext->UdpPort = -1;
1635 }
1636 else
1637 {
1638 /* Set the UDP Guid */
1639 SET_UDP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
1640 RnrContext->UdpPort = PortNumber;
1641 RnrContext->TcpPort = -1;
1642 }
1643 }
1644 else
1645 {
1646 /* Check if the caller requested for RES_SERVICE */
1647 if(RnrContext->dwControlFlags & LUP_RES_SERVICE)
1648 {
1649 /* Make sure that this is the first instance */
1650 if (Instance)
1651 {
1652 /* Fail */
1653 ErrorCode = WSA_E_NO_MORE;
1654 goto Quickie;
1655 }
1656
1657 #if 0
1658 /* Create the blob */
1659 DnsArray = NULL;
1660 Blob = SaBlob_CreateFromIp4(RnrContext->ServiceName,
1661 1,
1662 &DnsArray);
1663 #else
1664 /* FIXME */
1665 Blob = NULL;
1666 DnsArray = NULL;
1667 ErrorCode = WSAEFAULT;
1668 goto Quickie;
1669 #endif
1670 }
1671 else if(!(Blob = RnrContext->CachedSaBlob))
1672 {
1673 /* An actual Host Lookup, but we don't have a cached HostEntry yet */
1674 if (!memcmp(&RnrContext->lpServiceClassId,
1675 &HostnameGuid,
1676 sizeof(GUID)) && !(RnrContext->ServiceName))
1677 {
1678 /* Do a Regular DNS Lookup */
1679 Blob = Rnr_DoHostnameLookup(RnrContext);
1680 }
1681 else if (RnrContext->LookupFlags & REVERSE)
1682 {
1683 /* Do a Reverse DNS Lookup */
1684 Blob = Rnr_GetHostByAddr(RnrContext);
1685 }
1686 else
1687 {
1688 /* Do a Hostname Lookup */
1689 Blob = Rnr_DoDnsLookup(RnrContext);
1690 }
1691
1692 /* Check if we got a blob, and cache it */
1693 if (Blob) RnrContext->CachedSaBlob = Blob;
1694 }
1695
1696 /* We should have a blob by now */
1697 if (!Blob)
1698 {
1699 /* We dont, fail */
1700 if (ErrorCode == NO_ERROR)
1701 {
1702 /* Supposedly no error, so find it out */
1703 ErrorCode = GetLastError();
1704 if (ErrorCode == NO_ERROR) ErrorCode = WSASERVICE_NOT_FOUND;
1705 }
1706
1707 /* Fail */
1708 goto Quickie;
1709 }
1710 }
1711
1712 /* Check if this is the first instance or not */
1713 if(!RnrContext->Instance)
1714 {
1715 /* It is, get the name from the blob */
1716 Name = Blob->Name;
1717 }
1718 else
1719 {
1720 /* Only accept this scenario if the caller wanted Aliases */
1721 if((RnrContext->dwControlFlags & LUP_RETURN_ALIASES) &&
1722 (Blob->AliasCount > RnrContext->Instance))
1723 {
1724 /* Get the name from the Alias */
1725 Name = Blob->Aliases[RnrContext->Instance];
1726
1727 /* Let the caller know that this is an Alias */
1728 /* lpqsResults->dwOutputFlags |= RESULT_IS_ALIAS; */
1729 }
1730 else
1731 {
1732 /* Fail */
1733 ErrorCode = WSA_E_NO_MORE;
1734 goto Quickie;
1735 }
1736 }
1737
1738 /* Lookups are complete... time to return the right stuff! */
1739 lpqsResults->dwNameSpace = NS_DNS;
1740
1741 /* Caller wants the Type back */
1742 if(RnrContext->dwControlFlags & LUP_RETURN_TYPE)
1743 {
1744 /* Copy into the flat buffer and point to it */
1745 lpqsResults->lpServiceClassId = FlatBuf_CopyMemory(&FlatBuffer,
1746 &RnrContext->lpServiceClassId,
1747 sizeof(GUID),
1748 sizeof(PVOID));
1749 }
1750
1751 /* Caller wants the Addreses Back */
1752 if((RnrContext->dwControlFlags & LUP_RETURN_ADDR) && (Blob))
1753 {
1754 /* Build the CS Addr for the caller */
1755 ErrorCode = BuildCsAddr(lpqsResults,
1756 &FlatBuffer,
1757 Blob,
1758 RnrContext->UdpPort,
1759 RnrContext->TcpPort,
1760 (RnrContext->LookupFlags & REVERSE) == 1);
1761 }
1762
1763 /* Caller wants a Blob */
1764 if(RnrContext->dwControlFlags & LUP_RETURN_BLOB)
1765 {
1766 /* Save the current size and position */
1767 FreeSize = FlatBuffer.BufferFreeSize;
1768 Position = FlatBuffer.BufferPos;
1769
1770 /* Allocate some space for the Public Blob */
1771 lpqsResults->lpBlob = FlatBuf_ReserveAlignDword(&FlatBuffer,
1772 sizeof(BLOB));
1773
1774 /* Check for a Cached Blob */
1775 if((RnrContext->RrType) && (RnrContext->CachedBlob.pBlobData))
1776 {
1777 /* We have a Cached Blob, use it */
1778 BlobSize = RnrContext->CachedBlob.cbSize;
1779 BlobData = FlatBuf_ReserveAlignDword(&FlatBuffer, BlobSize);
1780
1781 /* Copy into the blob */
1782 RtlCopyMemory(RnrContext->CachedBlob.pBlobData,
1783 BlobData,
1784 BlobSize);
1785 }
1786 else if (!Blob)
1787 {
1788 /* Create an ANSI Host Entry */
1789 BlobData = SaBlob_CreateHostent(&FlatBuffer.BufferPos,
1790 &FlatBuffer.BufferFreeSize,
1791 &BlobSize,
1792 Blob,
1793 AnsiString,
1794 TRUE,
1795 FALSE);
1796 }
1797 else if ((RnrContext->LookupFlags & IANA) && (ServEntry))
1798 {
1799 /* Get Servent */
1800 BlobData = CopyServEntry(ServEntry,
1801 &FlatBuffer.BufferPos,
1802 &FlatBuffer.BufferFreeSize,
1803 &BlobSize,
1804 TRUE);
1805
1806 /* Manually update the buffer (no SaBlob function for servents) */
1807 FlatBuffer.BufferPos += BlobSize;
1808 FlatBuffer.BufferFreeSize -= BlobSize;
1809 }
1810 else
1811 {
1812 /* We have nothing to return! */
1813 BlobSize = 0;
1814 lpqsResults->lpBlob = NULL;
1815 FlatBuffer.BufferPos = Position;
1816 FlatBuffer.BufferFreeSize = FreeSize;
1817 }
1818
1819 /* Make sure we have a blob by here */
1820 if (Blob)
1821 {
1822 /* Set it */
1823 lpqsResults->lpBlob->pBlobData = BlobData;
1824 lpqsResults->lpBlob->cbSize = BlobSize;
1825 }
1826 else
1827 {
1828 /* Set the error code */
1829 ErrorCode = WSAEFAULT;
1830 }
1831 }
1832
1833 /* Caller wants a name, and we have one */
1834 if((RnrContext->dwControlFlags & LUP_RETURN_NAME) && (Name))
1835 {
1836 /* Check if we have an ANSI name */
1837 if (!IsUnicode)
1838 {
1839 /* Convert it */
1840 StringLength = 512;
1841 Dns_StringCopy(&UnicodeName,
1842 &StringLength,
1843 Name,
1844 0,
1845 AnsiString,
1846 UnicodeString);
1847 }
1848 else
1849 {
1850 /* Keep the name as is */
1851 UnicodeName = (LPWSTR)Name;
1852 }
1853
1854 /* Write it to the buffer */
1855 Name = FlatBuf_WriteString(&FlatBuffer, UnicodeName, TRUE);
1856
1857 /* Return it to the caller */
1858 lpqsResults->lpszServiceInstanceName = Name;
1859 }
1860
1861 Quickie:
1862 /* Check which path got us here */
1863 if (ErrorCode != NO_ERROR)
1864 {
1865 /* Set error */
1866 SetLastError(ErrorCode);
1867
1868 /* Check if was a memory error */
1869 if (ErrorCode == WSAEFAULT)
1870 {
1871 /* Update buffer length */
1872 *lpdwBufferLength -= (DWORD)FlatBuffer.BufferFreeSize;
1873
1874 /* Decrease an instance */
1875 RnrCtx_DecInstance(RnrContext);
1876 }
1877
1878 /* Set the normalized error code */
1879 ErrorCode = SOCKET_ERROR;
1880 }
1881
1882 /* Release the RnR Context */
1883 RnrCtx_Release(RnrContext);
1884
1885 /* Return error code */
1886 return ErrorCode;
1887 }
1888
1889 /*
1890 * COPYRIGHT: See COPYING in the top level directory
1891 * PROJECT: ReactOS Winsock 2 SPI
1892 * FILE: lib/mswsock/lib/init.c
1893 * PURPOSE: DLL Initialization
1894 */
1895
1896 /* INCLUDES ******************************************************************/
1897 #include "msafd.h"
1898
1899 #define ALL_LUP_FLAGS (0x0BFFF)
1900
1901 /* DATA **********************************************************************/
1902
1903 LPWSTR g_pszHostName;
1904 LPWSTR g_pszHostFqdn;
1905 LONG g_NspRefCount;
1906 GUID NbtProviderId = {0};
1907 GUID DNSProviderId = {0};
1908 DWORD MaskOfGuids;
1909
1910 NSP_ROUTINE g_NspVector = {sizeof(NSP_ROUTINE),
1911 1,
1912 1,
1913 Dns_NSPCleanup,
1914 Dns_NSPLookupServiceBegin,
1915 Dns_NSPLookupServiceNext,
1916 Dns_NSPLookupServiceEnd,
1917 Dns_NSPSetService,
1918 Dns_NSPInstallServiceClass,
1919 Dns_NSPRemoveServiceClass,
1920 Dns_NSPGetServiceClassInfo};
1921
1922 /* FUNCTIONS *****************************************************************/
1923
1924 INT
1925 WINAPI
1926 Dns_NSPStartup(IN LPGUID lpProviderId,
1927 IN OUT LPNSP_ROUTINE lpsnpRoutines)
1928 {
1929 INT ErrorCode;
1930 BOOLEAN Prolog;
1931
1932 /* Validate the size */
1933 if (lpsnpRoutines->cbSize != sizeof(NSP_ROUTINE))
1934 {
1935 /* Fail */
1936 SetLastError(WSAEINVALIDPROCTABLE);
1937 return SOCKET_ERROR;
1938 }
1939
1940 /* Enter the prolog */
1941 Prolog = RNRPROV_SockEnterApi();
1942 if (Prolog)
1943 {
1944 /* Increase our reference count */
1945 InterlockedIncrement(&g_NspRefCount);
1946
1947 /* Check if we don't have the hostname */
1948 if (!g_pszHostName)
1949 {
1950 /* Query it from DNS */
1951 DnsQueryConfig(DnsConfigHostName_W,
1952 DNS_CONFIG_FLAG_ALLOC,
1953 NULL,
1954 NULL,
1955 &g_pszHostName,
1956 0);
1957 }
1958
1959 /* Check if we have a hostname now, but not a Fully-Qualified Domain */
1960 if (g_pszHostName && !(g_pszHostFqdn))
1961 {
1962 /* Get the domain from DNS */
1963 DnsQueryConfig(DnsConfigFullHostName_W,
1964 DNS_CONFIG_FLAG_ALLOC,
1965 NULL,
1966 NULL,
1967 &g_pszHostFqdn,
1968 0);
1969 }
1970
1971 /* If we don't have both of them, then set error */
1972 if (!(g_pszHostName) || !(g_pszHostFqdn)) ErrorCode = SOCKET_ERROR;
1973 }
1974
1975 /* Check if the Prolog or DNS Local Queries failed */
1976 if (!(Prolog) || (ErrorCode != NO_ERROR))
1977 {
1978 /* Fail */
1979 SetLastError(WSASYSNOTREADY);
1980 return SOCKET_ERROR;
1981 }
1982
1983 /* Copy the Routines */
1984 RtlMoveMemory(lpsnpRoutines, &g_NspVector, sizeof(NSP_ROUTINE));
1985
1986 /* Check if this is NBT or DNS */
1987 if (!memcmp(lpProviderId, &NbtProviderId, sizeof(GUID)))
1988 {
1989 /* Enable the NBT Mask */
1990 MaskOfGuids |= NBT_MASK;
1991 }
1992 else if (!memcmp(lpProviderId, &DNSProviderId, sizeof(GUID)))
1993 {
1994 /* Enable the DNS Mask */
1995 MaskOfGuids |= DNS_MASK;
1996 }
1997
1998 /* Return success */
1999 return NO_ERROR;
2000 }
2001
2002 VOID
2003 WSPAPI
2004 Nsp_GlobalCleanup(VOID)
2005 {
2006 /* Cleanup the RnR Contexts */
2007 RnrCtx_ListCleanup();
2008
2009 /* Free the hostnames, if we have them */
2010 if (g_pszHostName) DnsApiFree(g_pszHostName);
2011 if (g_pszHostFqdn) DnsApiFree(g_pszHostFqdn);
2012 g_pszHostFqdn = g_pszHostName = NULL;
2013 }
2014
2015 INT
2016 WINAPI
2017 NSPStartup(IN LPGUID lpProviderId,
2018 IN OUT LPNSP_ROUTINE lpsnpRoutines)
2019 {
2020 INT ErrorCode;
2021
2022 /* Initialize the DLL */
2023 ErrorCode = MSWSOCK_Initialize();
2024 if (ErrorCode != NO_ERROR)
2025 {
2026 /* Fail */
2027 SetLastError(WSANOTINITIALISED);
2028 return SOCKET_ERROR;
2029 }
2030
2031 /* Check if this is Winsock Mobile or DNS */
2032 if (!memcmp(lpProviderId, &gNLANamespaceGuid, sizeof(GUID)))
2033 {
2034 /* Initialize WSM */
2035 return WSM_NSPStartup(lpProviderId, lpsnpRoutines);
2036 }
2037
2038 /* Initialize DNS */
2039 return Dns_NSPStartup(lpProviderId, lpsnpRoutines);
2040 }
2041
2042 INT
2043 WINAPI
2044 Dns_NSPCleanup(IN LPGUID lpProviderId)
2045 {
2046 /* Decrement our reference count and do global cleanup if it's reached 0 */
2047 if (!(InterlockedDecrement(&g_NspRefCount))) Nsp_GlobalCleanup();
2048
2049 /* Return success */
2050 return NO_ERROR;
2051 }
2052
2053 INT
2054 WINAPI
2055 Dns_NSPSetService(IN LPGUID lpProviderId,
2056 IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
2057 IN LPWSAQUERYSETW lpqsRegInfo,
2058 IN WSAESETSERVICEOP essOperation,
2059 IN DWORD dwControlFlags)
2060 {
2061 /* Unlike NLA, DNS Services cannot be dynmically modified */
2062 SetLastError(ERROR_NOT_SUPPORTED);
2063 return SOCKET_ERROR;
2064 }
2065
2066 INT
2067 WINAPI
2068 Dns_NSPInstallServiceClass(IN LPGUID lpProviderId,
2069 IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
2070 {
2071 /* Unlike NLA, DNS Services cannot be dynmically modified */
2072 SetLastError(WSAEOPNOTSUPP);
2073 return SOCKET_ERROR;
2074 };
2075
2076 INT
2077 WINAPI
2078 Dns_NSPRemoveServiceClass(IN LPGUID lpProviderId,
2079 IN LPGUID lpServiceCallId)
2080 {
2081 /* Unlike NLA, DNS Services cannot be dynmically modified */
2082 SetLastError(WSAEOPNOTSUPP);
2083 return SOCKET_ERROR;
2084 }
2085 INT
2086 WINAPI
2087 Dns_NSPGetServiceClassInfo(IN LPGUID lpProviderId,
2088 IN OUT LPDWORD lpdwBufSize,
2089 IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
2090 {
2091 /* Unlike NLA, DNS Services cannot be dynmically modified */
2092 SetLastError(WSAEOPNOTSUPP);
2093 return SOCKET_ERROR;
2094 }
2095
2096 INT
2097 WINAPI
2098 Dns_NSPLookupServiceEnd(IN HANDLE hLookup)
2099 {
2100 PRNR_CONTEXT RnrContext;
2101
2102 /* Get this handle's context */
2103 RnrContext = RnrCtx_Get(hLookup, 0, NULL);
2104
2105 /* Mark it as completed */
2106 RnrContext->LookupFlags |= DONE;
2107
2108 /* Dereference it once for our _Get */
2109 RnrCtx_Release(RnrContext);
2110
2111 /* And once last to delete it */
2112 RnrCtx_Release(RnrContext);
2113
2114 /* return */
2115 return NO_ERROR;
2116 }
2117
2118 INT
2119 WINAPI
2120 rnr_IdForGuid(IN LPGUID Guid)
2121 {
2122
2123 if (memcmp(Guid, &InetHostName, sizeof(GUID))) return 0x10000002;
2124 if (memcmp(Guid, &Ipv6Guid, sizeof(GUID))) return 0x10000023;
2125 if (memcmp(Guid, &HostnameGuid, sizeof(GUID))) return 0x1;
2126 if (memcmp(Guid, &AddressGuid, sizeof(GUID))) return 0x80000000;
2127 if (memcmp(Guid, &IANAGuid, sizeof(GUID))) return 0x2;
2128 if IS_SVCID_DNS(Guid) return 0x5000000;
2129 if IS_SVCID_TCP(Guid) return 0x1000000;
2130 if IS_SVCID_UDP(Guid) return 0x2000000;
2131 return 0;
2132 }
2133
2134 PVOID
2135 WSPAPI
2136 FlatBuf_ReserveAlignDword(IN PFLATBUFF FlatBuffer,
2137 IN ULONG Size)
2138 {
2139 /* Let DNSLIB do the grunt work */
2140 return FlatBuf_Arg_Reserve((PVOID)FlatBuffer->BufferPos,
2141 &FlatBuffer->BufferFreeSize,
2142 Size,
2143 sizeof(PVOID));
2144 }
2145
2146 PVOID
2147 WSPAPI
2148 FlatBuf_WriteString(IN PFLATBUFF FlatBuffer,
2149 IN PVOID String,
2150 IN BOOLEAN IsUnicode)
2151 {
2152 /* Let DNSLIB do the grunt work */
2153 return FlatBuf_Arg_WriteString((PVOID)FlatBuffer->BufferPos,
2154 &FlatBuffer->BufferFreeSize,
2155 String,
2156 IsUnicode);
2157 }
2158
2159 PVOID
2160 WSPAPI
2161 FlatBuf_CopyMemory(IN PFLATBUFF FlatBuffer,
2162 IN PVOID Buffer,
2163 IN ULONG Size,
2164 IN ULONG Align)
2165 {
2166 /* Let DNSLIB do the grunt work */
2167 return FlatBuf_Arg_CopyMemory((PVOID)FlatBuffer->BufferPos,
2168 &FlatBuffer->BufferFreeSize,
2169 Buffer,
2170 Size,
2171 Align);
2172 }
2173
2174 INT
2175 WINAPI
2176 Dns_NSPLookupServiceBegin(LPGUID lpProviderId,
2177 LPWSAQUERYSETW lpqsRestrictions,
2178 LPWSASERVICECLASSINFOW lpServiceClassInfo,
2179 DWORD dwControlFlags,
2180 LPHANDLE lphLookup)
2181 {
2182 INT ErrorCode = SOCKET_ERROR;
2183 PWCHAR ServiceName = lpqsRestrictions->lpszServiceInstanceName;
2184 LPGUID ServiceClassId;
2185 INT RnrId;
2186 ULONG LookupFlags = 0;
2187 BOOL NameRequested = FALSE;
2188 WCHAR StringBuffer[48];
2189 ULONG i;
2190 DWORD LocalProtocols;
2191 ULONG ProtocolFlags;
2192 PSERVENT LookupServent;
2193 DWORD UdpPort, TcpPort;
2194 PRNR_CONTEXT RnrContext;
2195 PSOCKADDR_IN ReverseSock;
2196
2197 /* Check if the Size isn't weird */
2198 if(lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW))
2199 {
2200 ErrorCode = WSAEFAULT;
2201 goto Quickie;
2202 }
2203
2204 /* Get the GUID */
2205 ServiceClassId = lpqsRestrictions->lpServiceClassId;
2206 if(!ServiceClassId)
2207 {
2208 /* No GUID, fail */
2209 ErrorCode = WSA_INVALID_PARAMETER;
2210 goto Quickie;
2211 }
2212
2213 /* Get the RNR ID */
2214 RnrId = rnr_IdForGuid(ServiceClassId);
2215
2216 /* Make sure that the control flags are valid */
2217 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
2218 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
2219 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
2220 {
2221 /* Either non-recognized flags or invalid combos were passed */
2222 ErrorCode = WSA_INVALID_PARAMETER;
2223 goto Quickie;
2224 }
2225
2226 /* Make sure that we have no context, and that LUP_CONTAINERS is not on */
2227 if(((lpqsRestrictions->lpszContext) &&
2228 (*lpqsRestrictions->lpszContext) &&
2229 (wcscmp(lpqsRestrictions->lpszContext, L"\\"))) ||
2230 (dwControlFlags & LUP_CONTAINERS))
2231 {
2232 /* We don't support contexts or LUP_CONTAINERS */
2233 ErrorCode = WSANO_DATA;
2234 goto Quickie;
2235 }
2236
2237 /* Is this a Reverse Lookup? */
2238 if (RnrId == 0x80000000)
2239 {
2240 /* Remember for later */
2241 LookupFlags = REVERSE;
2242 }
2243 else
2244 {
2245 /* Is this a IANA Lookup? */
2246 if (RnrId == 0x2)
2247 {
2248 /* Mask out this flag since it's of no use now */
2249 dwControlFlags &= ~(LUP_RETURN_ADDR);
2250
2251 /* This is a IANA lookup, remember for later */
2252 LookupFlags |= IANA;
2253 }
2254
2255 /* Check if we need a name or not */
2256 if ((RnrId == 0x1) ||
2257 (RnrId == 0x10000002) ||
2258 (RnrId == 0x10000023) ||
2259 (RnrId == 0x10000022))
2260 {
2261 /* We do */
2262 NameRequested = TRUE;
2263 }
2264 }
2265
2266 /* Final check to make sure if we need a name or not */
2267 if (RnrId & 0x3000000) NameRequested = TRUE;
2268
2269 /* No Service Name was specified */
2270 if(!(ServiceName) || !(*ServiceName))
2271 {
2272 /*
2273 * A name was requested but no Service Name was given,
2274 * so this is a local lookup
2275 */
2276 if(NameRequested)
2277 {
2278 /* A local Lookup */
2279 LookupFlags |= LOCAL;
2280 ServiceName = L"";
2281 }
2282 else if((LookupFlags & REVERSE) &&
2283 (lpqsRestrictions->lpcsaBuffer) &&
2284 (lpqsRestrictions->dwNumberOfCsAddrs == 1))
2285 {
2286 /* Reverse lookup, make sure a CS Address is there */
2287 ReverseSock = (struct sockaddr_in*)
2288 lpqsRestrictions->lpcsaBuffer->RemoteAddr.lpSockaddr;
2289
2290 /* Convert address to Unicode */
2291 MultiByteToWideChar(CP_ACP,
2292 0,
2293 inet_ntoa(ReverseSock->sin_addr),
2294 -1,
2295 StringBuffer,
2296 16);
2297
2298 /* Set it as the new name */
2299 ServiceName = StringBuffer;
2300 }
2301 else
2302 {
2303 /* We can't do anything without a service name at this point */
2304 ErrorCode = WSA_INVALID_PARAMETER;
2305 goto Quickie;
2306 }
2307 }
2308 else if(NameRequested)
2309 {
2310 /* Check for meaningful DNS Names */
2311 if (DnsNameCompare_W(ServiceName, L"localhost") ||
2312 DnsNameCompare_W(ServiceName, L"loopback"))
2313 {
2314 /* This is the local and/or loopback DNS name */
2315 LookupFlags |= (LOCAL | LOOPBACK);
2316 }
2317 else if (DnsNameCompare_W(ServiceName, g_pszHostName) ||
2318 DnsNameCompare_W(ServiceName, g_pszHostFqdn))
2319 {
2320 /* This is the local name of the computer */
2321 LookupFlags |= LOCAL;
2322 }
2323 }
2324
2325 /* Check if any restrictions were made on the protocols */
2326 if(lpqsRestrictions->lpafpProtocols)
2327 {
2328 /* Save our local copy to speed up the loop */
2329 LocalProtocols = lpqsRestrictions->dwNumberOfProtocols;
2330 ProtocolFlags = 0;
2331
2332 /* Loop the protocols */
2333 for(i = 0; LocalProtocols--;)
2334 {
2335 /* Make sure it's a family that we recognize */
2336 if ((lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET) ||
2337 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET6) ||
2338 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_UNSPEC) ||
2339 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_ATM))
2340 {
2341 /* Find which one is used */
2342 switch(lpqsRestrictions->lpafpProtocols[i].iProtocol)
2343 {
2344 case IPPROTO_UDP:
2345 ProtocolFlags |= UDP;
2346 break;
2347 case IPPROTO_TCP:
2348 ProtocolFlags |= TCP;
2349 break;
2350 case PF_ATM:
2351 ProtocolFlags |= ATM;
2352 break;
2353 default:
2354 break;
2355 }
2356 }
2357 }
2358 /* Make sure we have at least a valid protocol */
2359 if (!ProtocolFlags)
2360 {
2361 /* Fail */
2362 ErrorCode = WSANO_DATA;
2363 goto Quickie;
2364 }
2365 }
2366 else
2367 {
2368 /* No restrictions, assume TCP/UDP */
2369 ProtocolFlags = (TCP | UDP);
2370 }
2371
2372 /* Create the Servent from the Service String */
2373 UdpPort = TcpPort = -1;
2374 ProtocolFlags |= GetServerAndProtocolsFromString(lpqsRestrictions->lpszQueryString,
2375 ServiceClassId,
2376 &LookupServent);
2377
2378 /* Extract the port numbers */
2379 if(LookupServent)
2380 {
2381 /* Are we using UDP? */
2382 if(ProtocolFlags & UDP)
2383 {
2384 /* Get the UDP Port, disable the TCP Port */
2385 UdpPort = ntohs(LookupServent->s_port);
2386 TcpPort = -1;
2387 }
2388 else if(ProtocolFlags & TCP)
2389 {
2390 /* Get the TCP Port, disable the UDP Port */
2391 TcpPort = ntohs(LookupServent->s_port);
2392 UdpPort = -1;
2393 }
2394 }
2395 else
2396 {
2397 /* No servent, so use the Service ID to check */
2398 if(ProtocolFlags & UDP)
2399 {
2400 /* Get the Port from the Service ID */
2401 UdpPort = FetchPortFromClassInfo(UDP,
2402 ServiceClassId,
2403 lpServiceClassInfo);
2404 }
2405 else
2406 {
2407 /* No UDP */
2408 UdpPort = -1;
2409 }
2410
2411 /* No servent, so use the Service ID to check */
2412 if(ProtocolFlags & TCP)
2413 {
2414 /* Get the Port from the Service ID */
2415 UdpPort = FetchPortFromClassInfo(TCP,
2416 ServiceClassId,
2417 lpServiceClassInfo);
2418 }
2419 else
2420 {
2421 /* No TCP */
2422 TcpPort = -1;
2423 }
2424 }
2425
2426 /* Check if we still don't have a valid port by now */
2427 if((TcpPort == -1) && (UdpPort == -1))
2428 {
2429 /* Check if this is TCP */
2430 if ((ProtocolFlags & TCP) || !(ProtocolFlags & UDP))
2431 {
2432 /* Set the UDP Port to 0 */
2433 UdpPort = 0;
2434 }
2435 else
2436 {
2437 /* Set the TCP Port to 0 */
2438 TcpPort = 0;
2439 }
2440 }
2441
2442 /* Allocate a Context for this Query */
2443 RnrContext = RnrCtx_Create(NULL, ServiceName);
2444 RnrContext->lpServiceClassId = *ServiceClassId;
2445 RnrContext->RnrId = RnrId;
2446 RnrContext->dwControlFlags = dwControlFlags;
2447 RnrContext->TcpPort = TcpPort;
2448 RnrContext->UdpPort = UdpPort;
2449 RnrContext->LookupFlags = LookupFlags;
2450 RnrContext->lpProviderId = *lpProviderId;
2451 RnrContext->dwNameSpace = lpqsRestrictions->dwNameSpace;
2452 RnrCtx_Release(RnrContext);
2453
2454 /* Return the context as a handle */
2455 *lphLookup = (HANDLE)RnrContext;
2456
2457 /* Check if this was a TCP, UDP or DNS Query */
2458 if(RnrId & 0x3000000)
2459 {
2460 /* Get the RR Type from the Service ID */
2461 RnrContext->RrType = RR_FROM_SVCID(ServiceClassId);
2462 }
2463
2464 /* Return Success */
2465 ErrorCode = ERROR_SUCCESS;
2466
2467 Quickie:
2468 /* Check if we got here through a failure path */
2469 if (ErrorCode != ERROR_SUCCESS)
2470 {
2471 /* Set the last error and fail */
2472 SetLastError(ErrorCode);
2473 return SOCKET_ERROR;
2474 }
2475
2476 /* Return success */
2477 return ERROR_SUCCESS;
2478 }
2479
2480 INT
2481 WSPAPI
2482 BuildCsAddr(IN LPWSAQUERYSETW QuerySet,
2483 IN PFLATBUFF FlatBuffer,
2484 IN PDNS_BLOB Blob,
2485 IN DWORD UdpPort,
2486 IN DWORD TcpPort,
2487 IN BOOLEAN ReverseLookup)
2488 {
2489 return WSANO_DATA;
2490 }
2491
2492 INT
2493 WINAPI
2494 Dns_NSPLookupServiceNext(IN HANDLE hLookup,
2495 IN DWORD dwControlFlags,
2496 IN OUT LPDWORD lpdwBufferLength,
2497 OUT LPWSAQUERYSETW lpqsResults)
2498 {
2499 INT ErrorCode;
2500 WSAQUERYSETW LocalResults;
2501 LONG Instance;
2502 PRNR_CONTEXT RnrContext = NULL;
2503 FLATBUFF FlatBuffer;
2504 PVOID Name;
2505 PDNS_BLOB Blob = NULL;
2506 DWORD PortNumber;
2507 PSERVENT ServEntry = NULL;
2508 PDNS_ARRAY DnsArray;
2509 BOOLEAN IsUnicode = TRUE;
2510 SIZE_T FreeSize;
2511 ULONG BlobSize;
2512 ULONG_PTR Position;
2513 PVOID BlobData = NULL;
2514 ULONG StringLength;
2515 LPWSTR UnicodeName;
2516
2517 /* Make sure that the control flags are valid */
2518 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
2519 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
2520 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
2521 {
2522 /* Either non-recognized flags or invalid combos were passed */
2523 ErrorCode = WSA_INVALID_PARAMETER;
2524 goto Quickie;
2525 }
2526
2527 /* Get the Context */
2528 RnrContext = RnrCtx_Get(hLookup, dwControlFlags, &Instance);
2529 if (!RnrContext)
2530 {
2531 /* This lookup handle must be invalid */
2532 SetLastError(WSA_INVALID_HANDLE);
2533 return SOCKET_ERROR;
2534 }
2535
2536 /* Assume success for now */
2537 SetLastError(NO_ERROR);
2538
2539 /* Validate the query set size */
2540 if (*lpdwBufferLength < sizeof(WSAQUERYSETW))
2541 {
2542 /* Windows doesn't fail, but sets up a local QS for you... */
2543 lpqsResults = &LocalResults;
2544 ErrorCode = WSAEFAULT;
2545 }
2546
2547 /* Zero out the buffer and fill out basic data */
2548 RtlZeroMemory(lpqsResults, sizeof(WSAQUERYSETW));
2549 lpqsResults->dwNameSpace = NS_DNS;
2550 lpqsResults->dwSize = sizeof(WSAQUERYSETW);
2551
2552 /* Initialize the Buffer */
2553 FlatBuf_Init(&FlatBuffer,
2554 lpqsResults + 1,
2555 (ULONG)(*lpdwBufferLength - sizeof(WSAQUERYSETW)));
2556
2557 /* Check if this is an IANA Lookup */
2558 if(RnrContext->LookupFlags & IANA)
2559 {
2560 /* Service Lookup */
2561 GetServerAndProtocolsFromString(RnrContext->ServiceName,
2562 (LPGUID)&HostnameGuid,
2563 &ServEntry);
2564
2565 /* Get the Port */
2566 PortNumber = ntohs(ServEntry->s_port);
2567
2568 /* Use this as the name */
2569 Name = ServEntry->s_name;
2570 IsUnicode = FALSE;
2571
2572 /* Override some parts of the Context and check for TCP/UDP */
2573 if(!_stricmp("tcp", ServEntry->s_proto))
2574 {
2575 /* Set the TCP Guid */
2576 SET_TCP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
2577 RnrContext->TcpPort = PortNumber;
2578 RnrContext->UdpPort = -1;
2579 }
2580 else
2581 {
2582 /* Set the UDP Guid */
2583 SET_UDP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
2584 RnrContext->UdpPort = PortNumber;
2585 RnrContext->TcpPort = -1;
2586 }
2587 }
2588 else
2589 {
2590 /* Check if the caller requested for RES_SERVICE */
2591 if(RnrContext->dwControlFlags & LUP_RES_SERVICE)
2592 {
2593 /* Make sure that this is the first instance */
2594 if (Instance)
2595 {
2596 /* Fail */
2597 ErrorCode = WSA_E_NO_MORE;
2598 goto Quickie;
2599 }
2600
2601 #if 0
2602 /* Create the blob */
2603 DnsArray = NULL;
2604 Blob = SaBlob_CreateFromIp4(RnrContext->ServiceName,
2605 1,
2606 &DnsArray);
2607 #else
2608 /* FIXME */
2609 Blob = NULL;
2610 DnsArray = NULL;
2611 ErrorCode = WSAEFAULT;
2612 goto Quickie;
2613 #endif
2614 }
2615 else if(!(Blob = RnrContext->CachedSaBlob))
2616 {
2617 /* An actual Host Lookup, but we don't have a cached HostEntry yet */
2618 if (!memcmp(&RnrContext->lpServiceClassId,
2619 &HostnameGuid,
2620 sizeof(GUID)) && !(RnrContext->ServiceName))
2621 {
2622 /* Do a Regular DNS Lookup */
2623 Blob = Rnr_DoHostnameLookup(RnrContext);
2624 }
2625 else if (RnrContext->LookupFlags & REVERSE)
2626 {
2627 /* Do a Reverse DNS Lookup */
2628 Blob = Rnr_GetHostByAddr(RnrContext);
2629 }
2630 else
2631 {
2632 /* Do a Hostname Lookup */
2633 Blob = Rnr_DoDnsLookup(RnrContext);
2634 }
2635
2636 /* Check if we got a blob, and cache it */
2637 if (Blob) RnrContext->CachedSaBlob = Blob;
2638 }
2639
2640 /* We should have a blob by now */
2641 if (!Blob)
2642 {
2643 /* We dont, fail */
2644 if (ErrorCode == NO_ERROR)
2645 {
2646 /* Supposedly no error, so find it out */
2647 ErrorCode = GetLastError();
2648 if (ErrorCode == NO_ERROR) ErrorCode = WSASERVICE_NOT_FOUND;
2649 }
2650
2651 /* Fail */
2652 goto Quickie;
2653 }
2654 }
2655
2656 /* Check if this is the first instance or not */
2657 if(!RnrContext->Instance)
2658 {
2659 /* It is, get the name from the blob */
2660 Name = Blob->Name;
2661 }
2662 else
2663 {
2664 /* Only accept this scenario if the caller wanted Aliases */
2665 if((RnrContext->dwControlFlags & LUP_RETURN_ALIASES) &&
2666 (Blob->AliasCount > RnrContext->Instance))
2667 {
2668 /* Get the name from the Alias */
2669 Name = Blob->Aliases[RnrContext->Instance];
2670
2671 /* Let the caller know that this is an Alias */
2672 /* lpqsResults->dwOutputFlags |= RESULT_IS_ALIAS; */
2673 }
2674 else
2675 {
2676 /* Fail */
2677 ErrorCode = WSA_E_NO_MORE;
2678 goto Quickie;
2679 }
2680 }
2681
2682 /* Lookups are complete... time to return the right stuff! */
2683 lpqsResults->dwNameSpace = NS_DNS;
2684
2685 /* Caller wants the Type back */
2686 if(RnrContext->dwControlFlags & LUP_RETURN_TYPE)
2687 {
2688 /* Copy into the flat buffer and point to it */
2689 lpqsResults->lpServiceClassId = FlatBuf_CopyMemory(&FlatBuffer,
2690 &RnrContext->lpServiceClassId,
2691 sizeof(GUID),
2692 sizeof(PVOID));
2693 }
2694
2695 /* Caller wants the Addreses Back */
2696 if((RnrContext->dwControlFlags & LUP_RETURN_ADDR) && (Blob))
2697 {
2698 /* Build the CS Addr for the caller */
2699 ErrorCode = BuildCsAddr(lpqsResults,
2700 &FlatBuffer,
2701 Blob,
2702 RnrContext->UdpPort,
2703 RnrContext->TcpPort,
2704 (RnrContext->LookupFlags & REVERSE) == 1);
2705 }
2706
2707 /* Caller wants a Blob */
2708 if(RnrContext->dwControlFlags & LUP_RETURN_BLOB)
2709 {
2710 /* Save the current size and position */
2711 FreeSize = FlatBuffer.BufferFreeSize;
2712 Position = FlatBuffer.BufferPos;
2713
2714 /* Allocate some space for the Public Blob */
2715 lpqsResults->lpBlob = FlatBuf_ReserveAlignDword(&FlatBuffer,
2716 sizeof(BLOB));
2717
2718 /* Check for a Cached Blob */
2719 if((RnrContext->RrType) && (RnrContext->CachedBlob.pBlobData))
2720 {
2721 /* We have a Cached Blob, use it */
2722 BlobSize = RnrContext->CachedBlob.cbSize;
2723 BlobData = FlatBuf_ReserveAlignDword(&FlatBuffer, BlobSize);
2724
2725 /* Copy into the blob */
2726 RtlCopyMemory(RnrContext->CachedBlob.pBlobData,
2727 BlobData,
2728 BlobSize);
2729 }
2730 else if (!Blob)
2731 {
2732 /* Create an ANSI Host Entry */
2733 BlobData = SaBlob_CreateHostent(&FlatBuffer.BufferPos,
2734 &FlatBuffer.BufferFreeSize,
2735 &BlobSize,
2736 Blob,
2737 AnsiString,
2738 TRUE,
2739 FALSE);
2740 }
2741 else if ((RnrContext->LookupFlags & IANA) && (ServEntry))
2742 {
2743 /* Get Servent */
2744 BlobData = CopyServEntry(ServEntry,
2745 &FlatBuffer.BufferPos,
2746 &FlatBuffer.BufferFreeSize,
2747 &BlobSize,
2748 TRUE);
2749
2750 /* Manually update the buffer (no SaBlob function for servents) */
2751 FlatBuffer.BufferPos += BlobSize;
2752 FlatBuffer.BufferFreeSize -= BlobSize;
2753 }
2754 else
2755 {
2756 /* We have nothing to return! */
2757 BlobSize = 0;
2758 lpqsResults->lpBlob = NULL;
2759 FlatBuffer.BufferPos = Position;
2760 FlatBuffer.BufferFreeSize = FreeSize;
2761 }
2762
2763 /* Make sure we have a blob by here */
2764 if (Blob)
2765 {
2766 /* Set it */
2767 lpqsResults->lpBlob->pBlobData = BlobData;
2768 lpqsResults->lpBlob->cbSize = BlobSize;
2769 }
2770 else
2771 {
2772 /* Set the error code */
2773 ErrorCode = WSAEFAULT;
2774 }
2775 }
2776
2777 /* Caller wants a name, and we have one */
2778 if((RnrContext->dwControlFlags & LUP_RETURN_NAME) && (Name))
2779 {
2780 /* Check if we have an ANSI name */
2781 if (!IsUnicode)
2782 {
2783 /* Convert it */
2784 StringLength = 512;
2785 Dns_StringCopy(&UnicodeName,
2786 &StringLength,
2787 Name,
2788 0,
2789 AnsiString,
2790 UnicodeString);
2791 }
2792 else
2793 {
2794 /* Keep the name as is */
2795 UnicodeName = (LPWSTR)Name;
2796 }
2797
2798 /* Write it to the buffer */
2799 Name = FlatBuf_WriteString(&FlatBuffer, UnicodeName, TRUE);
2800
2801 /* Return it to the caller */
2802 lpqsResults->lpszServiceInstanceName = Name;
2803 }
2804
2805 Quickie:
2806 /* Check which path got us here */
2807 if (ErrorCode != NO_ERROR)
2808 {
2809 /* Set error */
2810 SetLastError(ErrorCode);
2811
2812 /* Check if was a memory error */
2813 if (ErrorCode == WSAEFAULT)
2814 {
2815 /* Update buffer length */
2816 *lpdwBufferLength -= (DWORD)FlatBuffer.BufferFreeSize;
2817
2818 /* Decrease an instance */
2819 RnrCtx_DecInstance(RnrContext);
2820 }
2821
2822 /* Set the normalized error code */
2823 ErrorCode = SOCKET_ERROR;
2824 }
2825
2826 /* Release the RnR Context */
2827 RnrCtx_Release(RnrContext);
2828
2829 /* Return error code */
2830 return ErrorCode;
2831 }
2832
2833 /*
2834 * COPYRIGHT: See COPYING in the top level directory
2835 * PROJECT: ReactOS Winsock 2 SPI
2836 * FILE: lib/mswsock/lib/init.c
2837 * PURPOSE: DLL Initialization
2838 */
2839
2840 /* INCLUDES ******************************************************************/
2841 #include "msafd.h"
2842
2843 #define ALL_LUP_FLAGS (0x0BFFF)
2844
2845 /* DATA **********************************************************************/
2846
2847 LPWSTR g_pszHostName;
2848 LPWSTR g_pszHostFqdn;
2849 LONG g_NspRefCount;
2850 GUID NbtProviderId = {0};
2851 GUID DNSProviderId = {0};
2852 DWORD MaskOfGuids;
2853
2854 NSP_ROUTINE g_NspVector = {sizeof(NSP_ROUTINE),
2855 1,
2856 1,
2857 Dns_NSPCleanup,
2858 Dns_NSPLookupServiceBegin,
2859 Dns_NSPLookupServiceNext,
2860 Dns_NSPLookupServiceEnd,
2861 Dns_NSPSetService,
2862 Dns_NSPInstallServiceClass,
2863 Dns_NSPRemoveServiceClass,
2864 Dns_NSPGetServiceClassInfo};
2865
2866 /* FUNCTIONS *****************************************************************/
2867
2868 INT
2869 WINAPI
2870 Dns_NSPStartup(IN LPGUID lpProviderId,
2871 IN OUT LPNSP_ROUTINE lpsnpRoutines)
2872 {
2873 INT ErrorCode;
2874 BOOLEAN Prolog;
2875
2876 /* Validate the size */
2877 if (lpsnpRoutines->cbSize != sizeof(NSP_ROUTINE))
2878 {
2879 /* Fail */
2880 SetLastError(WSAEINVALIDPROCTABLE);
2881 return SOCKET_ERROR;
2882 }
2883
2884 /* Enter the prolog */
2885 Prolog = RNRPROV_SockEnterApi();
2886 if (Prolog)
2887 {
2888 /* Increase our reference count */
2889 InterlockedIncrement(&g_NspRefCount);
2890
2891 /* Check if we don't have the hostname */
2892 if (!g_pszHostName)
2893 {
2894 /* Query it from DNS */
2895 DnsQueryConfig(DnsConfigHostName_W,
2896 DNS_CONFIG_FLAG_ALLOC,
2897 NULL,
2898 NULL,
2899 &g_pszHostName,
2900 0);
2901 }
2902
2903 /* Check if we have a hostname now, but not a Fully-Qualified Domain */
2904 if (g_pszHostName && !(g_pszHostFqdn))
2905 {
2906 /* Get the domain from DNS */
2907 DnsQueryConfig(DnsConfigFullHostName_W,
2908 DNS_CONFIG_FLAG_ALLOC,
2909 NULL,
2910 NULL,
2911 &g_pszHostFqdn,
2912 0);
2913 }
2914
2915 /* If we don't have both of them, then set error */
2916 if (!(g_pszHostName) || !(g_pszHostFqdn)) ErrorCode = SOCKET_ERROR;
2917 }
2918
2919 /* Check if the Prolog or DNS Local Queries failed */
2920 if (!(Prolog) || (ErrorCode != NO_ERROR))
2921 {
2922 /* Fail */
2923 SetLastError(WSASYSNOTREADY);
2924 return SOCKET_ERROR;
2925 }
2926
2927 /* Copy the Routines */
2928 RtlMoveMemory(lpsnpRoutines, &g_NspVector, sizeof(NSP_ROUTINE));
2929
2930 /* Check if this is NBT or DNS */
2931 if (!memcmp(lpProviderId, &NbtProviderId, sizeof(GUID)))
2932 {
2933 /* Enable the NBT Mask */
2934 MaskOfGuids |= NBT_MASK;
2935 }
2936 else if (!memcmp(lpProviderId, &DNSProviderId, sizeof(GUID)))
2937 {
2938 /* Enable the DNS Mask */
2939 MaskOfGuids |= DNS_MASK;
2940 }
2941
2942 /* Return success */
2943 return NO_ERROR;
2944 }
2945
2946 VOID
2947 WSPAPI
2948 Nsp_GlobalCleanup(VOID)
2949 {
2950 /* Cleanup the RnR Contexts */
2951 RnrCtx_ListCleanup();
2952
2953 /* Free the hostnames, if we have them */
2954 if (g_pszHostName) DnsApiFree(g_pszHostName);
2955 if (g_pszHostFqdn) DnsApiFree(g_pszHostFqdn);
2956 g_pszHostFqdn = g_pszHostName = NULL;
2957 }
2958
2959 INT
2960 WINAPI
2961 NSPStartup(IN LPGUID lpProviderId,
2962 IN OUT LPNSP_ROUTINE lpsnpRoutines)
2963 {
2964 INT ErrorCode;
2965
2966 /* Initialize the DLL */
2967 ErrorCode = MSWSOCK_Initialize();
2968 if (ErrorCode != NO_ERROR)
2969 {
2970 /* Fail */
2971 SetLastError(WSANOTINITIALISED);
2972 return SOCKET_ERROR;
2973 }
2974
2975 /* Check if this is Winsock Mobile or DNS */
2976 if (!memcmp(lpProviderId, &gNLANamespaceGuid, sizeof(GUID)))
2977 {
2978 /* Initialize WSM */
2979 return WSM_NSPStartup(lpProviderId, lpsnpRoutines);
2980 }
2981
2982 /* Initialize DNS */
2983 return Dns_NSPStartup(lpProviderId, lpsnpRoutines);
2984 }
2985
2986 INT
2987 WINAPI
2988 Dns_NSPCleanup(IN LPGUID lpProviderId)
2989 {
2990 /* Decrement our reference count and do global cleanup if it's reached 0 */
2991 if (!(InterlockedDecrement(&g_NspRefCount))) Nsp_GlobalCleanup();
2992
2993 /* Return success */
2994 return NO_ERROR;
2995 }
2996
2997 INT
2998 WINAPI
2999 Dns_NSPSetService(IN LPGUID lpProviderId,
3000 IN LPWSASERVICECLASSINFOW lpServiceClassInfo,
3001 IN LPWSAQUERYSETW lpqsRegInfo,
3002 IN WSAESETSERVICEOP essOperation,
3003 IN DWORD dwControlFlags)
3004 {
3005 /* Unlike NLA, DNS Services cannot be dynmically modified */
3006 SetLastError(ERROR_NOT_SUPPORTED);
3007 return SOCKET_ERROR;
3008 }
3009
3010 INT
3011 WINAPI
3012 Dns_NSPInstallServiceClass(IN LPGUID lpProviderId,
3013 IN LPWSASERVICECLASSINFOW lpServiceClassInfo)
3014 {
3015 /* Unlike NLA, DNS Services cannot be dynmically modified */
3016 SetLastError(WSAEOPNOTSUPP);
3017 return SOCKET_ERROR;
3018 };
3019
3020 INT
3021 WINAPI
3022 Dns_NSPRemoveServiceClass(IN LPGUID lpProviderId,
3023 IN LPGUID lpServiceCallId)
3024 {
3025 /* Unlike NLA, DNS Services cannot be dynmically modified */
3026 SetLastError(WSAEOPNOTSUPP);
3027 return SOCKET_ERROR;
3028 }
3029 INT
3030 WINAPI
3031 Dns_NSPGetServiceClassInfo(IN LPGUID lpProviderId,
3032 IN OUT LPDWORD lpdwBufSize,
3033 IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
3034 {
3035 /* Unlike NLA, DNS Services cannot be dynmically modified */
3036 SetLastError(WSAEOPNOTSUPP);
3037 return SOCKET_ERROR;
3038 }
3039
3040 INT
3041 WINAPI
3042 Dns_NSPLookupServiceEnd(IN HANDLE hLookup)
3043 {
3044 PRNR_CONTEXT RnrContext;
3045
3046 /* Get this handle's context */
3047 RnrContext = RnrCtx_Get(hLookup, 0, NULL);
3048
3049 /* Mark it as completed */
3050 RnrContext->LookupFlags |= DONE;
3051
3052 /* Dereference it once for our _Get */
3053 RnrCtx_Release(RnrContext);
3054
3055 /* And once last to delete it */
3056 RnrCtx_Release(RnrContext);
3057
3058 /* return */
3059 return NO_ERROR;
3060 }
3061
3062 INT
3063 WINAPI
3064 rnr_IdForGuid(IN LPGUID Guid)
3065 {
3066
3067 if (memcmp(Guid, &InetHostName, sizeof(GUID))) return 0x10000002;
3068 if (memcmp(Guid, &Ipv6Guid, sizeof(GUID))) return 0x10000023;
3069 if (memcmp(Guid, &HostnameGuid, sizeof(GUID))) return 0x1;
3070 if (memcmp(Guid, &AddressGuid, sizeof(GUID))) return 0x80000000;
3071 if (memcmp(Guid, &IANAGuid, sizeof(GUID))) return 0x2;
3072 if IS_SVCID_DNS(Guid) return 0x5000000;
3073 if IS_SVCID_TCP(Guid) return 0x1000000;
3074 if IS_SVCID_UDP(Guid) return 0x2000000;
3075 return 0;
3076 }
3077
3078 PVOID
3079 WSPAPI
3080 FlatBuf_ReserveAlignDword(IN PFLATBUFF FlatBuffer,
3081 IN ULONG Size)
3082 {
3083 /* Let DNSLIB do the grunt work */
3084 return FlatBuf_Arg_Reserve((PVOID)FlatBuffer->BufferPos,
3085 &FlatBuffer->BufferFreeSize,
3086 Size,
3087 sizeof(PVOID));
3088 }
3089
3090 PVOID
3091 WSPAPI
3092 FlatBuf_WriteString(IN PFLATBUFF FlatBuffer,
3093 IN PVOID String,
3094 IN BOOLEAN IsUnicode)
3095 {
3096 /* Let DNSLIB do the grunt work */
3097 return FlatBuf_Arg_WriteString((PVOID)FlatBuffer->BufferPos,
3098 &FlatBuffer->BufferFreeSize,
3099 String,
3100 IsUnicode);
3101 }
3102
3103 PVOID
3104 WSPAPI
3105 FlatBuf_CopyMemory(IN PFLATBUFF FlatBuffer,
3106 IN PVOID Buffer,
3107 IN ULONG Size,
3108 IN ULONG Align)
3109 {
3110 /* Let DNSLIB do the grunt work */
3111 return FlatBuf_Arg_CopyMemory((PVOID)FlatBuffer->BufferPos,
3112 &FlatBuffer->BufferFreeSize,
3113 Buffer,
3114 Size,
3115 Align);
3116 }
3117
3118 INT
3119 WINAPI
3120 Dns_NSPLookupServiceBegin(LPGUID lpProviderId,
3121 LPWSAQUERYSETW lpqsRestrictions,
3122 LPWSASERVICECLASSINFOW lpServiceClassInfo,
3123 DWORD dwControlFlags,
3124 LPHANDLE lphLookup)
3125 {
3126 INT ErrorCode = SOCKET_ERROR;
3127 PWCHAR ServiceName = lpqsRestrictions->lpszServiceInstanceName;
3128 LPGUID ServiceClassId;
3129 INT RnrId;
3130 ULONG LookupFlags = 0;
3131 BOOL NameRequested = FALSE;
3132 WCHAR StringBuffer[48];
3133 ULONG i;
3134 DWORD LocalProtocols;
3135 ULONG ProtocolFlags;
3136 PSERVENT LookupServent;
3137 DWORD UdpPort, TcpPort;
3138 PRNR_CONTEXT RnrContext;
3139 PSOCKADDR_IN ReverseSock;
3140
3141 /* Check if the Size isn't weird */
3142 if(lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW))
3143 {
3144 ErrorCode = WSAEFAULT;
3145 goto Quickie;
3146 }
3147
3148 /* Get the GUID */
3149 ServiceClassId = lpqsRestrictions->lpServiceClassId;
3150 if(!ServiceClassId)
3151 {
3152 /* No GUID, fail */
3153 ErrorCode = WSA_INVALID_PARAMETER;
3154 goto Quickie;
3155 }
3156
3157 /* Get the RNR ID */
3158 RnrId = rnr_IdForGuid(ServiceClassId);
3159
3160 /* Make sure that the control flags are valid */
3161 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
3162 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
3163 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
3164 {
3165 /* Either non-recognized flags or invalid combos were passed */
3166 ErrorCode = WSA_INVALID_PARAMETER;
3167 goto Quickie;
3168 }
3169
3170 /* Make sure that we have no context, and that LUP_CONTAINERS is not on */
3171 if(((lpqsRestrictions->lpszContext) &&
3172 (*lpqsRestrictions->lpszContext) &&
3173 (wcscmp(lpqsRestrictions->lpszContext, L"\\"))) ||
3174 (dwControlFlags & LUP_CONTAINERS))
3175 {
3176 /* We don't support contexts or LUP_CONTAINERS */
3177 ErrorCode = WSANO_DATA;
3178 goto Quickie;
3179 }
3180
3181 /* Is this a Reverse Lookup? */
3182 if (RnrId == 0x80000000)
3183 {
3184 /* Remember for later */
3185 LookupFlags = REVERSE;
3186 }
3187 else
3188 {
3189 /* Is this a IANA Lookup? */
3190 if (RnrId == 0x2)
3191 {
3192 /* Mask out this flag since it's of no use now */
3193 dwControlFlags &= ~(LUP_RETURN_ADDR);
3194
3195 /* This is a IANA lookup, remember for later */
3196 LookupFlags |= IANA;
3197 }
3198
3199 /* Check if we need a name or not */
3200 if ((RnrId == 0x1) ||
3201 (RnrId == 0x10000002) ||
3202 (RnrId == 0x10000023) ||
3203 (RnrId == 0x10000022))
3204 {
3205 /* We do */
3206 NameRequested = TRUE;
3207 }
3208 }
3209
3210 /* Final check to make sure if we need a name or not */
3211 if (RnrId & 0x3000000) NameRequested = TRUE;
3212
3213 /* No Service Name was specified */
3214 if(!(ServiceName) || !(*ServiceName))
3215 {
3216 /*
3217 * A name was requested but no Service Name was given,
3218 * so this is a local lookup
3219 */
3220 if(NameRequested)
3221 {
3222 /* A local Lookup */
3223 LookupFlags |= LOCAL;
3224 ServiceName = L"";
3225 }
3226 else if((LookupFlags & REVERSE) &&
3227 (lpqsRestrictions->lpcsaBuffer) &&
3228 (lpqsRestrictions->dwNumberOfCsAddrs == 1))
3229 {
3230 /* Reverse lookup, make sure a CS Address is there */
3231 ReverseSock = (struct sockaddr_in*)
3232 lpqsRestrictions->lpcsaBuffer->RemoteAddr.lpSockaddr;
3233
3234 /* Convert address to Unicode */
3235 MultiByteToWideChar(CP_ACP,
3236 0,
3237 inet_ntoa(ReverseSock->sin_addr),
3238 -1,
3239 StringBuffer,
3240 16);
3241
3242 /* Set it as the new name */
3243 ServiceName = StringBuffer;
3244 }
3245 else
3246 {
3247 /* We can't do anything without a service name at this point */
3248 ErrorCode = WSA_INVALID_PARAMETER;
3249 goto Quickie;
3250 }
3251 }
3252 else if(NameRequested)
3253 {
3254 /* Check for meaningful DNS Names */
3255 if (DnsNameCompare_W(ServiceName, L"localhost") ||
3256 DnsNameCompare_W(ServiceName, L"loopback"))
3257 {
3258 /* This is the local and/or loopback DNS name */
3259 LookupFlags |= (LOCAL | LOOPBACK);
3260 }
3261 else if (DnsNameCompare_W(ServiceName, g_pszHostName) ||
3262 DnsNameCompare_W(ServiceName, g_pszHostFqdn))
3263 {
3264 /* This is the local name of the computer */
3265 LookupFlags |= LOCAL;
3266 }
3267 }
3268
3269 /* Check if any restrictions were made on the protocols */
3270 if(lpqsRestrictions->lpafpProtocols)
3271 {
3272 /* Save our local copy to speed up the loop */
3273 LocalProtocols = lpqsRestrictions->dwNumberOfProtocols;
3274 ProtocolFlags = 0;
3275
3276 /* Loop the protocols */
3277 for(i = 0; LocalProtocols--;)
3278 {
3279 /* Make sure it's a family that we recognize */
3280 if ((lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET) ||
3281 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_INET6) ||
3282 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_UNSPEC) ||
3283 (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_ATM))
3284 {
3285 /* Find which one is used */
3286 switch(lpqsRestrictions->lpafpProtocols[i].iProtocol)
3287 {
3288 case IPPROTO_UDP:
3289 ProtocolFlags |= UDP;
3290 break;
3291 case IPPROTO_TCP:
3292 ProtocolFlags |= TCP;
3293 break;
3294 case PF_ATM:
3295 ProtocolFlags |= ATM;
3296 break;
3297 default:
3298 break;
3299 }
3300 }
3301 }
3302 /* Make sure we have at least a valid protocol */
3303 if (!ProtocolFlags)
3304 {
3305 /* Fail */
3306 ErrorCode = WSANO_DATA;
3307 goto Quickie;
3308 }
3309 }
3310 else
3311 {
3312 /* No restrictions, assume TCP/UDP */
3313 ProtocolFlags = (TCP | UDP);
3314 }
3315
3316 /* Create the Servent from the Service String */
3317 UdpPort = TcpPort = -1;
3318 ProtocolFlags |= GetServerAndProtocolsFromString(lpqsRestrictions->lpszQueryString,
3319 ServiceClassId,
3320 &LookupServent);
3321
3322 /* Extract the port numbers */
3323 if(LookupServent)
3324 {
3325 /* Are we using UDP? */
3326 if(ProtocolFlags & UDP)
3327 {
3328 /* Get the UDP Port, disable the TCP Port */
3329 UdpPort = ntohs(LookupServent->s_port);
3330 TcpPort = -1;
3331 }
3332 else if(ProtocolFlags & TCP)
3333 {
3334 /* Get the TCP Port, disable the UDP Port */
3335 TcpPort = ntohs(LookupServent->s_port);
3336 UdpPort = -1;
3337 }
3338 }
3339 else
3340 {
3341 /* No servent, so use the Service ID to check */
3342 if(ProtocolFlags & UDP)
3343 {
3344 /* Get the Port from the Service ID */
3345 UdpPort = FetchPortFromClassInfo(UDP,
3346 ServiceClassId,
3347 lpServiceClassInfo);
3348 }
3349 else
3350 {
3351 /* No UDP */
3352 UdpPort = -1;
3353 }
3354
3355 /* No servent, so use the Service ID to check */
3356 if(ProtocolFlags & TCP)
3357 {
3358 /* Get the Port from the Service ID */
3359 UdpPort = FetchPortFromClassInfo(TCP,
3360 ServiceClassId,
3361 lpServiceClassInfo);
3362 }
3363 else
3364 {
3365 /* No TCP */
3366 TcpPort = -1;
3367 }
3368 }
3369
3370 /* Check if we still don't have a valid port by now */
3371 if((TcpPort == -1) && (UdpPort == -1))
3372 {
3373 /* Check if this is TCP */
3374 if ((ProtocolFlags & TCP) || !(ProtocolFlags & UDP))
3375 {
3376 /* Set the UDP Port to 0 */
3377 UdpPort = 0;
3378 }
3379 else
3380 {
3381 /* Set the TCP Port to 0 */
3382 TcpPort = 0;
3383 }
3384 }
3385
3386 /* Allocate a Context for this Query */
3387 RnrContext = RnrCtx_Create(NULL, ServiceName);
3388 RnrContext->lpServiceClassId = *ServiceClassId;
3389 RnrContext->RnrId = RnrId;
3390 RnrContext->dwControlFlags = dwControlFlags;
3391 RnrContext->TcpPort = TcpPort;
3392 RnrContext->UdpPort = UdpPort;
3393 RnrContext->LookupFlags = LookupFlags;
3394 RnrContext->lpProviderId = *lpProviderId;
3395 RnrContext->dwNameSpace = lpqsRestrictions->dwNameSpace;
3396 RnrCtx_Release(RnrContext);
3397
3398 /* Return the context as a handle */
3399 *lphLookup = (HANDLE)RnrContext;
3400
3401 /* Check if this was a TCP, UDP or DNS Query */
3402 if(RnrId & 0x3000000)
3403 {
3404 /* Get the RR Type from the Service ID */
3405 RnrContext->RrType = RR_FROM_SVCID(ServiceClassId);
3406 }
3407
3408 /* Return Success */
3409 ErrorCode = ERROR_SUCCESS;
3410
3411 Quickie:
3412 /* Check if we got here through a failure path */
3413 if (ErrorCode != ERROR_SUCCESS)
3414 {
3415 /* Set the last error and fail */
3416 SetLastError(ErrorCode);
3417 return SOCKET_ERROR;
3418 }
3419
3420 /* Return success */
3421 return ERROR_SUCCESS;
3422 }
3423
3424 INT
3425 WSPAPI
3426 BuildCsAddr(IN LPWSAQUERYSETW QuerySet,
3427 IN PFLATBUFF FlatBuffer,
3428 IN PDNS_BLOB Blob,
3429 IN DWORD UdpPort,
3430 IN DWORD TcpPort,
3431 IN BOOLEAN ReverseLookup)
3432 {
3433 return WSANO_DATA;
3434 }
3435
3436 INT
3437 WINAPI
3438 Dns_NSPLookupServiceNext(IN HANDLE hLookup,
3439 IN DWORD dwControlFlags,
3440 IN OUT LPDWORD lpdwBufferLength,
3441 OUT LPWSAQUERYSETW lpqsResults)
3442 {
3443 INT ErrorCode;
3444 WSAQUERYSETW LocalResults;
3445 LONG Instance;
3446 PRNR_CONTEXT RnrContext = NULL;
3447 FLATBUFF FlatBuffer;
3448 PVOID Name;
3449 PDNS_BLOB Blob = NULL;
3450 DWORD PortNumber;
3451 PSERVENT ServEntry = NULL;
3452 PDNS_ARRAY DnsArray;
3453 BOOLEAN IsUnicode = TRUE;
3454 SIZE_T FreeSize;
3455 ULONG BlobSize;
3456 ULONG_PTR Position;
3457 PVOID BlobData = NULL;
3458 ULONG StringLength;
3459 LPWSTR UnicodeName;
3460
3461 /* Make sure that the control flags are valid */
3462 if ((dwControlFlags & ~ALL_LUP_FLAGS) ||
3463 ((dwControlFlags & (LUP_CONTAINERS | LUP_NOCONTAINERS)) ==
3464 (LUP_CONTAINERS | LUP_NOCONTAINERS)))
3465 {
3466 /* Either non-recognized flags or invalid combos were passed */
3467 ErrorCode = WSA_INVALID_PARAMETER;
3468 goto Quickie;
3469 }
3470
3471 /* Get the Context */
3472 RnrContext = RnrCtx_Get(hLookup, dwControlFlags, &Instance);
3473 if (!RnrContext)
3474 {
3475 /* This lookup handle must be invalid */
3476 SetLastError(WSA_INVALID_HANDLE);
3477 return SOCKET_ERROR;
3478 }
3479
3480 /* Assume success for now */
3481 SetLastError(NO_ERROR);
3482
3483 /* Validate the query set size */
3484 if (*lpdwBufferLength < sizeof(WSAQUERYSETW))
3485 {
3486 /* Windows doesn't fail, but sets up a local QS for you... */
3487 lpqsResults = &LocalResults;
3488 ErrorCode = WSAEFAULT;
3489 }
3490
3491 /* Zero out the buffer and fill out basic data */
3492 RtlZeroMemory(lpqsResults, sizeof(WSAQUERYSETW));
3493 lpqsResults->dwNameSpace = NS_DNS;
3494 lpqsResults->dwSize = sizeof(WSAQUERYSETW);
3495
3496 /* Initialize the Buffer */
3497 FlatBuf_Init(&FlatBuffer,
3498 lpqsResults + 1,
3499 (ULONG)(*lpdwBufferLength - sizeof(WSAQUERYSETW)));
3500
3501 /* Check if this is an IANA Lookup */
3502 if(RnrContext->LookupFlags & IANA)
3503 {
3504 /* Service Lookup */
3505 GetServerAndProtocolsFromString(RnrContext->ServiceName,
3506 (LPGUID)&HostnameGuid,
3507 &ServEntry);
3508
3509 /* Get the Port */
3510 PortNumber = ntohs(ServEntry->s_port);
3511
3512 /* Use this as the name */
3513 Name = ServEntry->s_name;
3514 IsUnicode = FALSE;
3515
3516 /* Override some parts of the Context and check for TCP/UDP */
3517 if(!_stricmp("tcp", ServEntry->s_proto))
3518 {
3519 /* Set the TCP Guid */
3520 SET_TCP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
3521 RnrContext->TcpPort = PortNumber;
3522 RnrContext->UdpPort = -1;
3523 }
3524 else
3525 {
3526 /* Set the UDP Guid */
3527 SET_UDP_SVCID(&RnrContext->lpServiceClassId, PortNumber);
3528 RnrContext->UdpPort = PortNumber;
3529 RnrContext->TcpPort = -1;
3530 }
3531 }
3532 else
3533 {
3534 /* Check if the caller requested for RES_SERVICE */
3535 if(RnrContext->dwControlFlags & LUP_RES_SERVICE)
3536 {
3537 /* Make sure that this is the first instance */
3538 if (Instance)
3539 {
3540 /* Fail */
3541 ErrorCode = WSA_E_NO_MORE;
3542 goto Quickie;
3543 }
3544
3545 #if 0
3546 /* Create the blob */
3547 DnsArray = NULL;
3548 Blob = SaBlob_CreateFromIp4(RnrContext->ServiceName,
3549 1,
3550 &DnsArray);
3551 #else
3552 /* FIXME */
3553 Blob = NULL;
3554 DnsArray = NULL;
3555 ErrorCode = WSAEFAULT;
3556 goto Quickie;
3557 #endif
3558 }
3559 else if(!(Blob = RnrContext->CachedSaBlob))
3560 {
3561 /* An actual Host Lookup, but we don't have a cached HostEntry yet */
3562 if (!memcmp(&RnrContext->lpServiceClassId,
3563 &HostnameGuid,
3564 sizeof(GUID)) && !(RnrContext->ServiceName))
3565 {
3566 /* Do a Regular DNS Lookup */
3567 Blob = Rnr_DoHostnameLookup(RnrContext);
3568 }
3569 else if (RnrContext->LookupFlags & REVERSE)
3570 {
3571 /* Do a Reverse DNS Lookup */
3572 Blob = Rnr_GetHostByAddr(RnrContext);
3573 }
3574 else
3575 {
3576 /* Do a Hostname Lookup */
3577 Blob = Rnr_DoDnsLookup(RnrContext);
3578 }
3579
3580 /* Check if we got a blob, and cache it */
3581 if (Blob) RnrContext->CachedSaBlob = Blob;
3582 }
3583
3584 /* We should have a blob by now */
3585 if (!Blob)
3586 {
3587 /* We dont, fail */
3588 if (ErrorCode == NO_ERROR)
3589 {
3590 /* Supposedly no error, so find it out */
3591 ErrorCode = GetLastError();
3592 if (ErrorCode == NO_ERROR) ErrorCode = WSASERVICE_NOT_FOUND;
3593 }
3594
3595 /* Fail */
3596 goto Quickie;
3597 }
3598 }
3599
3600 /* Check if this is the first instance or not */
3601 if(!RnrContext->Instance)
3602 {
3603 /* It is, get the name from the blob */
3604 Name = Blob->Name;
3605 }
3606 else
3607 {
3608 /* Only accept this scenario if the caller wanted Aliases */
3609 if((RnrContext->dwControlFlags & LUP_RETURN_ALIASES) &&
3610 (Blob->AliasCount > RnrContext->Instance))
3611 {
3612 /* Get the name from the Alias */
3613 Name = Blob->Aliases[RnrContext->Instance];
3614
3615 /* Let the caller know that this is an Alias */
3616 /* lpqsResults->dwOutputFlags |= RESULT_IS_ALIAS; */
3617 }
3618 else
3619 {
3620 /* Fail */
3621 ErrorCode = WSA_E_NO_MORE;
3622 goto Quickie;
3623 }
3624 }
3625
3626 /* Lookups are complete... time to return the right stuff! */
3627 lpqsResults->dwNameSpace = NS_DNS;
3628
3629 /* Caller wants the Type back */
3630 if(RnrContext->dwControlFlags & LUP_RETURN_TYPE)
3631 {
3632 /* Copy into the flat buffer and point to it */
3633 lpqsResults->lpServiceClassId = FlatBuf_CopyMemory(&FlatBuffer,
3634 &RnrContext->lpServiceClassId,
3635 sizeof(GUID),
3636 sizeof(PVOID));
3637 }
3638
3639 /* Caller wants the Addreses Back */
3640 if((RnrContext->dwControlFlags & LUP_RETURN_ADDR) && (Blob))
3641 {
3642 /* Build the CS Addr for the caller */
3643 ErrorCode = BuildCsAddr(lpqsResults,
3644 &FlatBuffer,
3645 Blob,
3646 RnrContext->UdpPort,
3647 RnrContext->TcpPort,
3648 (RnrContext->LookupFlags & REVERSE) == 1);
3649 }
3650
3651 /* Caller wants a Blob */
3652 if(RnrContext->dwControlFlags & LUP_RETURN_BLOB)
3653 {
3654 /* Save the current size and position */
3655 FreeSize = FlatBuffer.BufferFreeSize;
3656 Position = FlatBuffer.BufferPos;
3657
3658 /* Allocate some space for the Public Blob */
3659 lpqsResults->lpBlob = FlatBuf_ReserveAlignDword(&FlatBuffer,
3660 sizeof(BLOB));
3661
3662 /* Check for a Cached Blob */
3663 if((RnrContext->RrType) && (RnrContext->CachedBlob.pBlobData))
3664 {
3665 /* We have a Cached Blob, use it */
3666 BlobSize = RnrContext->CachedBlob.cbSize;
3667 BlobData = FlatBuf_ReserveAlignDword(&FlatBuffer, BlobSize);
3668
3669 /* Copy into the blob */
3670 RtlCopyMemory(RnrContext->CachedBlob.pBlobData,
3671 BlobData,
3672 BlobSize);
3673 }
3674 else if (!Blob)
3675 {
3676 /* Create an ANSI Host Entry */
3677 BlobData = SaBlob_CreateHostent(&FlatBuffer.BufferPos,
3678 &FlatBuffer.BufferFreeSize,
3679 &BlobSize,
3680 Blob,
3681 AnsiString,
3682 TRUE,
3683 FALSE);
3684 }
3685 else if ((RnrContext->LookupFlags & IANA) && (ServEntry))
3686 {
3687 /* Get Servent */
3688 BlobData = CopyServEntry(ServEntry,
3689 &FlatBuffer.BufferPos,
3690 &FlatBuffer.BufferFreeSize,
3691 &BlobSize,
3692 TRUE);
3693
3694 /* Manually update the buffer (no SaBlob function for servents) */
3695 FlatBuffer.BufferPos += BlobSize;
3696 FlatBuffer.BufferFreeSize -= BlobSize;
3697 }
3698 else
3699 {
3700 /* We have nothing to return! */
3701 BlobSize = 0;
3702 lpqsResults->lpBlob = NULL;
3703 FlatBuffer.BufferPos = Position;
3704 FlatBuffer.BufferFreeSize = FreeSize;
3705 }
3706
3707 /* Make sure we have a blob by here */
3708 if (Blob)
3709 {
3710 /* Set it */
3711 lpqsResults->lpBlob->pBlobData = BlobData;
3712 lpqsResults->lpBlob->cbSize = BlobSize;
3713 }
3714 else
3715 {
3716 /* Set the error code */
3717 ErrorCode = WSAEFAULT;
3718 }
3719 }
3720
3721 /* Caller wants a name, and we have one */
3722 if((RnrContext->dwControlFlags & LUP_RETURN_NAME) && (Name))
3723 {
3724 /* Check if we have an ANSI name */
3725 if (!IsUnicode)
3726 {
3727 /* Convert it */
3728 StringLength = 512;
3729 Dns_StringCopy(&UnicodeName,
3730 &StringLength,
3731 Name,
3732 0,
3733 AnsiString,
3734 UnicodeString);
3735 }
3736 else
3737 {
3738 /* Keep the name as is */
3739 UnicodeName = (LPWSTR)Name;
3740 }
3741
3742 /* Write it to the buffer */
3743 Name = FlatBuf_WriteString(&FlatBuffer, UnicodeName, TRUE);
3744
3745 /* Return it to the caller */
3746 lpqsResults->lpszServiceInstanceName = Name;
3747 }
3748
3749 Quickie:
3750 /* Check which path got us here */
3751 if (ErrorCode != NO_ERROR)
3752 {
3753 /* Set error */
3754 SetLastError(ErrorCode);
3755
3756 /* Check if was a memory error */
3757 if (ErrorCode == WSAEFAULT)
3758 {
3759 /* Update buffer length */
3760 *lpdwBufferLength -= (DWORD)FlatBuffer.BufferFreeSize;
3761
3762 /* Decrease an instance */
3763 RnrCtx_DecInstance(RnrContext);
3764 }
3765
3766 /* Set the normalized error code */
3767 ErrorCode = SOCKET_ERROR;
3768 }
3769
3770 /* Release the RnR Context */
3771 RnrCtx_Release(RnrContext);
3772
3773 /* Return error code */
3774 return ErrorCode;
3775 }
3776