win32u: Respect per-monitor thread dpi awareness when getting window from point.
[wine.git] / dlls / winhttp / net.c
blobe46f2023fae8fe51d37096bc826bdd87488875f8
1 /*
2 * Copyright 2008 Hans Leidekker for CodeWeavers
3 * Copyright 2013 Jacek Caban for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <assert.h>
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "ws2tcpip.h"
26 #include "winhttp.h"
27 #include "schannel.h"
28 #include "winternl.h"
30 #include "wine/debug.h"
31 #include "winhttp_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
35 static int sock_send(int fd, const void *msg, size_t len, WSAOVERLAPPED *ovr)
37 WSABUF wsabuf;
38 DWORD size;
39 int err;
41 wsabuf.len = len;
42 wsabuf.buf = (void *)msg;
44 if (!WSASend( (SOCKET)fd, &wsabuf, 1, &size, 0, ovr, NULL ))
46 assert( size == len );
47 return size;
49 err = WSAGetLastError();
50 if (!(ovr && err == WSA_IO_PENDING)) WARN( "send error %d\n", err );
51 return -1;
54 BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, DWORD *len )
56 OVERLAPPED *completion_ovr;
57 ULONG_PTR key;
59 while (1)
61 if (!GetQueuedCompletionStatus( conn->port, len, &key, &completion_ovr, INFINITE ))
63 WARN( "GetQueuedCompletionStatus failed, err %lu.\n", GetLastError() );
64 return FALSE;
66 if (completion_ovr == (OVERLAPPED *)ovr && (key == conn->socket || conn->socket == -1))
67 break;
68 ERR( "Unexpected completion key %Ix, completion ovr %p, ovr %p.\n", key, completion_ovr, ovr );
70 return TRUE;
73 static int sock_recv(int fd, void *msg, size_t len, int flags)
75 int ret;
78 if ((ret = recv(fd, msg, len, flags)) == -1) WARN( "recv error %d\n", WSAGetLastError() );
80 while(ret == -1 && WSAGetLastError() == WSAEINTR);
81 return ret;
84 static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, WCHAR *server, DWORD security_flags, BOOL check_revocation )
86 HCERTSTORE store = cert->hCertStore;
87 BOOL ret;
88 CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
89 PCCERT_CHAIN_CONTEXT chain;
90 char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
91 char *server_auth[] = { oid_server_auth };
92 DWORD err = ERROR_SUCCESS;
94 TRACE("verifying %s\n", debugstr_w( server ));
95 chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
96 chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
97 ret = CertGetCertificateChain( NULL, cert, NULL, store, &chainPara,
98 check_revocation ? CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT : 0,
99 NULL, &chain );
100 if (ret)
102 if (chain->TrustStatus.dwErrorStatus)
104 static const DWORD supportedErrors =
105 CERT_TRUST_IS_NOT_TIME_VALID |
106 CERT_TRUST_IS_UNTRUSTED_ROOT |
107 CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
109 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
111 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
112 err = ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
114 else if ((chain->TrustStatus.dwErrorStatus &
115 CERT_TRUST_IS_UNTRUSTED_ROOT) ||
116 (chain->TrustStatus.dwErrorStatus &
117 CERT_TRUST_IS_PARTIAL_CHAIN))
119 if (!(security_flags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
120 err = ERROR_WINHTTP_SECURE_INVALID_CA;
122 else if ((chain->TrustStatus.dwErrorStatus &
123 CERT_TRUST_IS_OFFLINE_REVOCATION) ||
124 (chain->TrustStatus.dwErrorStatus &
125 CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
126 err = ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
127 else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
128 err = ERROR_WINHTTP_SECURE_CERT_REVOKED;
129 else if (chain->TrustStatus.dwErrorStatus &
130 CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
132 if (!(security_flags & SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE))
133 err = ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
135 else if (chain->TrustStatus.dwErrorStatus & ~supportedErrors)
136 err = ERROR_WINHTTP_SECURE_INVALID_CERT;
138 if (!err)
140 CERT_CHAIN_POLICY_PARA policyPara;
141 SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
142 CERT_CHAIN_POLICY_STATUS policyStatus;
143 CERT_CHAIN_CONTEXT chainCopy;
145 /* Clear chain->TrustStatus.dwErrorStatus so
146 * CertVerifyCertificateChainPolicy will verify additional checks
147 * rather than stopping with an existing, ignored error.
149 memcpy(&chainCopy, chain, sizeof(chainCopy));
150 chainCopy.TrustStatus.dwErrorStatus = 0;
151 sslExtraPolicyPara.cbSize = sizeof(sslExtraPolicyPara);
152 sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
153 sslExtraPolicyPara.pwszServerName = server;
154 sslExtraPolicyPara.fdwChecks = security_flags;
155 policyPara.cbSize = sizeof(policyPara);
156 policyPara.dwFlags = 0;
157 policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
158 ret = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
159 &chainCopy, &policyPara,
160 &policyStatus );
161 /* Any error in the policy status indicates that the
162 * policy couldn't be verified.
164 if (ret && policyStatus.dwError)
166 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
167 err = ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
168 else
169 err = ERROR_WINHTTP_SECURE_INVALID_CERT;
172 CertFreeCertificateChain( chain );
174 else
175 err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
176 TRACE( "returning %#lx\n", err );
177 return err;
180 static BOOL winsock_loaded;
182 void netconn_unload( void )
184 if (winsock_loaded) WSACleanup();
187 static BOOL WINAPI winsock_startup( INIT_ONCE *once, void *param, void **ctx )
189 int ret;
190 WSADATA data;
191 if (!(ret = WSAStartup( MAKEWORD(1,1), &data ))) winsock_loaded = TRUE;
192 else ERR( "WSAStartup failed: %d\n", ret );
193 return TRUE;
196 static void winsock_init(void)
198 static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
199 InitOnceExecuteOnce( &once, winsock_startup, NULL, NULL );
202 static void set_blocking( struct netconn *conn, BOOL blocking )
204 ULONG state = !blocking;
205 ioctlsocket( conn->socket, FIONBIO, &state );
208 DWORD netconn_create( struct hostdata *host, const struct sockaddr_storage *sockaddr, int timeout,
209 struct netconn **ret_conn )
211 struct netconn *conn;
212 unsigned int addr_len;
213 DWORD ret;
215 winsock_init();
217 if (!(conn = calloc( 1, sizeof(*conn) ))) return ERROR_OUTOFMEMORY;
218 conn->refs = 1;
219 conn->host = host;
220 conn->sockaddr = *sockaddr;
221 if ((conn->socket = WSASocketW( sockaddr->ss_family, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED )) == -1)
223 ret = WSAGetLastError();
224 WARN( "unable to create socket (%lu)\n", ret );
225 free( conn );
226 return ret;
228 if (!SetFileCompletionNotificationModes( (HANDLE)(UINT_PTR)conn->socket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS ))
229 ERR( "SetFileCompletionNotificationModes failed.\n" );
231 switch (conn->sockaddr.ss_family)
233 case AF_INET:
234 addr_len = sizeof(struct sockaddr_in);
235 break;
236 case AF_INET6:
237 addr_len = sizeof(struct sockaddr_in6);
238 break;
239 default:
240 ERR( "unhandled family %u\n", conn->sockaddr.ss_family );
241 free( conn );
242 return ERROR_INVALID_PARAMETER;
245 if (timeout > 0) set_blocking( conn, FALSE );
247 if (!connect( conn->socket, (const struct sockaddr *)&conn->sockaddr, addr_len )) ret = ERROR_SUCCESS;
248 else
250 ret = WSAGetLastError();
251 if (ret == WSAEWOULDBLOCK || ret == WSAEINPROGRESS)
253 TIMEVAL timeval = { timeout / 1000, (timeout % 1000) * 1000 };
254 FD_SET set_read, set_error;
255 int res;
257 FD_ZERO( &set_read );
258 FD_SET( conn->socket, &set_read );
259 FD_ZERO( &set_error );
260 FD_SET( conn->socket, &set_error );
261 if ((res = select( conn->socket + 1, NULL, &set_read, &set_error, &timeval )) > 0)
263 if (FD_ISSET(conn->socket, &set_read)) ret = ERROR_SUCCESS;
264 else assert( FD_ISSET(conn->socket, &set_error) );
266 else if (!res) ret = ERROR_WINHTTP_TIMEOUT;
270 if (timeout > 0) set_blocking( conn, TRUE );
272 if (ret)
274 WARN( "unable to connect to host (%lu)\n", ret );
275 closesocket( conn->socket );
276 free( conn );
277 return ret == ERROR_WINHTTP_TIMEOUT ? ERROR_WINHTTP_TIMEOUT : ERROR_WINHTTP_CANNOT_CONNECT;
280 *ret_conn = conn;
281 return ERROR_SUCCESS;
284 void netconn_addref( struct netconn *conn )
286 InterlockedIncrement( &conn->refs );
289 void netconn_release( struct netconn *conn )
291 if (InterlockedDecrement( &conn->refs )) return;
292 TRACE( "Closing connection %p.\n", conn );
293 if (conn->secure)
295 free( conn->peek_msg_mem );
296 free(conn->ssl_read_buf);
297 free(conn->ssl_write_buf);
298 free(conn->extra_buf);
299 DeleteSecurityContext(&conn->ssl_ctx);
301 if (conn->socket != -1)
302 closesocket( conn->socket );
303 release_host( conn->host );
304 if (conn->port)
305 CloseHandle( conn->port );
306 free(conn);
309 DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle,
310 BOOL check_revocation )
312 SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}};
313 SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs};
314 BYTE *read_buf;
315 SIZE_T read_buf_size = 2048;
316 ULONG attrs = 0;
317 CtxtHandle ctx;
318 SSIZE_T size;
319 const CERT_CONTEXT *cert;
320 SECURITY_STATUS status;
321 DWORD res = ERROR_SUCCESS;
323 const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY
324 |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION;
326 if (!(read_buf = malloc( read_buf_size ))) return ERROR_OUTOFMEMORY;
328 memset( &ctx, 0, sizeof(ctx) );
329 status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0,
330 &ctx, &out_desc, &attrs, NULL);
332 assert(status != SEC_E_OK);
334 while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) {
335 if(out_buf.cbBuffer) {
336 assert(status == SEC_I_CONTINUE_NEEDED);
338 TRACE( "sending %lu bytes\n", out_buf.cbBuffer );
340 size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, NULL);
341 if(size != out_buf.cbBuffer) {
342 ERR("send failed\n");
343 res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
344 break;
347 FreeContextBuffer(out_buf.pvBuffer);
348 out_buf.pvBuffer = NULL;
349 out_buf.cbBuffer = 0;
352 if(status == SEC_I_CONTINUE_NEEDED) {
353 assert(in_bufs[1].cbBuffer < read_buf_size);
355 memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer);
356 in_bufs[0].cbBuffer = in_bufs[1].cbBuffer;
359 assert(in_bufs[0].BufferType == SECBUFFER_TOKEN);
360 in_bufs[1].BufferType = SECBUFFER_EMPTY;
361 in_bufs[1].cbBuffer = 0;
362 in_bufs[1].pvBuffer = NULL;
364 if(in_bufs[0].cbBuffer + 1024 > read_buf_size) {
365 BYTE *new_read_buf;
367 new_read_buf = realloc(read_buf, read_buf_size + 1024);
368 if(!new_read_buf) {
369 status = E_OUTOFMEMORY;
370 break;
373 in_bufs[0].pvBuffer = read_buf = new_read_buf;
374 read_buf_size += 1024;
377 size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0);
378 if(size < 1) {
379 status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
380 break;
383 TRACE( "recv %Iu bytes\n", size );
385 in_bufs[0].cbBuffer += size;
386 in_bufs[0].pvBuffer = read_buf;
387 status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc,
388 0, NULL, &out_desc, &attrs, NULL);
389 TRACE( "InitializeSecurityContext ret %#lx\n", status );
391 if(status == SEC_E_OK) {
392 if(in_bufs[1].BufferType == SECBUFFER_EXTRA)
393 FIXME("SECBUFFER_EXTRA not supported\n");
395 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes);
396 if(status != SEC_E_OK) {
397 WARN("Could not get sizes\n");
398 break;
401 status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
402 if(status == SEC_E_OK) {
403 res = netconn_verify_cert(cert, hostname, security_flags, check_revocation);
404 CertFreeCertificateContext(cert);
405 if(res != ERROR_SUCCESS) {
406 WARN( "cert verify failed: %lu\n", res );
407 break;
409 }else {
410 WARN("Could not get cert\n");
411 break;
414 conn->ssl_read_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
415 if(!conn->ssl_read_buf) {
416 res = ERROR_OUTOFMEMORY;
417 break;
419 conn->ssl_write_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
420 if(!conn->ssl_write_buf) {
421 res = ERROR_OUTOFMEMORY;
422 break;
427 free(read_buf);
429 if(status != SEC_E_OK || res != ERROR_SUCCESS) {
430 WARN( "Failed to initialize security context: %#lx\n", status );
431 free(conn->ssl_read_buf);
432 conn->ssl_read_buf = NULL;
433 free(conn->ssl_write_buf);
434 conn->ssl_write_buf = NULL;
435 DeleteSecurityContext(&ctx);
436 return ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
440 TRACE("established SSL connection\n");
441 conn->secure = TRUE;
442 conn->ssl_ctx = ctx;
443 return ERROR_SUCCESS;
446 static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size, WSAOVERLAPPED *ovr )
448 SecBuffer bufs[4] = {
449 {conn->ssl_sizes.cbHeader, SECBUFFER_STREAM_HEADER, conn->ssl_write_buf},
450 {size, SECBUFFER_DATA, conn->ssl_write_buf+conn->ssl_sizes.cbHeader},
451 {conn->ssl_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, conn->ssl_write_buf+conn->ssl_sizes.cbHeader+size},
452 {0, SECBUFFER_EMPTY, NULL}
454 SecBufferDesc buf_desc = {SECBUFFER_VERSION, ARRAY_SIZE(bufs), bufs};
455 SECURITY_STATUS res;
457 memcpy( bufs[1].pvBuffer, msg, size );
458 if ((res = EncryptMessage(&conn->ssl_ctx, 0, &buf_desc, 0)) != SEC_E_OK)
460 WARN( "EncryptMessage failed: %#lx\n", res );
461 return res;
464 if (sock_send( conn->socket, conn->ssl_write_buf, bufs[0].cbBuffer + bufs[1].cbBuffer + bufs[2].cbBuffer, ovr ) < 1)
466 WARN("send failed\n");
467 return WSAGetLastError();
470 return ERROR_SUCCESS;
473 DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent, WSAOVERLAPPED *ovr )
475 DWORD err;
477 if (ovr && !conn->port)
479 if (!(conn->port = CreateIoCompletionPort( (HANDLE)(SOCKET)conn->socket, NULL, (ULONG_PTR)conn->socket, 0 )))
480 ERR( "Failed to create port.\n" );
483 if (conn->secure)
485 const BYTE *ptr = msg;
486 size_t chunk_size;
487 DWORD res;
489 *sent = 0;
490 while (len)
492 chunk_size = min( len, conn->ssl_sizes.cbMaximumMessage );
493 if ((res = send_ssl_chunk( conn, ptr, chunk_size, ovr )))
495 if (res == WSA_IO_PENDING) *sent += chunk_size;
496 return res;
498 *sent += chunk_size;
499 ptr += chunk_size;
500 len -= chunk_size;
503 return ERROR_SUCCESS;
506 if ((*sent = sock_send( conn->socket, msg, len, ovr )) < 0)
508 err = WSAGetLastError();
509 *sent = (err == WSA_IO_PENDING) ? len : 0;
510 return err;
512 return ERROR_SUCCESS;
515 static DWORD read_ssl_chunk( struct netconn *conn, void *buf, SIZE_T buf_size, SIZE_T *ret_size, BOOL *eof )
517 const SIZE_T ssl_buf_size = conn->ssl_sizes.cbHeader+conn->ssl_sizes.cbMaximumMessage+conn->ssl_sizes.cbTrailer;
518 SecBuffer bufs[4];
519 SecBufferDesc buf_desc = {SECBUFFER_VERSION, ARRAY_SIZE(bufs), bufs};
520 SSIZE_T size, buf_len;
521 unsigned int i;
522 SECURITY_STATUS res;
524 assert(conn->extra_len < ssl_buf_size);
526 if(conn->extra_len) {
527 memcpy(conn->ssl_read_buf, conn->extra_buf, conn->extra_len);
528 buf_len = conn->extra_len;
529 conn->extra_len = 0;
530 free(conn->extra_buf);
531 conn->extra_buf = NULL;
532 }else {
533 if ((buf_len = sock_recv( conn->socket, conn->ssl_read_buf + conn->extra_len, ssl_buf_size - conn->extra_len, 0)) < 0)
534 return WSAGetLastError();
536 if (!buf_len)
538 *eof = TRUE;
539 return ERROR_SUCCESS;
543 *ret_size = 0;
544 *eof = FALSE;
546 do {
547 memset(bufs, 0, sizeof(bufs));
548 bufs[0].BufferType = SECBUFFER_DATA;
549 bufs[0].cbBuffer = buf_len;
550 bufs[0].pvBuffer = conn->ssl_read_buf;
552 switch ((res = DecryptMessage( &conn->ssl_ctx, &buf_desc, 0, NULL )))
554 case SEC_E_OK:
555 break;
557 case SEC_I_RENEGOTIATE:
558 TRACE("renegotiate\n");
559 return ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED;
561 case SEC_I_CONTEXT_EXPIRED:
562 TRACE("context expired\n");
563 *eof = TRUE;
564 return ERROR_SUCCESS;
566 case SEC_E_INCOMPLETE_MESSAGE:
567 assert(buf_len < ssl_buf_size);
569 if ((size = sock_recv( conn->socket, conn->ssl_read_buf + buf_len, ssl_buf_size - buf_len, 0 )) < 1)
570 return SEC_E_INCOMPLETE_MESSAGE;
572 buf_len += size;
573 continue;
575 default:
576 WARN( "failed: %#lx\n", res );
577 return res;
579 } while (res != SEC_E_OK);
581 for(i = 0; i < ARRAY_SIZE(bufs); i++) {
582 if(bufs[i].BufferType == SECBUFFER_DATA) {
583 size = min(buf_size, bufs[i].cbBuffer);
584 memcpy(buf, bufs[i].pvBuffer, size);
585 if(size < bufs[i].cbBuffer) {
586 assert(!conn->peek_len);
587 conn->peek_msg_mem = conn->peek_msg = malloc(bufs[i].cbBuffer - size);
588 if(!conn->peek_msg)
589 return ERROR_OUTOFMEMORY;
590 conn->peek_len = bufs[i].cbBuffer-size;
591 memcpy(conn->peek_msg, (char*)bufs[i].pvBuffer+size, conn->peek_len);
594 *ret_size = size;
598 for(i = 0; i < ARRAY_SIZE(bufs); i++) {
599 if(bufs[i].BufferType == SECBUFFER_EXTRA) {
600 conn->extra_buf = malloc(bufs[i].cbBuffer);
601 if(!conn->extra_buf)
602 return ERROR_OUTOFMEMORY;
604 conn->extra_len = bufs[i].cbBuffer;
605 memcpy(conn->extra_buf, bufs[i].pvBuffer, conn->extra_len);
609 return ERROR_SUCCESS;
612 DWORD netconn_recv( struct netconn *conn, void *buf, size_t len, int flags, int *recvd )
614 *recvd = 0;
615 if (!len) return ERROR_SUCCESS;
617 if (conn->secure)
619 SIZE_T size;
620 DWORD res;
621 BOOL eof;
623 if (conn->peek_msg)
625 *recvd = min( len, conn->peek_len );
626 memcpy( buf, conn->peek_msg, *recvd );
627 conn->peek_len -= *recvd;
628 conn->peek_msg += *recvd;
630 if (conn->peek_len == 0)
632 free( conn->peek_msg_mem );
633 conn->peek_msg_mem = NULL;
634 conn->peek_msg = NULL;
636 /* check if we have enough data from the peek buffer */
637 if (!(flags & MSG_WAITALL) || *recvd == len) return ERROR_SUCCESS;
639 size = *recvd;
643 SIZE_T cread = 0;
644 if ((res = read_ssl_chunk( conn, (BYTE *)buf + size, len - size, &cread, &eof )))
646 WARN( "read_ssl_chunk failed: %lu\n", res );
647 if (!size) return res;
648 break;
650 if (eof)
652 TRACE("EOF\n");
653 break;
655 size += cread;
657 } while (!size || ((flags & MSG_WAITALL) && size < len));
659 TRACE( "received %Iu bytes\n", size );
660 *recvd = size;
661 return ERROR_SUCCESS;
664 if ((*recvd = sock_recv( conn->socket, buf, len, flags )) < 0) return WSAGetLastError();
665 return ERROR_SUCCESS;
668 void netconn_cancel_io( struct netconn *conn )
670 SOCKET socket = InterlockedExchange( (LONG *)&conn->socket, -1 );
672 closesocket( socket );
675 ULONG netconn_query_data_available( struct netconn *conn )
677 return conn->secure ? conn->peek_len : 0;
680 DWORD netconn_set_timeout( struct netconn *netconn, BOOL send, int value )
682 int opt = send ? SO_SNDTIMEO : SO_RCVTIMEO;
683 if (setsockopt( netconn->socket, SOL_SOCKET, opt, (void *)&value, sizeof(value) ) == -1)
685 DWORD err = WSAGetLastError();
686 WARN( "setsockopt failed (%lu)\n", err );
687 return err;
689 return ERROR_SUCCESS;
692 BOOL netconn_is_alive( struct netconn *netconn )
694 SIZE_T size;
695 int len;
696 char b;
697 DWORD err;
698 BOOL eof;
700 set_blocking( netconn, FALSE );
701 if (netconn->secure)
703 while (!netconn->peek_msg && !(err = read_ssl_chunk( netconn, NULL, 0, &size, &eof )) && !eof)
706 TRACE( "checking secure connection, err %lu\n", err );
708 if (netconn->peek_msg || err == WSAEWOULDBLOCK)
710 set_blocking( netconn, TRUE );
711 return TRUE;
713 if (err != SEC_E_OK && err != SEC_E_INCOMPLETE_MESSAGE)
715 set_blocking( netconn, TRUE );
716 return FALSE;
719 len = sock_recv( netconn->socket, &b, 1, MSG_PEEK );
720 err = WSAGetLastError();
721 set_blocking( netconn, TRUE );
723 return len == 1 || (len == -1 && err == WSAEWOULDBLOCK);
726 static DWORD resolve_hostname( const WCHAR *name, INTERNET_PORT port, struct sockaddr_storage *sa )
728 ADDRINFOW *res, hints;
729 int ret;
731 memset( &hints, 0, sizeof(hints) );
732 /* Prefer IPv4 to IPv6 addresses, since some web servers do not listen on
733 * their IPv6 addresses even though they have IPv6 addresses in the DNS.
735 hints.ai_family = AF_INET;
737 ret = GetAddrInfoW( name, NULL, &hints, &res );
738 if (ret != 0)
740 TRACE("failed to get IPv4 address of %s, retrying with IPv6\n", debugstr_w(name));
741 hints.ai_family = AF_INET6;
742 ret = GetAddrInfoW( name, NULL, &hints, &res );
743 if (ret != 0)
745 TRACE("failed to get address of %s\n", debugstr_w(name));
746 return ERROR_WINHTTP_NAME_NOT_RESOLVED;
749 memcpy( sa, res->ai_addr, res->ai_addrlen );
750 switch (res->ai_family)
752 case AF_INET:
753 ((struct sockaddr_in *)sa)->sin_port = htons( port );
754 break;
755 case AF_INET6:
756 ((struct sockaddr_in6 *)sa)->sin6_port = htons( port );
757 break;
760 FreeAddrInfoW( res );
761 return ERROR_SUCCESS;
764 struct async_resolve
766 LONG ref;
767 WCHAR *hostname;
768 INTERNET_PORT port;
769 struct sockaddr_storage addr;
770 DWORD result;
771 HANDLE done;
774 static struct async_resolve *create_async_resolve( const WCHAR *hostname, INTERNET_PORT port )
776 struct async_resolve *ret;
778 if (!(ret = malloc(sizeof(*ret))))
780 ERR( "No memory.\n" );
781 return NULL;
783 ret->ref = 1;
784 ret->hostname = wcsdup( hostname );
785 ret->port = port;
786 if (!(ret->done = CreateEventW( NULL, FALSE, FALSE, NULL )))
788 free( ret->hostname );
789 free( ret );
790 return NULL;
792 return ret;
795 static void async_resolve_release( struct async_resolve *async )
797 if (InterlockedDecrement( &async->ref )) return;
799 free( async->hostname );
800 CloseHandle( async->done );
801 free( async );
804 static void CALLBACK resolve_proc( TP_CALLBACK_INSTANCE *instance, void *ctx )
806 struct async_resolve *async = ctx;
808 async->result = resolve_hostname( async->hostname, async->port, &async->addr );
809 SetEvent( async->done );
810 async_resolve_release( async );
813 DWORD netconn_resolve( WCHAR *hostname, INTERNET_PORT port, struct sockaddr_storage *addr, int timeout )
815 DWORD ret;
817 if (!timeout) ret = resolve_hostname( hostname, port, addr );
818 else
820 struct async_resolve *async;
822 if (!(async = create_async_resolve( hostname, port )))
823 return ERROR_OUTOFMEMORY;
825 InterlockedIncrement( &async->ref );
826 if (!TrySubmitThreadpoolCallback( resolve_proc, async, NULL ))
828 InterlockedDecrement( &async->ref );
829 async_resolve_release( async );
830 return GetLastError();
832 if (WaitForSingleObject( async->done, timeout ) != WAIT_OBJECT_0) ret = ERROR_WINHTTP_TIMEOUT;
833 else
835 *addr = async->addr;
836 ret = async->result;
838 async_resolve_release( async );
841 return ret;
844 const void *netconn_get_certificate( struct netconn *conn )
846 const CERT_CONTEXT *ret;
847 SECURITY_STATUS res;
849 if (!conn->secure) return NULL;
850 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&ret);
851 return res == SEC_E_OK ? ret : NULL;
854 int netconn_get_cipher_strength( struct netconn *conn )
856 SecPkgContext_ConnectionInfo conn_info;
857 SECURITY_STATUS res;
859 if (!conn->secure) return 0;
860 res = QueryContextAttributesW(&conn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info);
861 if(res != SEC_E_OK)
862 WARN( "QueryContextAttributesW failed: %#lx\n", res );
863 return res == SEC_E_OK ? conn_info.dwCipherStrength : 0;