Author: tfaber
Date: Thu Apr 9 19:42:18 2015
New Revision: 67122
URL:
http://svn.reactos.org/svn/reactos?rev=67122&view=rev
Log:
[RTL]
- Implement RtlIpv6AddressToString*. Patch by Mark Jansen.
CORE-6490
Modified:
trunk/reactos/lib/rtl/network.c
Modified: trunk/reactos/lib/rtl/network.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/network.c?rev=6712…
==============================================================================
--- trunk/reactos/lib/rtl/network.c [iso-8859-1] (original)
+++ trunk/reactos/lib/rtl/network.c [iso-8859-1] Thu Apr 9 19:42:18 2015
@@ -18,6 +18,12 @@
/* maximum length of an ipv4 port expressed as a string */
#define IPV4_PORT_STRING_MAX_LEN 7 /* with the leading ':' */
+
+/* maximum length of an ipv6 string for RtlIpv6AddressToString */
+#define RTLIPV6A2S_MAX_LEN 46
+
+/* maximum length of an ipv6 string with scope and port for RtlIpv6AddressToStringEx */
+#define RTLIPV6A2SEX_MAX_LEN 65
/* network to host order conversion for little endian machines */
#define WN2H(w) (((w & 0xFF00) >> 8) | ((w & 0x00FF) << 8))
@@ -443,20 +449,38 @@
}
/*
-* @unimplemented
+* @implemented
*/
PSTR
NTAPI
RtlIpv6AddressToStringA(
_In_ const struct in6_addr *Addr,
- _Out_writes_(46) PSTR S)
-{
- UNIMPLEMENTED;
- return NULL;
-}
-
-/*
-* @unimplemented
+ _Out_writes_(RTLIPV6A2S_MAX_LEN) PSTR S)
+{
+ WCHAR Buffer[RTLIPV6A2S_MAX_LEN];
+ PWSTR Result;
+ NTSTATUS Status;
+
+ if (!S)
+ return (PSTR)~0;
+
+ Buffer[0] = 0;
+ Result = RtlIpv6AddressToStringW(Addr, Buffer);
+ if (Result == (PWSTR)~0)
+ return (PSTR)~0;
+
+ ASSERT(Result >= Buffer);
+ ASSERT(Result < Buffer + RTL_NUMBER_OF(Buffer));
+
+ Status = RtlUnicodeToMultiByteN(S, RTLIPV6A2S_MAX_LEN, NULL, Buffer, (wcslen(Buffer)
+ 1) * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ return (PSTR)~0;
+
+ return S + strlen(S);
+}
+
+/*
+* @implemented
*/
NTSTATUS
NTAPI
@@ -467,25 +491,135 @@
_Out_writes_to_(*AddressStringLength, *AddressStringLength) PSTR AddressString,
_Inout_ PULONG AddressStringLength)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
-* @unimplemented
+ WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN];
+ NTSTATUS Status;
+
+ if (!Address || !AddressString || !AddressStringLength)
+ return STATUS_INVALID_PARAMETER;
+
+ Status = RtlIpv6AddressToStringExW(Address, ScopeId, Port, Buffer,
AddressStringLength);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ Status = RtlUnicodeToMultiByteN(AddressString, RTLIPV6A2SEX_MAX_LEN, NULL, Buffer,
(wcslen(Buffer) + 1) * sizeof(WCHAR));
+ if (!NT_SUCCESS(Status))
+ return STATUS_INVALID_PARAMETER;
+
+ return STATUS_SUCCESS;
+}
+
+/*
+* @implemented
*/
PWSTR
NTAPI
RtlIpv6AddressToStringW(
_In_ const struct in6_addr *Addr,
- _Out_writes_(46) PWSTR S)
-{
- UNIMPLEMENTED;
- return NULL;
-}
-
-/*
-* @unimplemented
+ _Out_writes_(RTLIPV6A2S_MAX_LEN) PWSTR S)
+{
+ NTSTATUS Status;
+ UINT Parts = 8, n;
+ BOOLEAN SkipOnce = TRUE;
+ PWSTR End;
+ size_t Remaining;
+
+ if (!S)
+ return (PWSTR)~0;
+
+ Remaining = RTLIPV6A2S_MAX_LEN;
+ /* does it look like an ipv4 address contained in an ipv6?
http://tools.ietf.org/html/rfc2765 */
+ if (!Addr->s6_words[0] && !Addr->s6_words[1] &&
!Addr->s6_words[2] && !Addr->s6_words[3] && Addr->s6_words[6])
+ {
+ PWSTR Prefix = NULL;
+ if (Addr->s6_words[4] == 0xffff && !Addr->s6_words[5])
+ Prefix = L"ffff:0:";
+ else if (!Addr->s6_words[4] && Addr->s6_words[5] == 0xffff)
+ Prefix = L"ffff:";
+ else if (!Addr->s6_words[4] && !Addr->s6_words[5])
+ Prefix = L"";
+ if (Prefix != NULL)
+ {
+ Status = RtlStringCchPrintfExW(S,
+ Remaining,
+ &End,
+ NULL,
+ 0,
+ L"::%ls%u.%u.%u.%u",
+ Prefix,
+ Addr->s6_bytes[12],
+ Addr->s6_bytes[13],
+ Addr->s6_bytes[14],
+ Addr->s6_bytes[15]);
+ ASSERT(Status == STATUS_SUCCESS);
+ if (!NT_SUCCESS(Status))
+ return (PWSTR)~0;
+ return End;
+ }
+ }
+
+ /* does it look like an ISATAP address?
http://tools.ietf.org/html/rfc5214 */
+ if (!(Addr->s6_words[4] & 0xfffd) && Addr->s6_words[5] == 0xfe5e)
+ Parts = 6;
+
+ for (n = 0; n < Parts; ++n)
+ {
+ if (SkipOnce && ((n + 1) < Parts) && !Addr->s6_words[n]
&& !Addr->s6_words[n + 1])
+ {
+ SkipOnce = FALSE;
+ while (!Addr->s6_words[n + 1] && (n + 1) < Parts)
+ ++n;
+ *S++ = ':';
+ Remaining--;
+ if ((n + 1) >= Parts)
+ {
+ *S++ = ':';
+ Remaining--;
+ }
+ }
+ else
+ {
+ if (n)
+ {
+ *S++ = ':';
+ Remaining--;
+ }
+ Status = RtlStringCchPrintfExW(S,
+ Remaining,
+ &End,
+ &Remaining,
+ 0,
+ L"%x",
+ WN2H(Addr->s6_words[n]));
+ ASSERT(Status == STATUS_SUCCESS);
+ if (!NT_SUCCESS(Status))
+ return (PWSTR)~0;
+ S = End;
+ }
+ }
+ if (Parts < 8)
+ {
+ Status = RtlStringCchPrintfExW(S,
+ Remaining,
+ &End,
+ NULL,
+ 0,
+ L":%u.%u.%u.%u",
+ Addr->s6_bytes[12],
+ Addr->s6_bytes[13],
+ Addr->s6_bytes[14],
+ Addr->s6_bytes[15]);
+ ASSERT(Status == STATUS_SUCCESS);
+ if (!NT_SUCCESS(Status))
+ return (PWSTR)~0;
+
+ return End;
+ }
+ *S = UNICODE_NULL;
+ return S;
+}
+
+/*
+* @implemented
*/
NTSTATUS
NTAPI
@@ -496,8 +630,68 @@
_Out_writes_to_(*AddressStringLength, *AddressStringLength) PWCHAR AddressString,
_Inout_ PULONG AddressStringLength)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ WCHAR Buffer[RTLIPV6A2SEX_MAX_LEN];
+ PWCHAR S = Buffer;
+ NTSTATUS Status;
+ ULONG Length;
+ size_t Remaining;
+
+ if (!Address || !AddressString || !AddressStringLength)
+ return STATUS_INVALID_PARAMETER;
+
+ if (Port)
+ *S++ = L'[';
+
+ S = RtlIpv6AddressToStringW(Address, S);
+ ASSERT(S != (PCWSTR)~0);
+ if (S == (PCWSTR)~0)
+ return STATUS_INVALID_PARAMETER;
+
+ ASSERT(S >= Buffer);
+ ASSERT(S <= Buffer + RTLIPV6A2S_MAX_LEN + 1);
+ Remaining = RTL_NUMBER_OF(Buffer) - (S - Buffer);
+ ASSERT(Remaining >= RTLIPV6A2SEX_MAX_LEN - RTLIPV6A2S_MAX_LEN);
+
+ if (ScopeId)
+ {
+ Status = RtlStringCchPrintfExW(S,
+ Remaining,
+ &S,
+ &Remaining,
+ 0,
+ L"%%%u",
+ ScopeId);
+ ASSERT(Status == STATUS_SUCCESS);
+ if (!NT_SUCCESS(Status))
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Port)
+ {
+ Status = RtlStringCchPrintfExW(S,
+ Remaining,
+ &S,
+ &Remaining,
+ 0,
+ L"]:%u",
+ WN2H(Port));
+ ASSERT(Status == STATUS_SUCCESS);
+ if (!NT_SUCCESS(Status))
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ Length = S - Buffer;
+ ASSERT(Buffer[Length] == UNICODE_NULL);
+ if (*AddressStringLength > Length)
+ {
+ Status = RtlStringCchCopyW(AddressString, *AddressStringLength, Buffer);
+ ASSERT(Status == STATUS_SUCCESS);
+ *AddressStringLength = Length + 1;
+ return STATUS_SUCCESS;
+ }
+
+ *AddressStringLength = Length + 1;
+ return STATUS_INVALID_PARAMETER;
}
/*