📄 net.c
字号:
if( pWinHttpGetDefaultProxyConfiguration != NULL && \
pWinHttpGetDefaultProxyConfiguration( &proxyInfo ) && \
proxyInfo.lpszProxy != NULL )
{
count = wcstombs( proxy, proxyInfo.lpszProxy, MAX_DNS_SIZE );
GlobalFree( proxyInfo.lpszProxy );
if( proxyInfo.lpszProxyBypass != NULL )
GlobalFree( proxyInfo.lpszProxy );
}
/* The next fallback is to get the proxy info from MSIE. This is also
usually much quicker than WinHttpGetProxyForUrl(), although sometimes
it seems to fall back to that, based on the longish delay involved.
Another issue with this is that it won't work in a service process
that isn't impersonating an interactive user (since there isn't a
current user), but in that case we just fall back to
WinHttpGetProxyForUrl() */
if( pWinHttpGetIEProxyConfigForCurrentUser != NULL && \
pWinHttpGetIEProxyConfigForCurrentUser( &ieProxyInfo ) )
{
count = wcstombs( proxy, ieProxyInfo.lpszProxy, MAX_DNS_SIZE );
if( ieProxyInfo.lpszAutoConfigUrl != NULL )
GlobalFree( ieProxyInfo.lpszAutoConfigUrl );
if( ieProxyInfo.lpszProxy != NULL )
GlobalFree( ieProxyInfo.lpszProxy );
if( ieProxyInfo.lpszProxyBypass != NULL )
GlobalFree( ieProxyInfo.lpszProxyBypass );
if( count > 0 )
{
proxy[ count ] = '\0';
return( CRYPT_OK );
}
}
/* WinHttpGetProxyForUrl() requires a schema for the URL that it's
performing a lookup on, if the URL doesn't contain one we use a
default value of "http://" */
if( strstr( url, "://" ) == NULL )
{
strcpy( urlBuffer, "http://" );
offset = 7;
}
memcpy( urlBuffer + offset, url, min( urlLen, MAX_DNS_SIZE - offset ) );
urlBuffer[ offset + min( urlLen, MAX_DNS_SIZE - offset ) ] = '\0';
/* Locate the proxy used for accessing the resource at the supplied URL.
We have to convert to and from Unicode because the WinHTTP functions
all take Unicode strings as args. Note that we use the libc widechar
functions rather than the Windows ones since the latter aren't
present in Win95 or Win98.
WinHttpGetProxyForUrl() can be rather flaky, in some cases it'll fail
instantly (without even trying auto-discovery) with GetLastError() =
87 (parameter error), but then calling it again some time later works
fine. Because of this we leave it as the last resort after trying
all the other get-proxy mechanisms */
hSession = pWinHttpOpen( L"cryptlib/1.0",
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0 );
if( hSession == NULL )
return( CRYPT_ERROR_NOTFOUND );
count = mbstowcs( unicodeURL, urlBuffer, MAX_DNS_SIZE );
if( count <= 0 )
{
pWinHttpCloseHandle( hSession );
return( CRYPT_ERROR_NOTFOUND );
}
unicodeURL[ count ] = L'\0';
count = 0;
memset( &proxyInfo, 0, sizeof( WINHTTP_PROXY_INFO ) );
if( pWinHttpGetProxyForUrl( hSession, unicodeURL, &autoProxyOptions,
&proxyInfo ) == TRUE )
{
count = wcstombs( proxy, proxyInfo.lpszProxy, MAX_DNS_SIZE );
GlobalFree( proxyInfo.lpszProxy );
if( proxyInfo.lpszProxyBypass != NULL )
GlobalFree( proxyInfo.lpszProxy );
}
pWinHttpCloseHandle( hSession );
if( count <= 0 )
return( CRYPT_ERROR_NOTFOUND );
proxy[ count ] = '\0';
return( CRYPT_OK );
}
#if 0
typedef BOOL ( WINAPI *INTERNETGETPROXYINFO )( LPCSTR lpszUrl, DWORD dwUrlLength,
LPSTR lpszUrlHostName, DWORD dwUrlHostNameLength,
LPSTR* lplpszProxyHostName,
LPDWORD lpdwProxyHostNameLength );
typedef BOOL ( WINAPI *INTERNETINITIALIZEAUTOPROXYDLL )( DWORD dwVersion,
LPSTR lpszDownloadedTempFile, LPSTR lpszMime,
AutoProxyHelperFunctions* lpAutoProxyCallbacks,
LPAUTO_PROXY_SCRIPT_BUFFER lpAutoProxyScriptBuffer );
static int findProxyURL( char *proxy, const char *url )
{
static INTERNETGETPROXYINFO pInternetGetProxyInfo = NULL;
static INTERNETINITIALIZEAUTOPROXYDLL pInternetInitializeAutoProxyDll = NULL;
URL_INFO urlInfo;
char urlHost[ MAX_DNS_SIZE + 1 ];
char *proxyHost = NULL;
int proxyHostLen, status;
/* This gets somewhat complicated, under Win2K SP3, XP and 2003 (or at
least Windows versions with WinHTTP 5.1 installed in some way, it
officially shipped with the versions mentioned earlier) we can use
WinHTTP AutoProxy support, which implements the Web Proxy Auto-
Discovery (WPAD) protocol from an internet draft that expired in May
2001. Under older versions of Windows we have to use the WinINet
InternetGetProxyInfo.
These functions were never meant to be used by the general public
(see the comment below), so they work in an extremely peculiar way
and only with the exact calling sequence that's used by MS code - it
looks like they were only intended as components of Windows-internal
implementation of proxy support, since they require manual handling
of proxy config script downloading, parsing, and all manner of other
stuff that really doesn't concern us. Because of the extreme
difficulty in doing anything with these functions, we use the WinHTTP
approach instead */
if( pInternetGetProxyInfo == NULL )
{
HMODULE hModJS;
if( ( hModJS = LoadLibrary( "JSProxy.dll" ) ) == NULL )
return( CRYPT_ERROR_NOTFOUND );
pInternetGetProxyInfo = ( INTERNETGETPROXYINFO ) \
GetProcAddress( hModJS, "InternetGetProxyInfo" );
pInternetInitializeAutoProxyDll = ( INTERNETINITIALIZEAUTOPROXYDLL ) \
GetProcAddress( hModJS, "InternetInitializeAutoProxyDll" );
if( pInternetGetProxyInfo == NULL || \
pInternetInitializeAutoProxyDll == NULL )
{
FreeLibrary( hModJS );
return( CRYPT_ERROR_NOTFOUND );
}
pInternetInitializeAutoProxyDll( 0, TempFile, NULL,
&HelperFunctions, NULL )
}
/* InternetGetProxyInfo() is a somewhat screwball undocumented function
that was crowbarred out of MS as part of the DoJ consent decree. It
takes as input four parameters that do the work of a single
parameter, the null-terminated target URL string. The documentation
for the function was initially wrong, but has been partially
corrected in places after user complaints, there are still missing
parts, as well as possible errors (why is it necessary to specify a
length for a supposedly null-terminated string?). In order to meet
the strange input-parameter requirements, we have to pre-parse the
target URL in order to provide the various bits and pieces that
InternetGetProxyInfo() requires */
status = parseURL( &urlInfo, url, strlen( url ), 80 );
if( cryptStatusError( status ) )
return( status );
if( urlInfo.hostLen > MAX_DNS_SIZE )
return( CRYPT_ERROR_OVERFLOW );
memcpy( urlHost, urlInfo.host, urlInfo.hostLen );
urlHost[ urlInfo.hostLen ] = '\0';
if( !pInternetGetProxyInfo( url, strlen( url ), urlHost, urlInfo.hostLen,
&proxyHost, &proxyHostLen ) )
return( CRYPT_ERROR_NOTFOUND );
memcpy( proxy, proxyHost, proxyHostLen );
proxy[ proxyHostLen ] = '\0';
GlobalFree( proxyHost );
return( CRYPT_OK );
}
#endif
#else
#define findProxyURL( proxy, url ) CRYPT_ERROR_NOTFOUND
#endif /* __WIN32__ */
/****************************************************************************
* *
* Buffering Functions *
* *
****************************************************************************/
/* Buffered transport-layer read function. This sits on top of the
transport-layer read function and performs speculative read-ahead
buffering to improve performance in protocols such as HTTP that have to
read a byte at a time in places:
bPos bEnd
| |
v v
+-------+-----------+-------+
| |///////////| |
+-------+-----------+-------+
-- Read -->
We fill the buffer to bEnd, then empty it advancing bPos until there isn't
enough data left to satisfy the read, whereupon we move the data down and
refill from bEnd:
bPos bEnd
| |
v v
+-----------+---------------+
|///////////| |
+-----------+---------------+
-- Write --> */
static int bufferedTransportReadFunction( STREAM *stream, BYTE *buffer,
const int length, const int flags )
{
const int bytesLeft = stream->bufEnd - stream->bufPos;
int bytesToRead, status;
assert( isWritePtr( buffer, length ) );
assert( length > 0 );
assert( bytesLeft >= 0 );
/* If there's enough data in the buffer to satisfy the request, return it
directly */
if( length <= bytesLeft )
{
if( length == 1 )
/* Optimisation for HTTP header reads */
*buffer = stream->buffer[ stream->bufPos++ ];
else
{
memcpy( buffer, stream->buffer + stream->bufPos, length );
stream->bufPos += length;
}
assert( stream->bufPos <= stream->bufEnd );
return( length );
}
/* We're about to refill the buffer, if there's a gap at the start move
everything down to make room for the new data */
if( stream->bufPos > 0 )
{
if( bytesLeft > 0 )
memmove( stream->buffer, stream->buffer + stream->bufPos,
bytesLeft );
stream->bufEnd = bytesLeft;
stream->bufPos = 0;
}
assert( stream->bufPos == 0 );
assert( length > bytesLeft );
/* If there's more room in the buffer, refill it */
if( stream->bufEnd < stream->bufSize )
{
int bytesRead;
/* Perform an explicitly blocking read of as many bytes as we can/are
asked for. Since there may be data already present from an
earlier speculative read, we only read as much as we need to
fulfill the request */
bytesRead = stream->transportReadFunction( stream,
stream->buffer + stream->bufEnd,
min( length - bytesLeft, \
stream->bufSize - stream->bufEnd ),
TRANSPORT_FLAG_BLOCKING );
if( cryptStatusError( bytesRead ) )
return( bytesRead );
stream->bufEnd += bytesRead;
/* If there's room for more, perform a second, nonblocking read for
whatever might still be there. An error at this point isn't
fatal since this was only a speculative read */
if( stream->bufEnd < stream->bufSize )
{
bytesRead = stream->transportReadFunction( stream,
stream->buffer + stream->bufEnd,
stream->bufSize - stream->bufEnd,
TRANSPORT_FLAG_NONBLOCKING );
if( !cryptStatusError( bytesRead ) )
stream->bufEnd += bytesRead;
}
}
assert( stream->bufEnd <= stream->bufSize );
/* Read as much as we can from the buffer */
bytesToRead = min( length, stream->bufEnd );
memcpy( buffer, stream->buffer, bytesToRead );
stream->bufPos += bytesToRead;
assert( stream->bufPos <= stream->bufEnd );
/* If we could satisfy the read from the buffer, we're done */
if( length <= bytesToRead )
return( length );
/* We're drained the stream buffer and there's more to go, read it
directly into the caller's buffer */
status = stream->transportReadFunction( stream,
buffer + bytesToRead, length - bytesToRead,
TRANSPORT_FLAG_BLOCKING );
return( cryptStatusError( status ) ? status : status + bytesToRead );
}
/* Buffered transport-layer write function. This sits on top of the
transport-layer write function and combines two (or more, although in
practice only two ever occur) writes into a single write. The reason for
this is that when using TCP transport the delayed-ACK handling means
that performing two writes followed by a read (typical for HTTP and CMP
messages) leads to very poor performance, usually made even worse by TCP
slow-start.
The reason for this is that the TCP MSS is typically 1460 bytes on a LAN
(Ethernet) or 512/536 bytes on a WAN, while HTTP headers are ~200-300
bytes, far less than the MSS. When an HTTP message is first sent, the
TCP congestion window begins at one segment, with the TCP slow-start then
doubling its size for each ACK. Sending the headers separately will
send one short segment and a second MSS-size segment, whereupon the TCP
stack will wait for the responder's ACK before continuing. The responder
gets both segments, then delays its ACK for 200ms in the hopes of
piggybacking it on responder data, which is never sent since it's still
waiting for the rest of the HTTP body from the initiator. As a result,
this results in a 200ms (+ assorted RTT) delay in each message sent.
There is a somewhat related situation that occurs as a result of TCP
slow-start and that can't be avoided programmatically in which we can't
send more than a single request initially, however most BSD-derived
implementations set the server's congestion window to two segments in
response to receiving the TCP handshake ACK, so for the initial message
exchange the client can send a request of 1MSS and the server a response
of 2MSS without running into congestion-control problems.
A related problem is the fact that many TCP implementations will reset the
congestion window after one retransmission timeout period if all data sent
at that point has been acked, which means that both sides now restart with
a congestion window of size 1. Unfortunately there's nothing that can be
done about this, however hopefully at some point TCP implementations will
start to fall into line with RFC 3390 and allow initial windows of ~4K,
which will fix this particular problem */
static int bufferedTransportWriteFunction( STREAM *stream, const BYTE *buffer,
const int length, const int flags )
{
const BYTE *bufPtr = buffer;
int byteCount = length, status;
assert( isReadPtr( buffer, length ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -