Use a timeout when sending broadcast messages.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #ifdef HAVE_SYS_TIME_H
27 # include <sys/time.h>
28 #endif
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32 #ifdef HAVE_SYS_SOCKET_H
33 # include <sys/socket.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "wine/library.h"
43 #include "windef.h"
44 #include "winbase.h"
45 #include "wininet.h"
46 #include "winerror.h"
47
48 #include "wine/debug.h"
49 #include "internet.h"
50
51 #define RESPONSE_TIMEOUT        30            /* FROM internet.c */
52
53
54 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55
56 /* FIXME!!!!!!
57  *    This should use winsock - To use winsock the funtions will have to change a bit
58  *        as they are designed for unix sockets.
59  *    SSL stuff should use crypt32.dll
60  */
61
62 #ifdef HAVE_OPENSSL_SSL_H
63
64 #ifndef SONAME_LIBSSL
65 #define SONAME_LIBSSL "libssl.so"
66 #endif
67 #ifndef SONAME_LIBCRYPTO
68 #define SONAME_LIBCRYPTO "libcrypto.so"
69 #endif
70
71 static void *OpenSSL_ssl_handle;
72 static void *OpenSSL_crypto_handle;
73
74 static SSL_METHOD *meth;
75 static SSL_CTX *ctx;
76
77 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
78
79 /* OpenSSL funtions that we use */
80 MAKE_FUNCPTR(SSL_library_init);
81 MAKE_FUNCPTR(SSL_load_error_strings);
82 MAKE_FUNCPTR(SSLv23_method);
83 MAKE_FUNCPTR(SSL_CTX_new);
84 MAKE_FUNCPTR(SSL_new);
85 MAKE_FUNCPTR(SSL_set_bio);
86 MAKE_FUNCPTR(SSL_connect);
87 MAKE_FUNCPTR(SSL_write);
88 MAKE_FUNCPTR(SSL_read);
89 MAKE_FUNCPTR(SSL_CTX_get_timeout);
90 MAKE_FUNCPTR(SSL_CTX_set_timeout);
91
92 /* OpenSSL's libcrypto functions that we use */
93 MAKE_FUNCPTR(BIO_new_socket);
94 MAKE_FUNCPTR(BIO_new_fp);
95 #undef MAKE_FUNCPTR
96
97 #endif
98
99 void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
100 {
101     connection->useSSL = useSSL;
102     connection->socketFD = -1;
103     if (connection->useSSL)
104     {
105 #ifdef HAVE_OPENSSL_SSL_H
106         TRACE("using SSL connection\n");
107         connection->ssl_sock = -1;
108         if (OpenSSL_ssl_handle) /* already initilzed everything */
109             return;
110         OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0);
111         if (!OpenSSL_ssl_handle)
112         {
113             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
114                 SONAME_LIBSSL);
115             connection->useSSL = FALSE;
116             return;
117         }
118         OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0);
119         if (!OpenSSL_crypto_handle)
120         {
121             ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n",
122                 SONAME_LIBCRYPTO);
123             connection->useSSL = FALSE;
124             return;
125         }
126
127         /* mmm nice ugly macroness */
128 #define DYNSSL(x) \
129     p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \
130     if (!p##x) \
131     { \
132         ERR("failed to load symbol %s\n", #x); \
133         connection->useSSL = FALSE; \
134         return; \
135     }
136
137         DYNSSL(SSL_library_init);
138         DYNSSL(SSL_load_error_strings);
139         DYNSSL(SSLv23_method);
140         DYNSSL(SSL_CTX_new);
141         DYNSSL(SSL_new);
142         DYNSSL(SSL_set_bio);
143         DYNSSL(SSL_connect);
144         DYNSSL(SSL_write);
145         DYNSSL(SSL_read);
146         DYNSSL(SSL_CTX_get_timeout);
147         DYNSSL(SSL_CTX_set_timeout);
148 #undef DYNSSL
149
150 #define DYNCRYPTO(x) \
151     p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \
152     if (!p##x) \
153     { \
154         ERR("failed to load symbol %s\n", #x); \
155         connection->useSSL = FALSE; \
156         return; \
157     }
158         DYNCRYPTO(BIO_new_fp);
159         DYNCRYPTO(BIO_new_socket);
160 #undef DYNCRYPTO
161
162         pSSL_library_init();
163         pSSL_load_error_strings();
164         pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */
165
166         meth = pSSLv23_method();
167         /* FIXME: SECURITY PROBLEM! WE ARN'T VERIFYING THE HOSTS CERTIFICATES OR ANYTHING */
168 #else
169         FIXME("can't use SSL, not compiled in.\n");
170         connection->useSSL = FALSE;
171 #endif
172     }
173 }
174
175 BOOL NETCON_connected(WININET_NETCONNECTION *connection)
176 {
177     if (!connection->useSSL)
178     {
179         if (connection->socketFD == -1)
180             return FALSE;
181         return TRUE;
182     }
183     else
184     {
185 #ifdef HAVE_OPENSSL_SSL_H
186         if (connection->ssl_sock == -1)
187             return FALSE;
188         return TRUE;
189 #else
190         return FALSE;
191 #endif
192     }
193 }
194
195 /******************************************************************************
196  * NETCON_create
197  * Basically calls 'socket()' unless useSSL is supplised,
198  *  in which case we do other things.
199  */
200 BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain,
201               int type, int protocol)
202 {
203     if (!connection->useSSL)
204     {
205         connection->socketFD = socket(domain, type, protocol);
206         if (connection->socketFD == -1)
207             return FALSE;
208         return TRUE;
209     }
210     else
211     {
212 #ifdef HAVE_OPENSSL_SSL_H
213         connection->ssl_sock = socket(domain, type, protocol);
214         return TRUE;
215 #else
216         return FALSE;
217 #endif
218     }
219 }
220
221 /******************************************************************************
222  * NETCON_close
223  * Basically calls 'close()' unless we should use SSL
224  */
225 BOOL NETCON_close(WININET_NETCONNECTION *connection)
226 {
227     if (!NETCON_connected(connection)) return FALSE;
228     if (!connection->useSSL)
229     {
230         int result;
231         result = close(connection->socketFD);
232         connection->socketFD = -1;
233         if (result == -1)
234             return FALSE;
235         return TRUE;
236     }
237     else
238     {
239 #ifdef HAVE_OPENSSL_SSL_H
240         close(connection->ssl_sock);
241         connection->ssl_sock = -1;
242         /* FIXME should we call SSL_shutdown here?? Probably on whatever is the
243          * opposite of NETCON_init.... */
244         return TRUE;
245 #else
246         return FALSE;
247 #endif
248     }
249 }
250
251 /******************************************************************************
252  * NETCON_connect
253  * Basically calls 'connect()' unless we should use SSL
254  */
255 BOOL NETCON_connect(WININET_NETCONNECTION *connection, const struct sockaddr *serv_addr,
256                     socklen_t addrlen)
257 {
258     if (!NETCON_connected(connection)) return FALSE;
259     if (!connection->useSSL)
260     {
261         int result;
262         result = connect(connection->socketFD, serv_addr, addrlen);
263         if (result == -1)
264         {
265             close(connection->socketFD);
266             connection->socketFD = -1;
267             return FALSE;
268         }
269         return TRUE;
270     }
271     else
272     {
273 #ifdef HAVE_OPENSSL_SSL_H
274         BIO *sbio;
275
276         ctx = pSSL_CTX_new(meth);
277         connection->ssl_s = pSSL_new(ctx);
278
279         if (connect(connection->ssl_sock, serv_addr, addrlen) == -1)
280             return FALSE;
281
282         sbio = pBIO_new_socket(connection->ssl_sock, BIO_NOCLOSE);
283         pSSL_set_bio(connection->ssl_s, sbio, sbio);
284         if (pSSL_connect(connection->ssl_s) <= 0)
285         {
286             ERR("ssl couldn't connect\n");
287             return FALSE;
288         }
289         return TRUE;
290 #else
291         return FALSE;
292 #endif
293     }
294 }
295
296 /******************************************************************************
297  * NETCON_send
298  * Basically calls 'send()' unless we should use SSL
299  * number of chars send is put in *sent
300  */
301 BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, int flags,
302                 int *sent /* out */)
303 {
304     if (!NETCON_connected(connection)) return FALSE;
305     if (!connection->useSSL)
306     {
307         *sent = send(connection->socketFD, msg, len, flags);
308         if (*sent == -1)
309             return FALSE;
310         return TRUE;
311     }
312     else
313     {
314 #ifdef HAVE_OPENSSL_SSL_H
315         if (flags)
316             FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
317         *sent = pSSL_write(connection->ssl_s, msg, len);
318         if (*sent < 1 && len)
319             return FALSE;
320         return TRUE;
321 #else
322         return FALSE;
323 #endif
324     }
325 }
326
327 /******************************************************************************
328  * NETCON_recv
329  * Basically calls 'recv()' unless we should use SSL
330  * number of chars received is put in *recvd
331  */
332 BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int flags,
333                 int *recvd /* out */)
334 {
335     if (!NETCON_connected(connection)) return FALSE;
336     if (!connection->useSSL)
337     {
338         *recvd = recv(connection->socketFD, buf, len, flags);
339         if (*recvd == -1)
340             return FALSE;
341         return TRUE;
342     }
343     else
344     {
345 #ifdef HAVE_OPENSSL_SSL_H
346         static char *peek_msg = NULL;
347         static char *peek_msg_mem = NULL;
348
349         if (flags & (~MSG_PEEK))
350             FIXME("SSL_read does not support the following flag: %08x\n", flags);
351
352         /* this ugly hack is all for MSG_PEEK. eww gross */
353         if (flags & MSG_PEEK && !peek_msg)
354         {
355             peek_msg = peek_msg_mem = HeapAlloc(GetProcessHeap(), 0, (sizeof(char) * len) + 1);
356         }
357         else if (flags & MSG_PEEK && peek_msg)
358         {
359             if (len < strlen(peek_msg))
360                 FIXME("buffer isn't big enough. Do the expect us to wrap?\n");
361             strncpy(buf, peek_msg, len);
362             *recvd = (strlen(peek_msg) <= len ? strlen(peek_msg) : len);
363             return TRUE;
364         }
365         else if (peek_msg)
366         {
367             strncpy(buf, peek_msg, len);
368             peek_msg += *recvd = min(len, strlen(peek_msg));
369             if (*peek_msg == '\0' || *(peek_msg - 1) == '\0')
370             {
371                 HeapFree(GetProcessHeap(), 0, peek_msg_mem);
372                 peek_msg_mem = NULL;
373                 peek_msg = NULL;
374             }
375             return TRUE;
376         }
377         *recvd = pSSL_read(connection->ssl_s, buf, len);
378         if (flags & MSG_PEEK) /* must copy stuff into buffer */
379         {
380             if (!*recvd)
381             {
382                 HeapFree(GetProcessHeap(), 0, peek_msg_mem);
383                 peek_msg_mem = NULL;
384                 peek_msg = NULL;
385             }
386             else
387             {
388                 strncpy(peek_msg, buf, *recvd);
389                 peek_msg[*recvd] = '\0';
390             }
391         }
392         if (*recvd < 1 && len)
393             return FALSE;
394         return TRUE;
395 #else
396         return FALSE;
397 #endif
398     }
399 }
400
401 /******************************************************************************
402  * NETCON_getNextLine
403  */
404 BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPDWORD dwBuffer)
405 {
406
407     TRACE("\n");
408
409     if (!NETCON_connected(connection)) return FALSE;
410
411     if (!connection->useSSL)
412     {
413         struct timeval tv;
414         fd_set infd;
415         BOOL bSuccess = FALSE;
416         INT nRecv = 0;
417
418         FD_ZERO(&infd);
419         FD_SET(connection->socketFD, &infd);
420         tv.tv_sec=RESPONSE_TIMEOUT;
421         tv.tv_usec=0;
422
423         while (nRecv < *dwBuffer)
424         {
425             if (select(connection->socketFD+1,&infd,NULL,NULL,&tv) > 0)
426             {
427                 if (recv(connection->socketFD, &lpszBuffer[nRecv], 1, 0) <= 0)
428                 {
429                     INTERNET_SetLastError(ERROR_CONNECTION_ABORTED); /* fixme: right error? */
430                     goto lend;
431                 }
432
433                 if (lpszBuffer[nRecv] == '\n')
434                 {
435                     bSuccess = TRUE;
436                     break;
437                 }
438                 if (lpszBuffer[nRecv] != '\r')
439                     nRecv++;
440             }
441             else
442             {
443                 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
444                 goto lend;
445             }
446         }
447
448     lend:             /* FIXME: don't use labels */
449         if (bSuccess)
450         {
451             lpszBuffer[nRecv] = '\0';
452             *dwBuffer = nRecv - 1;
453             TRACE(":%d %s\n", nRecv, lpszBuffer);
454             return TRUE;
455         }
456         else
457         {
458             return FALSE;
459         }
460     }
461     else
462     {
463 #ifdef HAVE_OPENSSL_SSL_H
464         long prev_timeout;
465         INT nRecv = 0;
466         BOOL success = TRUE;
467
468         prev_timeout = pSSL_CTX_get_timeout(ctx);
469         pSSL_CTX_set_timeout(ctx, RESPONSE_TIMEOUT);
470
471         while (nRecv < *dwBuffer)
472         {
473             int recv = 1;
474             if (!NETCON_recv(connection, &lpszBuffer[nRecv], 1, 0, &recv))
475             {
476                 INTERNET_SetLastError(ERROR_CONNECTION_ABORTED);
477                 success = FALSE;
478             }
479
480             if (lpszBuffer[nRecv] == '\n')
481             {
482                 success = TRUE;
483                 break;
484             }
485             if (lpszBuffer[nRecv] != '\r')
486                 nRecv++;
487         }
488
489         pSSL_CTX_set_timeout(ctx, prev_timeout);
490         if (success)
491         {
492             lpszBuffer[nRecv] = '\0';
493             *dwBuffer = nRecv - 1;
494             TRACE("_SSL:%d %s\n", nRecv, lpszBuffer);
495             return TRUE;
496         }
497         return FALSE;
498 #else
499         return FALSE;
500 #endif
501     }
502 }