server: Move socket async activation to sock_poll_event.
[wine] / dlls / wininet / netconnection.c
1 /*
2  * Wininet - networking layer. Uses unix sockets or OpenSSL.
3  *
4  * Copyright 2002 TransGaming Technologies Inc.
5  *
6  * David Hammerton
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #define NONAMELESSUNION
27
28 #if defined(__MINGW32__) || defined (_MSC_VER)
29 #include <ws2tcpip.h>
30 #endif
31
32 #include <sys/types.h>
33 #ifdef HAVE_POLL_H
34 #include <poll.h>
35 #endif
36 #ifdef HAVE_SYS_POLL_H
37 # include <sys/poll.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 #ifdef HAVE_SYS_SOCKET_H
43 # include <sys/socket.h>
44 #endif
45 #ifdef HAVE_SYS_FILIO_H
46 # include <sys/filio.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51 #ifdef HAVE_SYS_IOCTL_H
52 # include <sys/ioctl.h>
53 #endif
54 #include <time.h>
55 #ifdef HAVE_NETDB_H
56 # include <netdb.h>
57 #endif
58 #ifdef HAVE_NETINET_IN_H
59 # include <netinet/in.h>
60 #endif
61 #ifdef HAVE_OPENSSL_SSL_H
62 # include <openssl/ssl.h>
63 #undef FAR
64 #undef DSA
65 #endif
66
67 #include <stdarg.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <stdio.h>
71 #include <errno.h>
72
73 #include "wine/library.h"
74 #include "windef.h"
75 #include "winbase.h"
76 #include "wininet.h"
77 #include "winerror.h"
78 #include "wincrypt.h"
79
80 #include "wine/debug.h"
81 #include "internet.h"
82
83 /* To avoid conflicts with the Unix socket headers. we only need it for
84  * the error codes anyway. */
85 #define USE_WS_PREFIX
86 #include "winsock2.h"
87
88 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
89
90
91 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
92
93 /* FIXME!!!!!!
94  *    This should use winsock - To use winsock the functions will have to change a bit
95  *        as they are designed for unix sockets.
96  *    SSL stuff should use crypt32.dll
97  */
98
99 #ifdef SONAME_LIBSSL
100
101 #include <openssl/err.h>
102
103 static CRITICAL_SECTION init_ssl_cs;
104 static CRITICAL_SECTION_DEBUG init_ssl_cs_debug =
105 {
106     0, 0, &init_ssl_cs,
107     { &init_ssl_cs_debug.ProcessLocksList,
108       &init_ssl_cs_debug.ProcessLocksList },
109     0, 0, { (DWORD_PTR)(__FILE__ ": init_ssl_cs") }
110 };
111 static CRITICAL_SECTION init_ssl_cs = { &init_ssl_cs_debug, -1, 0, 0, 0, 0 };
112
113 static void *OpenSSL_ssl_handle;
114 static void *OpenSSL_crypto_handle;
115
116 static SSL_METHOD *meth;
117 static SSL_CTX *ctx;
118 static int hostname_idx;
119 static int error_idx;
120
121 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
122
123 /* OpenSSL functions that we use */
124 MAKE_FUNCPTR(SSL_library_init);
125 MAKE_FUNCPTR(SSL_load_error_strings);
126 MAKE_FUNCPTR(SSLv23_method);
127 MAKE_FUNCPTR(SSL_CTX_free);
128 MAKE_FUNCPTR(SSL_CTX_new);
129 MAKE_FUNCPTR(SSL_new);
130 MAKE_FUNCPTR(SSL_free);
131 MAKE_FUNCPTR(SSL_set_fd);
132 MAKE_FUNCPTR(SSL_connect);
133 MAKE_FUNCPTR(SSL_shutdown);
134 MAKE_FUNCPTR(SSL_write);
135 MAKE_FUNCPTR(SSL_read);
136 MAKE_FUNCPTR(SSL_pending);
137 MAKE_FUNCPTR(SSL_get_error);
138 MAKE_FUNCPTR(SSL_get_ex_new_index);
139 MAKE_FUNCPTR(SSL_get_ex_data);
140 MAKE_FUNCPTR(SSL_set_ex_data);
141 MAKE_FUNCPTR(SSL_get_ex_data_X509_STORE_CTX_idx);
142 MAKE_FUNCPTR(SSL_get_verify_result);
143 MAKE_FUNCPTR(SSL_get_peer_certificate);
144 MAKE_FUNCPTR(SSL_CTX_get_timeout);
145 MAKE_FUNCPTR(SSL_CTX_set_timeout);
146 MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths);
147 MAKE_FUNCPTR(SSL_CTX_set_verify);
148 MAKE_FUNCPTR(X509_STORE_CTX_get_ex_data);
149
150 /* OpenSSL's libcrypto functions that we use */
151 MAKE_FUNCPTR(BIO_new_fp);
152 MAKE_FUNCPTR(CRYPTO_num_locks);
153 MAKE_FUNCPTR(CRYPTO_set_id_callback);
154 MAKE_FUNCPTR(CRYPTO_set_locking_callback);
155 MAKE_FUNCPTR(ERR_free_strings);
156 MAKE_FUNCPTR(ERR_get_error);
157 MAKE_FUNCPTR(ERR_error_string);
158 MAKE_FUNCPTR(i2d_X509);
159 MAKE_FUNCPTR(sk_num);
160 MAKE_FUNCPTR(sk_value);
161 #undef MAKE_FUNCPTR
162
163 static CRITICAL_SECTION *ssl_locks;
164 static unsigned int num_ssl_locks;
165
166 static unsigned long ssl_thread_id(void)
167 {
168     return GetCurrentThreadId();
169 }
170
171 static void ssl_lock_callback(int mode, int type, const char *file, int line)
172 {
173     if (mode & CRYPTO_LOCK)
174         EnterCriticalSection(&ssl_locks[type]);
175     else
176         LeaveCriticalSection(&ssl_locks[type]);
177 }
178
179 static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
180 {
181     unsigned char* buffer,*p;
182     INT len;
183     BOOL malloced = FALSE;
184     PCCERT_CONTEXT ret;
185
186     p = NULL;
187     len = pi2d_X509(cert,&p);
188     /*
189      * SSL 0.9.7 and above malloc the buffer if it is null.
190      * however earlier version do not and so we would need to alloc the buffer.
191      *
192      * see the i2d_X509 man page for more details.
193      */
194     if (!p)
195     {
196         buffer = HeapAlloc(GetProcessHeap(),0,len);
197         p = buffer;
198         len = pi2d_X509(cert,&p);
199     }
200     else
201     {
202         buffer = p;
203         malloced = TRUE;
204     }
205
206     ret = CertCreateCertificateContext(X509_ASN_ENCODING,buffer,len);
207
208     if (malloced)
209         free(buffer);
210     else
211         HeapFree(GetProcessHeap(),0,buffer);
212
213     return ret;
214 }
215
216 static DWORD netconn_verify_cert(PCCERT_CONTEXT cert, HCERTSTORE store,
217     WCHAR *server)
218 {
219     BOOL ret;
220     CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
221     PCCERT_CHAIN_CONTEXT chain;
222     char oid_server_auth[] = szOID_PKIX_KP_SERVER_AUTH;
223     char *server_auth[] = { oid_server_auth };
224     DWORD err = ERROR_SUCCESS;
225
226     TRACE("verifying %s\n", debugstr_w(server));
227     chainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
228     chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = server_auth;
229     if ((ret = CertGetCertificateChain(NULL, cert, NULL, store, &chainPara, 0,
230         NULL, &chain)))
231     {
232         if (chain->TrustStatus.dwErrorStatus)
233         {
234             if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID)
235                 err = ERROR_INTERNET_SEC_CERT_DATE_INVALID;
236             else if (chain->TrustStatus.dwErrorStatus &
237                      CERT_TRUST_IS_UNTRUSTED_ROOT)
238                 err = ERROR_INTERNET_INVALID_CA;
239             else if ((chain->TrustStatus.dwErrorStatus &
240                       CERT_TRUST_IS_OFFLINE_REVOCATION) ||
241                      (chain->TrustStatus.dwErrorStatus &
242                       CERT_TRUST_REVOCATION_STATUS_UNKNOWN))
243                 err = ERROR_INTERNET_SEC_CERT_NO_REV;
244             else if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED)
245                 err = ERROR_INTERNET_SEC_CERT_REVOKED;
246             else if (chain->TrustStatus.dwErrorStatus &
247                 CERT_TRUST_IS_NOT_VALID_FOR_USAGE)
248                 err = ERROR_INTERNET_SEC_INVALID_CERT;
249             else
250                 err = ERROR_INTERNET_SEC_INVALID_CERT;
251         }
252         else
253         {
254             CERT_CHAIN_POLICY_PARA policyPara;
255             SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslExtraPolicyPara;
256             CERT_CHAIN_POLICY_STATUS policyStatus;
257
258             sslExtraPolicyPara.u.cbSize = sizeof(sslExtraPolicyPara);
259             sslExtraPolicyPara.dwAuthType = AUTHTYPE_SERVER;
260             sslExtraPolicyPara.pwszServerName = server;
261             policyPara.cbSize = sizeof(policyPara);
262             policyPara.dwFlags = 0;
263             policyPara.pvExtraPolicyPara = &sslExtraPolicyPara;
264             ret = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
265                 chain, &policyPara, &policyStatus);
266             /* Any error in the policy status indicates that the
267              * policy couldn't be verified.
268              */
269             if (ret && policyStatus.dwError)
270             {
271                 if (policyStatus.dwError == CERT_E_CN_NO_MATCH)
272                     err = ERROR_INTERNET_SEC_CERT_CN_INVALID;
273                 else
274                     err = ERROR_INTERNET_SEC_INVALID_CERT;
275             }
276         }
277         CertFreeCertificateChain(chain);
278     }
279     TRACE("returning %08x\n", err);
280     return err;
281 }
282
283 static int netconn_secure_verify(int preverify_ok, X509_STORE_CTX *ctx)
284 {
285     SSL *ssl;
286     WCHAR *server;
287     BOOL ret = FALSE;
288
289     ssl = pX509_STORE_CTX_get_ex_data(ctx,
290         pSSL_get_ex_data_X509_STORE_CTX_idx());
291     server = pSSL_get_ex_data(ssl, hostname_idx);
292     if (preverify_ok)
293     {
294         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
295             CERT_STORE_CREATE_NEW_FLAG, NULL);
296
297         if (store)
298         {
299             X509 *cert;
300             int i;
301             PCCERT_CONTEXT endCert = NULL;
302
303             ret = TRUE;
304             for (i = 0; ret && i < psk_num((struct stack_st *)ctx->chain); i++)
305             {
306                 PCCERT_CONTEXT context;
307
308                 cert = (X509 *)psk_value((struct stack_st *)ctx->chain, i);
309                 if ((context = X509_to_cert_context(cert)))
310                 {
311                     if (i == 0)
312                         ret = CertAddCertificateContextToStore(store, context,
313                             CERT_STORE_ADD_ALWAYS, &endCert);
314                     else
315                         ret = CertAddCertificateContextToStore(store, context,
316                             CERT_STORE_ADD_ALWAYS, NULL);
317                     CertFreeCertificateContext(context);
318                 }
319             }
320             if (!endCert) ret = FALSE;
321             if (ret)
322             {
323                 DWORD_PTR err = netconn_verify_cert(endCert, store, server);
324
325                 if (err)
326                 {
327                     pSSL_set_ex_data(ssl, error_idx, (void *)err);
328                     ret = FALSE;
329                 }
330             }
331             CertFreeCertificateContext(endCert);
332             CertCloseStore(store, 0);
333         }
334     }
335     return ret;
336 }
337
338 #endif
339
340 DWORD NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
341 {
342     connection->useSSL = FALSE;
343     connection->socketFD = -1;
344     if (useSSL)
345     {
346 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
347         int i;
348
349         TRACE("using SSL connection\n");
350         EnterCriticalSection(&init_ssl_cs);
351         if (OpenSSL_ssl_handle) /* already initialized everything */
352         {
353             LeaveCriticalSection(&init_ssl_cs);
354             return ERROR_SUCCESS;
355         }
356         OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0);
357         if (!OpenSSL_ssl_handle)
358         {
359             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
360                 SONAME_LIBSSL);
361             LeaveCriticalSection(&init_ssl_cs);
362             return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
363         }
364         OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
365         if (!OpenSSL_crypto_handle)
366         {
367             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
368                 SONAME_LIBCRYPTO);
369             LeaveCriticalSection(&init_ssl_cs);
370             return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
371         }
372
373         /* mmm nice ugly macroness */
374 #define DYNSSL(x) \
375     p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \
376     if (!p##x) \
377     { \
378         ERR("failed to load symbol %s\n", #x); \
379         LeaveCriticalSection(&init_ssl_cs); \
380         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \
381     }
382
383         DYNSSL(SSL_library_init);
384         DYNSSL(SSL_load_error_strings);
385         DYNSSL(SSLv23_method);
386         DYNSSL(SSL_CTX_free);
387         DYNSSL(SSL_CTX_new);
388         DYNSSL(SSL_new);
389         DYNSSL(SSL_free);
390         DYNSSL(SSL_set_fd);
391         DYNSSL(SSL_connect);
392         DYNSSL(SSL_shutdown);
393         DYNSSL(SSL_write);
394         DYNSSL(SSL_read);
395         DYNSSL(SSL_pending);
396         DYNSSL(SSL_get_error);
397         DYNSSL(SSL_get_ex_new_index);
398         DYNSSL(SSL_get_ex_data);
399         DYNSSL(SSL_set_ex_data);
400         DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx);
401         DYNSSL(SSL_get_verify_result);
402         DYNSSL(SSL_get_peer_certificate);
403         DYNSSL(SSL_CTX_get_timeout);
404         DYNSSL(SSL_CTX_set_timeout);
405         DYNSSL(SSL_CTX_set_default_verify_paths);
406         DYNSSL(SSL_CTX_set_verify);
407         DYNSSL(X509_STORE_CTX_get_ex_data);
408 #undef DYNSSL
409
410 #define DYNCRYPTO(x) \
411     p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \
412     if (!p##x) \
413     { \
414         ERR("failed to load symbol %s\n", #x); \
415         LeaveCriticalSection(&init_ssl_cs); \
416         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \
417     }
418         DYNCRYPTO(BIO_new_fp);
419         DYNCRYPTO(CRYPTO_num_locks);
420         DYNCRYPTO(CRYPTO_set_id_callback);
421         DYNCRYPTO(CRYPTO_set_locking_callback);
422         DYNCRYPTO(ERR_free_strings);
423         DYNCRYPTO(ERR_get_error);
424         DYNCRYPTO(ERR_error_string);
425         DYNCRYPTO(i2d_X509);
426         DYNCRYPTO(sk_num);
427         DYNCRYPTO(sk_value);
428 #undef DYNCRYPTO
429
430         pSSL_library_init();
431         pSSL_load_error_strings();
432         pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */
433
434         meth = pSSLv23_method();
435         ctx = pSSL_CTX_new(meth);
436         if (!pSSL_CTX_set_default_verify_paths(ctx))
437         {
438             ERR("SSL_CTX_set_default_verify_paths failed: %s\n",
439                 pERR_error_string(pERR_get_error(), 0));
440             LeaveCriticalSection(&init_ssl_cs);
441             return ERROR_OUTOFMEMORY;
442         }
443         hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index",
444                 NULL, NULL, NULL);
445         if (hostname_idx == -1)
446         {
447             ERR("SSL_get_ex_new_index failed; %s\n",
448                 pERR_error_string(pERR_get_error(), 0));
449             LeaveCriticalSection(&init_ssl_cs);
450             return ERROR_OUTOFMEMORY;
451         }
452         error_idx = pSSL_get_ex_new_index(0, (void *)"error index",
453                 NULL, NULL, NULL);
454         if (error_idx == -1)
455         {
456             ERR("SSL_get_ex_new_index failed; %s\n",
457                 pERR_error_string(pERR_get_error(), 0));
458             LeaveCriticalSection(&init_ssl_cs);
459             return ERROR_OUTOFMEMORY;
460         }
461         pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify);
462
463         pCRYPTO_set_id_callback(ssl_thread_id);
464         num_ssl_locks = pCRYPTO_num_locks();
465         ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION));
466         if (!ssl_locks)
467         {
468             LeaveCriticalSection(&init_ssl_cs);
469             return ERROR_OUTOFMEMORY;
470         }
471         for (i = 0; i < num_ssl_locks; i++)
472             InitializeCriticalSection(&ssl_locks[i]);
473         pCRYPTO_set_locking_callback(ssl_lock_callback);
474         LeaveCriticalSection(&init_ssl_cs);
475 #else
476         FIXME("can't use SSL, not compiled in.\n");
477         return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
478 #endif
479     }
480     return ERROR_SUCCESS;
481 }
482
483 void NETCON_unload(void)
484 {
485 #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO)
486     if (OpenSSL_crypto_handle)
487     {
488         pERR_free_strings();
489         wine_dlclose(OpenSSL_crypto_handle, NULL, 0);
490     }
491     if (OpenSSL_ssl_handle)
492     {
493         if (ctx)
494             pSSL_CTX_free(ctx);
495         wine_dlclose(OpenSSL_ssl_handle, NULL, 0);
496     }
497     if (ssl_locks)
498     {
499         int i;
500         for (i = 0; i < num_ssl_locks; i++) DeleteCriticalSection(&ssl_locks[i]);
501         HeapFree(GetProcessHeap(), 0, ssl_locks);
502     }
503 #endif
504 }
505
506 BOOL NETCON_connected(WININET_NETCONNECTION *connection)
507 {
508     if (connection->socketFD == -1)
509         return FALSE;
510     else
511         return TRUE;
512 }
513
514 /* translate a unix error code into a winsock one */
515 int sock_get_error( int err )
516 {
517 #if !defined(__MINGW32__) && !defined (_MSC_VER)
518     switch (err)
519     {
520         case EINTR:             return WSAEINTR;
521         case EBADF:             return WSAEBADF;
522         case EPERM:
523         case EACCES:            return WSAEACCES;
524         case EFAULT:            return WSAEFAULT;
525         case EINVAL:            return WSAEINVAL;
526         case EMFILE:            return WSAEMFILE;
527         case EWOULDBLOCK:       return WSAEWOULDBLOCK;
528         case EINPROGRESS:       return WSAEINPROGRESS;
529         case EALREADY:          return WSAEALREADY;
530         case ENOTSOCK:          return WSAENOTSOCK;
531         case EDESTADDRREQ:      return WSAEDESTADDRREQ;
532         case EMSGSIZE:          return WSAEMSGSIZE;
533         case EPROTOTYPE:        return WSAEPROTOTYPE;
534         case ENOPROTOOPT:       return WSAENOPROTOOPT;
535         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
536         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
537         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
538         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
539         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
540         case EADDRINUSE:        return WSAEADDRINUSE;
541         case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
542         case ENETDOWN:          return WSAENETDOWN;
543         case ENETUNREACH:       return WSAENETUNREACH;
544         case ENETRESET:         return WSAENETRESET;
545         case ECONNABORTED:      return WSAECONNABORTED;
546         case EPIPE:
547         case ECONNRESET:        return WSAECONNRESET;
548         case ENOBUFS:           return WSAENOBUFS;
549         case EISCONN:           return WSAEISCONN;
550         case ENOTCONN:          return WSAENOTCONN;
551         case ESHUTDOWN:         return WSAESHUTDOWN;
552         case ETOOMANYREFS:      return WSAETOOMANYREFS;
553         case ETIMEDOUT:         return WSAETIMEDOUT;
554         case ECONNREFUSED:      return WSAECONNREFUSED;
555         case ELOOP:             return WSAELOOP;
556         case ENAMETOOLONG:      return WSAENAMETOOLONG;
557         case EHOSTDOWN:         return WSAEHOSTDOWN;
558         case EHOSTUNREACH:      return WSAEHOSTUNREACH;
559         case ENOTEMPTY:         return WSAENOTEMPTY;
560 #ifdef EPROCLIM
561         case EPROCLIM:          return WSAEPROCLIM;
562 #endif
563 #ifdef EUSERS
564         case EUSERS:            return WSAEUSERS;
565 #endif
566 #ifdef EDQUOT
567         case EDQUOT:            return WSAEDQUOT;
568 #endif
569 #ifdef ESTALE
570         case ESTALE:            return WSAESTALE;
571 #endif
572 #ifdef EREMOTE
573         case EREMOTE:           return WSAEREMOTE;
574 #endif
575     default: errno=err; perror("sock_set_error"); return WSAEFAULT;
576     }
577 #endif
578     return err;
579 }
580
581 /******************************************************************************
582  * NETCON_create
583  * Basically calls 'socket()'
584  */
585 DWORD NETCON_create(WININET_NETCONNECTION *connection, int domain,
586               int type, int protocol)
587 {
588 #ifdef SONAME_LIBSSL
589     if (connection->useSSL)
590         return ERROR_NOT_SUPPORTED;
591 #endif
592
593     connection->socketFD = socket(domain, type, protocol);
594     if (connection->socketFD == -1)
595         return sock_get_error(errno);
596
597     return ERROR_SUCCESS;
598 }
599
600 /******************************************************************************
601  * NETCON_close
602  * Basically calls 'close()' unless we should use SSL
603  */
604 DWORD NETCON_close(WININET_NETCONNECTION *connection)
605 {
606     int result;
607
608     if (!NETCON_connected(connection)) return ERROR_SUCCESS;
609
610 #ifdef SONAME_LIBSSL
611     if (connection->useSSL)
612     {
613         pSSL_shutdown(connection->ssl_s);
614         pSSL_free(connection->ssl_s);
615         connection->ssl_s = NULL;
616
617         connection->useSSL = FALSE;
618     }
619 #endif
620
621     result = closesocket(connection->socketFD);
622     connection->socketFD = -1;
623
624     if (result == -1)
625         return sock_get_error(errno);
626     return ERROR_SUCCESS;
627 }
628
629 /******************************************************************************
630  * NETCON_secure_connect
631  * Initiates a secure connection over an existing plaintext connection.
632  */
633 DWORD NETCON_secure_connect(WININET_NETCONNECTION *connection, LPWSTR hostname)
634 {
635     DWORD res = ERROR_NOT_SUPPORTED;
636 #ifdef SONAME_LIBSSL
637     long verify_res;
638     X509 *cert;
639
640     /* can't connect if we are already connected */
641     if (connection->useSSL)
642     {
643         ERR("already connected\n");
644         return ERROR_INTERNET_CANNOT_CONNECT;
645     }
646
647     connection->ssl_s = pSSL_new(ctx);
648     if (!connection->ssl_s)
649     {
650         ERR("SSL_new failed: %s\n",
651             pERR_error_string(pERR_get_error(), 0));
652         res = ERROR_OUTOFMEMORY;
653         goto fail;
654     }
655
656     if (!pSSL_set_fd(connection->ssl_s, connection->socketFD))
657     {
658         ERR("SSL_set_fd failed: %s\n",
659             pERR_error_string(pERR_get_error(), 0));
660         res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
661         goto fail;
662     }
663
664     if (pSSL_connect(connection->ssl_s) <= 0)
665     {
666         res = (DWORD_PTR)pSSL_get_ex_data(connection->ssl_s, error_idx);
667         if (!res)
668             res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
669         ERR("SSL_connect failed: %d\n", res);
670         goto fail;
671     }
672     pSSL_set_ex_data(connection->ssl_s, hostname_idx, hostname);
673     cert = pSSL_get_peer_certificate(connection->ssl_s);
674     if (!cert)
675     {
676         ERR("no certificate for server %s\n", debugstr_w(hostname));
677         /* FIXME: is this the best error? */
678         res = ERROR_INTERNET_INVALID_CA;
679         goto fail;
680     }
681     verify_res = pSSL_get_verify_result(connection->ssl_s);
682     if (verify_res != X509_V_OK)
683     {
684         ERR("couldn't verify the security of the connection, %ld\n", verify_res);
685         /* FIXME: we should set an error and return, but we only warn at
686          * the moment */
687     }
688
689     connection->useSSL = TRUE;
690     return ERROR_SUCCESS;
691
692 fail:
693     if (connection->ssl_s)
694     {
695         pSSL_shutdown(connection->ssl_s);
696         pSSL_free(connection->ssl_s);
697         connection->ssl_s = NULL;
698     }
699 #endif
700     return res;
701 }
702
703 /******************************************************************************
704  * NETCON_connect
705  * Connects to the specified address.
706  */
707 DWORD NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr,
708                     unsigned int addrlen)
709 {
710     int result;
711
712     result = connect(connection->socketFD, serv_addr, addrlen);
713     if (result == -1)
714     {
715         WARN("Unable to connect to host (%s)\n", strerror(errno));
716
717         closesocket(connection->socketFD);
718         connection->socketFD = -1;
719         return sock_get_error(errno);
720     }
721
722     return ERROR_SUCCESS;
723 }
724
725 /******************************************************************************
726  * NETCON_send
727  * Basically calls 'send()' unless we should use SSL
728  * number of chars send is put in *sent
729  */
730 DWORD NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags,
731                 int *sent /* out */)
732 {
733     if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED;
734     if (!connection->useSSL)
735     {
736         *sent = send(connection->socketFD, msg, len, flags);
737         if (*sent == -1)
738             return sock_get_error(errno);
739         return ERROR_SUCCESS;
740     }
741     else
742     {
743 #ifdef SONAME_LIBSSL
744         if (flags)
745             FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
746         *sent = pSSL_write(connection->ssl_s, msg, len);
747         if (*sent < 1 && len)
748             return ERROR_INTERNET_CONNECTION_ABORTED;
749         return ERROR_SUCCESS;
750 #else
751         return ERROR_NOT_SUPPORTED;
752 #endif
753     }
754 }
755
756 /******************************************************************************
757  * NETCON_recv
758  * Basically calls 'recv()' unless we should use SSL
759  * number of chars received is put in *recvd
760  */
761 DWORD NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags,
762                 int *recvd /* out */)
763 {
764     *recvd = 0;
765     if (!NETCON_connected(connection)) return ERROR_INTERNET_CONNECTION_ABORTED;
766     if (!len)
767         return ERROR_SUCCESS;
768     if (!connection->useSSL)
769     {
770         *recvd = recv(connection->socketFD, buf, len, flags);
771         return *recvd == -1 ? sock_get_error(errno) :  ERROR_SUCCESS;
772     }
773     else
774     {
775 #ifdef SONAME_LIBSSL
776         *recvd = pSSL_read(connection->ssl_s, buf, len);
777
778         /* Check if EOF was received */
779         if(!*recvd && (pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_ZERO_RETURN
780                     || pSSL_get_error(connection->ssl_s, *recvd)==SSL_ERROR_SYSCALL))
781             return ERROR_SUCCESS;
782
783         return *recvd > 0 ? ERROR_SUCCESS : ERROR_INTERNET_CONNECTION_ABORTED;
784 #else
785         return ERROR_NOT_SUPPORTED;
786 #endif
787     }
788 }
789
790 /******************************************************************************
791  * NETCON_query_data_available
792  * Returns the number of bytes of peeked data plus the number of bytes of
793  * queued, but unread data.
794  */
795 BOOL NETCON_query_data_available(WININET_NETCONNECTION *connection, DWORD *available)
796 {
797     *available = 0;
798     if (!NETCON_connected(connection))
799         return FALSE;
800
801     if (!connection->useSSL)
802     {
803 #ifdef FIONREAD
804         int unread;
805         int retval = ioctlsocket(connection->socketFD, FIONREAD, &unread);
806         if (!retval)
807         {
808             TRACE("%d bytes of queued, but unread data\n", unread);
809             *available += unread;
810         }
811 #endif
812     }
813     else
814     {
815 #ifdef SONAME_LIBSSL
816         *available = pSSL_pending(connection->ssl_s);
817 #endif
818     }
819     return TRUE;
820 }
821
822 LPCVOID NETCON_GetCert(WININET_NETCONNECTION *connection)
823 {
824 #ifdef SONAME_LIBSSL
825     X509* cert;
826     LPCVOID r = NULL;
827
828     if (!connection->useSSL)
829         return NULL;
830
831     cert = pSSL_get_peer_certificate(connection->ssl_s);
832     r = X509_to_cert_context(cert);
833     return r;
834 #else
835     return NULL;
836 #endif
837 }
838
839 DWORD NETCON_set_timeout(WININET_NETCONNECTION *connection, BOOL send, int value)
840 {
841     int result;
842     struct timeval tv;
843
844     /* FIXME: we should probably store the timeout in the connection to set
845      * when we do connect */
846     if (!NETCON_connected(connection))
847         return ERROR_SUCCESS;
848
849     /* value is in milliseconds, convert to struct timeval */
850     tv.tv_sec = value / 1000;
851     tv.tv_usec = (value % 1000) * 1000;
852
853     result = setsockopt(connection->socketFD, SOL_SOCKET,
854                         send ? SO_SNDTIMEO : SO_RCVTIMEO, (void*)&tv,
855                         sizeof(tv));
856
857     if (result == -1)
858     {
859         WARN("setsockopt failed (%s)\n", strerror(errno));
860         return sock_get_error(errno);
861     }
862
863     return ERROR_SUCCESS;
864 }