]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/mbedtls/library/net_sockets.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / mbedtls / library / net_sockets.c
1 /*\r
2  *  TCP/IP or UDP/IP networking functions\r
3  *\r
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved\r
5  *  SPDX-License-Identifier: Apache-2.0\r
6  *\r
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may\r
8  *  not use this file except in compliance with the License.\r
9  *  You may obtain a copy of the License at\r
10  *\r
11  *  http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  *  Unless required by applicable law or agreed to in writing, software\r
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  *  See the License for the specific language governing permissions and\r
17  *  limitations under the License.\r
18  *\r
19  *  This file is part of mbed TLS (https://tls.mbed.org)\r
20  */\r
21 \r
22 /* Enable definition of getaddrinfo() even when compiling with -std=c99. Must\r
23  * be set before config.h, which pulls in glibc's features.h indirectly.\r
24  * Harmless on other platforms. */\r
25 #define _POSIX_C_SOURCE 200112L\r
26 \r
27 #if !defined(MBEDTLS_CONFIG_FILE)\r
28 #include "mbedtls/config.h"\r
29 #else\r
30 #include MBEDTLS_CONFIG_FILE\r
31 #endif\r
32 \r
33 #if defined(MBEDTLS_NET_C)\r
34 \r
35 #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \\r
36     !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \\r
37     !defined(__HAIKU__)\r
38 #error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h"\r
39 #endif\r
40 \r
41 #if defined(MBEDTLS_PLATFORM_C)\r
42 #include "mbedtls/platform.h"\r
43 #else\r
44 #include <stdlib.h>\r
45 #endif\r
46 \r
47 #include "mbedtls/net_sockets.h"\r
48 \r
49 #include <string.h>\r
50 \r
51 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \\r
52     !defined(EFI32)\r
53 \r
54 #define IS_EINTR( ret ) ( ( ret ) == WSAEINTR )\r
55 \r
56 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501)\r
57 #undef _WIN32_WINNT\r
58 /* Enables getaddrinfo() & Co */\r
59 #define _WIN32_WINNT 0x0501\r
60 #endif\r
61 \r
62 #include <ws2tcpip.h>\r
63 \r
64 #include <winsock2.h>\r
65 #include <windows.h>\r
66 \r
67 #if defined(_MSC_VER)\r
68 #if defined(_WIN32_WCE)\r
69 #pragma comment( lib, "ws2.lib" )\r
70 #else\r
71 #pragma comment( lib, "ws2_32.lib" )\r
72 #endif\r
73 #endif /* _MSC_VER */\r
74 \r
75 #define read(fd,buf,len)        recv( fd, (char*)( buf ), (int)( len ), 0 )\r
76 #define write(fd,buf,len)       send( fd, (char*)( buf ), (int)( len ), 0 )\r
77 #define close(fd)               closesocket(fd)\r
78 \r
79 static int wsa_init_done = 0;\r
80 \r
81 #else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */\r
82 \r
83 #include <sys/types.h>\r
84 #include <sys/socket.h>\r
85 #include <netinet/in.h>\r
86 #include <arpa/inet.h>\r
87 #include <sys/time.h>\r
88 #include <unistd.h>\r
89 #include <signal.h>\r
90 #include <fcntl.h>\r
91 #include <netdb.h>\r
92 #include <errno.h>\r
93 \r
94 #define IS_EINTR( ret ) ( ( ret ) == EINTR )\r
95 \r
96 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */\r
97 \r
98 /* Some MS functions want int and MSVC warns if we pass size_t,\r
99  * but the standard functions use socklen_t, so cast only for MSVC */\r
100 #if defined(_MSC_VER)\r
101 #define MSVC_INT_CAST   (int)\r
102 #else\r
103 #define MSVC_INT_CAST\r
104 #endif\r
105 \r
106 #include <stdio.h>\r
107 \r
108 #include <time.h>\r
109 \r
110 #include <stdint.h>\r
111 \r
112 /*\r
113  * Prepare for using the sockets interface\r
114  */\r
115 static int net_prepare( void )\r
116 {\r
117 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
118     !defined(EFI32)\r
119     WSADATA wsaData;\r
120 \r
121     if( wsa_init_done == 0 )\r
122     {\r
123         if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 )\r
124             return( MBEDTLS_ERR_NET_SOCKET_FAILED );\r
125 \r
126         wsa_init_done = 1;\r
127     }\r
128 #else\r
129 #if !defined(EFIX64) && !defined(EFI32)\r
130     signal( SIGPIPE, SIG_IGN );\r
131 #endif\r
132 #endif\r
133     return( 0 );\r
134 }\r
135 \r
136 /*\r
137  * Initialize a context\r
138  */\r
139 void mbedtls_net_init( mbedtls_net_context *ctx )\r
140 {\r
141     ctx->fd = -1;\r
142 }\r
143 \r
144 /*\r
145  * Initiate a TCP connection with host:port and the given protocol\r
146  */\r
147 int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host,\r
148                          const char *port, int proto )\r
149 {\r
150     int ret;\r
151     struct addrinfo hints, *addr_list, *cur;\r
152 \r
153     if( ( ret = net_prepare() ) != 0 )\r
154         return( ret );\r
155 \r
156     /* Do name resolution with both IPv6 and IPv4 */\r
157     memset( &hints, 0, sizeof( hints ) );\r
158     hints.ai_family = AF_UNSPEC;\r
159     hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;\r
160     hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;\r
161 \r
162     if( getaddrinfo( host, port, &hints, &addr_list ) != 0 )\r
163         return( MBEDTLS_ERR_NET_UNKNOWN_HOST );\r
164 \r
165     /* Try the sockaddrs until a connection succeeds */\r
166     ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;\r
167     for( cur = addr_list; cur != NULL; cur = cur->ai_next )\r
168     {\r
169         ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype,\r
170                             cur->ai_protocol );\r
171         if( ctx->fd < 0 )\r
172         {\r
173             ret = MBEDTLS_ERR_NET_SOCKET_FAILED;\r
174             continue;\r
175         }\r
176 \r
177         if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 )\r
178         {\r
179             ret = 0;\r
180             break;\r
181         }\r
182 \r
183         close( ctx->fd );\r
184         ret = MBEDTLS_ERR_NET_CONNECT_FAILED;\r
185     }\r
186 \r
187     freeaddrinfo( addr_list );\r
188 \r
189     return( ret );\r
190 }\r
191 \r
192 /*\r
193  * Create a listening socket on bind_ip:port\r
194  */\r
195 int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )\r
196 {\r
197     int n, ret;\r
198     struct addrinfo hints, *addr_list, *cur;\r
199 \r
200     if( ( ret = net_prepare() ) != 0 )\r
201         return( ret );\r
202 \r
203     /* Bind to IPv6 and/or IPv4, but only in the desired protocol */\r
204     memset( &hints, 0, sizeof( hints ) );\r
205     hints.ai_family = AF_UNSPEC;\r
206     hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;\r
207     hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;\r
208     if( bind_ip == NULL )\r
209         hints.ai_flags = AI_PASSIVE;\r
210 \r
211     if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 )\r
212         return( MBEDTLS_ERR_NET_UNKNOWN_HOST );\r
213 \r
214     /* Try the sockaddrs until a binding succeeds */\r
215     ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;\r
216     for( cur = addr_list; cur != NULL; cur = cur->ai_next )\r
217     {\r
218         ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype,\r
219                             cur->ai_protocol );\r
220         if( ctx->fd < 0 )\r
221         {\r
222             ret = MBEDTLS_ERR_NET_SOCKET_FAILED;\r
223             continue;\r
224         }\r
225 \r
226         n = 1;\r
227         if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR,\r
228                         (const char *) &n, sizeof( n ) ) != 0 )\r
229         {\r
230             close( ctx->fd );\r
231             ret = MBEDTLS_ERR_NET_SOCKET_FAILED;\r
232             continue;\r
233         }\r
234 \r
235         if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 )\r
236         {\r
237             close( ctx->fd );\r
238             ret = MBEDTLS_ERR_NET_BIND_FAILED;\r
239             continue;\r
240         }\r
241 \r
242         /* Listen only makes sense for TCP */\r
243         if( proto == MBEDTLS_NET_PROTO_TCP )\r
244         {\r
245             if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 )\r
246             {\r
247                 close( ctx->fd );\r
248                 ret = MBEDTLS_ERR_NET_LISTEN_FAILED;\r
249                 continue;\r
250             }\r
251         }\r
252 \r
253         /* Bind was successful */\r
254         ret = 0;\r
255         break;\r
256     }\r
257 \r
258     freeaddrinfo( addr_list );\r
259 \r
260     return( ret );\r
261 \r
262 }\r
263 \r
264 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
265     !defined(EFI32)\r
266 /*\r
267  * Check if the requested operation would be blocking on a non-blocking socket\r
268  * and thus 'failed' with a negative return value.\r
269  */\r
270 static int net_would_block( const mbedtls_net_context *ctx )\r
271 {\r
272     ((void) ctx);\r
273     return( WSAGetLastError() == WSAEWOULDBLOCK );\r
274 }\r
275 #else\r
276 /*\r
277  * Check if the requested operation would be blocking on a non-blocking socket\r
278  * and thus 'failed' with a negative return value.\r
279  *\r
280  * Note: on a blocking socket this function always returns 0!\r
281  */\r
282 static int net_would_block( const mbedtls_net_context *ctx )\r
283 {\r
284     int err = errno;\r
285 \r
286     /*\r
287      * Never return 'WOULD BLOCK' on a non-blocking socket\r
288      */\r
289     if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK )\r
290     {\r
291         errno = err;\r
292         return( 0 );\r
293     }\r
294 \r
295     switch( errno = err )\r
296     {\r
297 #if defined EAGAIN\r
298         case EAGAIN:\r
299 #endif\r
300 #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN\r
301         case EWOULDBLOCK:\r
302 #endif\r
303             return( 1 );\r
304     }\r
305     return( 0 );\r
306 }\r
307 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */\r
308 \r
309 /*\r
310  * Accept a connection from a remote client\r
311  */\r
312 int mbedtls_net_accept( mbedtls_net_context *bind_ctx,\r
313                         mbedtls_net_context *client_ctx,\r
314                         void *client_ip, size_t buf_size, size_t *ip_len )\r
315 {\r
316     int ret;\r
317     int type;\r
318 \r
319     struct sockaddr_storage client_addr;\r
320 \r
321 #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) ||  \\r
322     defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t)\r
323     socklen_t n = (socklen_t) sizeof( client_addr );\r
324     socklen_t type_len = (socklen_t) sizeof( type );\r
325 #else\r
326     int n = (int) sizeof( client_addr );\r
327     int type_len = (int) sizeof( type );\r
328 #endif\r
329 \r
330     /* Is this a TCP or UDP socket? */\r
331     if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE,\r
332                     (void *) &type, &type_len ) != 0 ||\r
333         ( type != SOCK_STREAM && type != SOCK_DGRAM ) )\r
334     {\r
335         return( MBEDTLS_ERR_NET_ACCEPT_FAILED );\r
336     }\r
337 \r
338     if( type == SOCK_STREAM )\r
339     {\r
340         /* TCP: actual accept() */\r
341         ret = client_ctx->fd = (int) accept( bind_ctx->fd,\r
342                                              (struct sockaddr *) &client_addr, &n );\r
343     }\r
344     else\r
345     {\r
346         /* UDP: wait for a message, but keep it in the queue */\r
347         char buf[1] = { 0 };\r
348 \r
349         ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK,\r
350                         (struct sockaddr *) &client_addr, &n );\r
351 \r
352 #if defined(_WIN32)\r
353         if( ret == SOCKET_ERROR &&\r
354             WSAGetLastError() == WSAEMSGSIZE )\r
355         {\r
356             /* We know buf is too small, thanks, just peeking here */\r
357             ret = 0;\r
358         }\r
359 #endif\r
360     }\r
361 \r
362     if( ret < 0 )\r
363     {\r
364         if( net_would_block( bind_ctx ) != 0 )\r
365             return( MBEDTLS_ERR_SSL_WANT_READ );\r
366 \r
367         return( MBEDTLS_ERR_NET_ACCEPT_FAILED );\r
368     }\r
369 \r
370     /* UDP: hijack the listening socket to communicate with the client,\r
371      * then bind a new socket to accept new connections */\r
372     if( type != SOCK_STREAM )\r
373     {\r
374         struct sockaddr_storage local_addr;\r
375         int one = 1;\r
376 \r
377         if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 )\r
378             return( MBEDTLS_ERR_NET_ACCEPT_FAILED );\r
379 \r
380         client_ctx->fd = bind_ctx->fd;\r
381         bind_ctx->fd   = -1; /* In case we exit early */\r
382 \r
383         n = sizeof( struct sockaddr_storage );\r
384         if( getsockname( client_ctx->fd,\r
385                          (struct sockaddr *) &local_addr, &n ) != 0 ||\r
386             ( bind_ctx->fd = (int) socket( local_addr.ss_family,\r
387                                            SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ||\r
388             setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR,\r
389                         (const char *) &one, sizeof( one ) ) != 0 )\r
390         {\r
391             return( MBEDTLS_ERR_NET_SOCKET_FAILED );\r
392         }\r
393 \r
394         if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 )\r
395         {\r
396             return( MBEDTLS_ERR_NET_BIND_FAILED );\r
397         }\r
398     }\r
399 \r
400     if( client_ip != NULL )\r
401     {\r
402         if( client_addr.ss_family == AF_INET )\r
403         {\r
404             struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;\r
405             *ip_len = sizeof( addr4->sin_addr.s_addr );\r
406 \r
407             if( buf_size < *ip_len )\r
408                 return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL );\r
409 \r
410             memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len );\r
411         }\r
412         else\r
413         {\r
414             struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr;\r
415             *ip_len = sizeof( addr6->sin6_addr.s6_addr );\r
416 \r
417             if( buf_size < *ip_len )\r
418                 return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL );\r
419 \r
420             memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len);\r
421         }\r
422     }\r
423 \r
424     return( 0 );\r
425 }\r
426 \r
427 /*\r
428  * Set the socket blocking or non-blocking\r
429  */\r
430 int mbedtls_net_set_block( mbedtls_net_context *ctx )\r
431 {\r
432 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
433     !defined(EFI32)\r
434     u_long n = 0;\r
435     return( ioctlsocket( ctx->fd, FIONBIO, &n ) );\r
436 #else\r
437     return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) );\r
438 #endif\r
439 }\r
440 \r
441 int mbedtls_net_set_nonblock( mbedtls_net_context *ctx )\r
442 {\r
443 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
444     !defined(EFI32)\r
445     u_long n = 1;\r
446     return( ioctlsocket( ctx->fd, FIONBIO, &n ) );\r
447 #else\r
448     return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) );\r
449 #endif\r
450 }\r
451 \r
452 /*\r
453  * Check if data is available on the socket\r
454  */\r
455 \r
456 int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout )\r
457 {\r
458     int ret;\r
459     struct timeval tv;\r
460 \r
461     fd_set read_fds;\r
462     fd_set write_fds;\r
463 \r
464     int fd = ctx->fd;\r
465 \r
466     if( fd < 0 )\r
467         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );\r
468 \r
469 #if defined(__has_feature)\r
470 #if __has_feature(memory_sanitizer)\r
471     /* Ensure that memory sanitizers consider read_fds and write_fds as\r
472      * initialized even on platforms such as Glibc/x86_64 where FD_ZERO\r
473      * is implemented in assembly. */\r
474     memset( &read_fds, 0, sizeof( read_fds ) );\r
475     memset( &write_fds, 0, sizeof( write_fds ) );\r
476 #endif\r
477 #endif\r
478 \r
479     FD_ZERO( &read_fds );\r
480     if( rw & MBEDTLS_NET_POLL_READ )\r
481     {\r
482         rw &= ~MBEDTLS_NET_POLL_READ;\r
483         FD_SET( fd, &read_fds );\r
484     }\r
485 \r
486     FD_ZERO( &write_fds );\r
487     if( rw & MBEDTLS_NET_POLL_WRITE )\r
488     {\r
489         rw &= ~MBEDTLS_NET_POLL_WRITE;\r
490         FD_SET( fd, &write_fds );\r
491     }\r
492 \r
493     if( rw != 0 )\r
494         return( MBEDTLS_ERR_NET_BAD_INPUT_DATA );\r
495 \r
496     tv.tv_sec  = timeout / 1000;\r
497     tv.tv_usec = ( timeout % 1000 ) * 1000;\r
498 \r
499     do\r
500     {\r
501         ret = select( fd + 1, &read_fds, &write_fds, NULL,\r
502                       timeout == (uint32_t) -1 ? NULL : &tv );\r
503     }\r
504     while( IS_EINTR( ret ) );\r
505 \r
506     if( ret < 0 )\r
507         return( MBEDTLS_ERR_NET_POLL_FAILED );\r
508 \r
509     ret = 0;\r
510     if( FD_ISSET( fd, &read_fds ) )\r
511         ret |= MBEDTLS_NET_POLL_READ;\r
512     if( FD_ISSET( fd, &write_fds ) )\r
513         ret |= MBEDTLS_NET_POLL_WRITE;\r
514 \r
515     return( ret );\r
516 }\r
517 \r
518 /*\r
519  * Portable usleep helper\r
520  */\r
521 void mbedtls_net_usleep( unsigned long usec )\r
522 {\r
523 #if defined(_WIN32)\r
524     Sleep( ( usec + 999 ) / 1000 );\r
525 #else\r
526     struct timeval tv;\r
527     tv.tv_sec  = usec / 1000000;\r
528 #if defined(__unix__) || defined(__unix) || \\r
529     ( defined(__APPLE__) && defined(__MACH__) )\r
530     tv.tv_usec = (suseconds_t) usec % 1000000;\r
531 #else\r
532     tv.tv_usec = usec % 1000000;\r
533 #endif\r
534     select( 0, NULL, NULL, NULL, &tv );\r
535 #endif\r
536 }\r
537 \r
538 /*\r
539  * Read at most 'len' characters\r
540  */\r
541 int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )\r
542 {\r
543     int ret;\r
544     int fd = ((mbedtls_net_context *) ctx)->fd;\r
545 \r
546     if( fd < 0 )\r
547         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );\r
548 \r
549     ret = (int) read( fd, buf, len );\r
550 \r
551     if( ret < 0 )\r
552     {\r
553         if( net_would_block( ctx ) != 0 )\r
554             return( MBEDTLS_ERR_SSL_WANT_READ );\r
555 \r
556 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
557     !defined(EFI32)\r
558         if( WSAGetLastError() == WSAECONNRESET )\r
559             return( MBEDTLS_ERR_NET_CONN_RESET );\r
560 #else\r
561         if( errno == EPIPE || errno == ECONNRESET )\r
562             return( MBEDTLS_ERR_NET_CONN_RESET );\r
563 \r
564         if( errno == EINTR )\r
565             return( MBEDTLS_ERR_SSL_WANT_READ );\r
566 #endif\r
567 \r
568         return( MBEDTLS_ERR_NET_RECV_FAILED );\r
569     }\r
570 \r
571     return( ret );\r
572 }\r
573 \r
574 /*\r
575  * Read at most 'len' characters, blocking for at most 'timeout' ms\r
576  */\r
577 int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf,\r
578                               size_t len, uint32_t timeout )\r
579 {\r
580     int ret;\r
581     struct timeval tv;\r
582     fd_set read_fds;\r
583     int fd = ((mbedtls_net_context *) ctx)->fd;\r
584 \r
585     if( fd < 0 )\r
586         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );\r
587 \r
588     FD_ZERO( &read_fds );\r
589     FD_SET( fd, &read_fds );\r
590 \r
591     tv.tv_sec  = timeout / 1000;\r
592     tv.tv_usec = ( timeout % 1000 ) * 1000;\r
593 \r
594     ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv );\r
595 \r
596     /* Zero fds ready means we timed out */\r
597     if( ret == 0 )\r
598         return( MBEDTLS_ERR_SSL_TIMEOUT );\r
599 \r
600     if( ret < 0 )\r
601     {\r
602 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
603     !defined(EFI32)\r
604         if( WSAGetLastError() == WSAEINTR )\r
605             return( MBEDTLS_ERR_SSL_WANT_READ );\r
606 #else\r
607         if( errno == EINTR )\r
608             return( MBEDTLS_ERR_SSL_WANT_READ );\r
609 #endif\r
610 \r
611         return( MBEDTLS_ERR_NET_RECV_FAILED );\r
612     }\r
613 \r
614     /* This call will not block */\r
615     return( mbedtls_net_recv( ctx, buf, len ) );\r
616 }\r
617 \r
618 /*\r
619  * Write at most 'len' characters\r
620  */\r
621 int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )\r
622 {\r
623     int ret;\r
624     int fd = ((mbedtls_net_context *) ctx)->fd;\r
625 \r
626     if( fd < 0 )\r
627         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );\r
628 \r
629     ret = (int) write( fd, buf, len );\r
630 \r
631     if( ret < 0 )\r
632     {\r
633         if( net_would_block( ctx ) != 0 )\r
634             return( MBEDTLS_ERR_SSL_WANT_WRITE );\r
635 \r
636 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \\r
637     !defined(EFI32)\r
638         if( WSAGetLastError() == WSAECONNRESET )\r
639             return( MBEDTLS_ERR_NET_CONN_RESET );\r
640 #else\r
641         if( errno == EPIPE || errno == ECONNRESET )\r
642             return( MBEDTLS_ERR_NET_CONN_RESET );\r
643 \r
644         if( errno == EINTR )\r
645             return( MBEDTLS_ERR_SSL_WANT_WRITE );\r
646 #endif\r
647 \r
648         return( MBEDTLS_ERR_NET_SEND_FAILED );\r
649     }\r
650 \r
651     return( ret );\r
652 }\r
653 \r
654 /*\r
655  * Gracefully close the connection\r
656  */\r
657 void mbedtls_net_free( mbedtls_net_context *ctx )\r
658 {\r
659     if( ctx->fd == -1 )\r
660         return;\r
661 \r
662     shutdown( ctx->fd, 2 );\r
663     close( ctx->fd );\r
664 \r
665     ctx->fd = -1;\r
666 }\r
667 \r
668 #endif /* MBEDTLS_NET_C */\r