mbedtls ported to mbed-classic
Fork of mbedtls by
Embed:
(wiki syntax)
Show/hide line numbers
net.c
00001 /* 00002 * TCP/IP or UDP/IP networking functions 00003 * 00004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved 00005 * SPDX-License-Identifier: Apache-2.0 00006 * 00007 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00008 * not use this file except in compliance with the License. 00009 * You may obtain a copy of the License at 00010 * 00011 * http://www.apache.org/licenses/LICENSE-2.0 00012 * 00013 * Unless required by applicable law or agreed to in writing, software 00014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00016 * See the License for the specific language governing permissions and 00017 * limitations under the License. 00018 * 00019 * This file is part of mbed TLS (https://tls.mbed.org) 00020 */ 00021 00022 #if !defined(MBEDTLS_CONFIG_FILE) 00023 #include "mbedtls/config.h" 00024 #else 00025 #include MBEDTLS_CONFIG_FILE 00026 #endif 00027 00028 #if defined(MBEDTLS_NET_C) 00029 00030 #include "mbedtls/net.h" 00031 00032 #include <string.h> 00033 00034 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 00035 !defined(EFI32) 00036 00037 #ifdef _WIN32_WINNT 00038 #undef _WIN32_WINNT 00039 #endif 00040 /* Enables getaddrinfo() & Co */ 00041 #define _WIN32_WINNT 0x0501 00042 #include <ws2tcpip.h> 00043 00044 #include <winsock2.h> 00045 #include <windows.h> 00046 00047 #if defined(_MSC_VER) 00048 #if defined(_WIN32_WCE) 00049 #pragma comment( lib, "ws2.lib" ) 00050 #else 00051 #pragma comment( lib, "ws2_32.lib" ) 00052 #endif 00053 #endif /* _MSC_VER */ 00054 00055 #define read(fd,buf,len) recv(fd,(char*)buf,(int) len,0) 00056 #define write(fd,buf,len) send(fd,(char*)buf,(int) len,0) 00057 #define close(fd) closesocket(fd) 00058 00059 static int wsa_init_done = 0; 00060 00061 #else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ 00062 00063 #include <sys/types.h> 00064 #include <sys/socket.h> 00065 #include <netinet/in.h> 00066 #include <arpa/inet.h> 00067 #include <sys/time.h> 00068 #include <unistd.h> 00069 #include <signal.h> 00070 #include <fcntl.h> 00071 #include <netdb.h> 00072 #include <errno.h> 00073 00074 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ 00075 00076 /* Some MS functions want int and MSVC warns if we pass size_t, 00077 * but the standard fucntions use socklen_t, so cast only for MSVC */ 00078 #if defined(_MSC_VER) 00079 #define MSVC_INT_CAST (int) 00080 #else 00081 #define MSVC_INT_CAST 00082 #endif 00083 00084 #include <stdlib.h> 00085 #include <stdio.h> 00086 00087 #include <time.h> 00088 00089 #include <stdint.h> 00090 00091 /* 00092 * Prepare for using the sockets interface 00093 */ 00094 static int net_prepare( void ) 00095 { 00096 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00097 !defined(EFI32) 00098 WSADATA wsaData; 00099 00100 if( wsa_init_done == 0 ) 00101 { 00102 if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) 00103 return( MBEDTLS_ERR_NET_SOCKET_FAILED ); 00104 00105 wsa_init_done = 1; 00106 } 00107 #else 00108 #if !defined(EFIX64) && !defined(EFI32) 00109 signal( SIGPIPE, SIG_IGN ); 00110 #endif 00111 #endif 00112 return( 0 ); 00113 } 00114 00115 /* 00116 * Initialize a context 00117 */ 00118 void mbedtls_net_init( mbedtls_net_context *ctx ) 00119 { 00120 ctx->fd = -1; 00121 } 00122 00123 /* 00124 * Initiate a TCP connection with host:port and the given protocol 00125 */ 00126 int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ) 00127 { 00128 int ret; 00129 struct addrinfo hints, *addr_list, *cur; 00130 00131 if( ( ret = net_prepare() ) != 0 ) 00132 return( ret ); 00133 00134 /* Do name resolution with both IPv6 and IPv4 */ 00135 memset( &hints, 0, sizeof( hints ) ); 00136 hints.ai_family = AF_UNSPEC; 00137 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; 00138 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; 00139 00140 if( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) 00141 return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); 00142 00143 /* Try the sockaddrs until a connection succeeds */ 00144 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; 00145 for( cur = addr_list; cur != NULL; cur = cur->ai_next ) 00146 { 00147 ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, 00148 cur->ai_protocol ); 00149 if( ctx->fd < 0 ) 00150 { 00151 ret = MBEDTLS_ERR_NET_SOCKET_FAILED; 00152 continue; 00153 } 00154 00155 if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 ) 00156 { 00157 ret = 0; 00158 break; 00159 } 00160 00161 close( ctx->fd ); 00162 ret = MBEDTLS_ERR_NET_CONNECT_FAILED; 00163 } 00164 00165 freeaddrinfo( addr_list ); 00166 00167 return( ret ); 00168 } 00169 00170 /* 00171 * Create a listening socket on bind_ip:port 00172 */ 00173 int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) 00174 { 00175 int n, ret; 00176 struct addrinfo hints, *addr_list, *cur; 00177 00178 if( ( ret = net_prepare() ) != 0 ) 00179 return( ret ); 00180 00181 /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ 00182 memset( &hints, 0, sizeof( hints ) ); 00183 hints.ai_family = AF_UNSPEC; 00184 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; 00185 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; 00186 if( bind_ip == NULL ) 00187 hints.ai_flags = AI_PASSIVE; 00188 00189 if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) 00190 return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); 00191 00192 /* Try the sockaddrs until a binding succeeds */ 00193 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; 00194 for( cur = addr_list; cur != NULL; cur = cur->ai_next ) 00195 { 00196 ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, 00197 cur->ai_protocol ); 00198 if( ctx->fd < 0 ) 00199 { 00200 ret = MBEDTLS_ERR_NET_SOCKET_FAILED; 00201 continue; 00202 } 00203 00204 n = 1; 00205 if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR, 00206 (const char *) &n, sizeof( n ) ) != 0 ) 00207 { 00208 close( ctx->fd ); 00209 ret = MBEDTLS_ERR_NET_SOCKET_FAILED; 00210 continue; 00211 } 00212 00213 if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 ) 00214 { 00215 close( ctx->fd ); 00216 ret = MBEDTLS_ERR_NET_BIND_FAILED; 00217 continue; 00218 } 00219 00220 /* Listen only makes sense for TCP */ 00221 if( proto == MBEDTLS_NET_PROTO_TCP ) 00222 { 00223 if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) 00224 { 00225 close( ctx->fd ); 00226 ret = MBEDTLS_ERR_NET_LISTEN_FAILED; 00227 continue; 00228 } 00229 } 00230 00231 /* I we ever get there, it's a success */ 00232 ret = 0; 00233 break; 00234 } 00235 00236 freeaddrinfo( addr_list ); 00237 00238 return( ret ); 00239 00240 } 00241 00242 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00243 !defined(EFI32) 00244 /* 00245 * Check if the requested operation would be blocking on a non-blocking socket 00246 * and thus 'failed' with a negative return value. 00247 */ 00248 static int net_would_block( const mbedtls_net_context *ctx ) 00249 { 00250 ((void) ctx); 00251 return( WSAGetLastError() == WSAEWOULDBLOCK ); 00252 } 00253 #else 00254 /* 00255 * Check if the requested operation would be blocking on a non-blocking socket 00256 * and thus 'failed' with a negative return value. 00257 * 00258 * Note: on a blocking socket this function always returns 0! 00259 */ 00260 static int net_would_block( const mbedtls_net_context *ctx ) 00261 { 00262 /* 00263 * Never return 'WOULD BLOCK' on a non-blocking socket 00264 */ 00265 if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) 00266 return( 0 ); 00267 00268 switch( errno ) 00269 { 00270 #if defined EAGAIN 00271 case EAGAIN: 00272 #endif 00273 #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN 00274 case EWOULDBLOCK: 00275 #endif 00276 return( 1 ); 00277 } 00278 return( 0 ); 00279 } 00280 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ 00281 00282 /* 00283 * Accept a connection from a remote client 00284 */ 00285 int mbedtls_net_accept( mbedtls_net_context *bind_ctx, 00286 mbedtls_net_context *client_ctx, 00287 void *client_ip, size_t buf_size, size_t *ip_len ) 00288 { 00289 int ret; 00290 int type; 00291 00292 struct sockaddr_storage client_addr; 00293 00294 #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ 00295 defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) 00296 socklen_t n = (socklen_t) sizeof( client_addr ); 00297 socklen_t type_len = (socklen_t) sizeof( type ); 00298 #else 00299 int n = (int) sizeof( client_addr ); 00300 int type_len = (int) sizeof( type ); 00301 #endif 00302 00303 /* Is this a TCP or UDP socket? */ 00304 if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, 00305 (void *) &type, &type_len ) != 0 || 00306 ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) 00307 { 00308 return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); 00309 } 00310 00311 if( type == SOCK_STREAM ) 00312 { 00313 /* TCP: actual accept() */ 00314 ret = client_ctx->fd = (int) accept( bind_ctx->fd, 00315 (struct sockaddr *) &client_addr, &n ); 00316 } 00317 else 00318 { 00319 /* UDP: wait for a message, but keep it in the queue */ 00320 char buf[1] = { 0 }; 00321 00322 ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, 00323 (struct sockaddr *) &client_addr, &n ); 00324 00325 #if defined(_WIN32) 00326 if( ret == SOCKET_ERROR && 00327 WSAGetLastError() == WSAEMSGSIZE ) 00328 { 00329 /* We know buf is too small, thanks, just peeking here */ 00330 ret = 0; 00331 } 00332 #endif 00333 } 00334 00335 if( ret < 0 ) 00336 { 00337 if( net_would_block( bind_ctx ) != 0 ) 00338 return( MBEDTLS_ERR_SSL_WANT_READ ); 00339 00340 return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); 00341 } 00342 00343 /* UDP: hijack the listening socket to communicate with the client, 00344 * then bind a new socket to accept new connections */ 00345 if( type != SOCK_STREAM ) 00346 { 00347 struct sockaddr_storage local_addr; 00348 int one = 1; 00349 00350 if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) 00351 return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); 00352 00353 client_ctx->fd = bind_ctx->fd; 00354 bind_ctx->fd = -1; /* In case we exit early */ 00355 00356 n = sizeof( struct sockaddr_storage ); 00357 if( getsockname( client_ctx->fd, 00358 (struct sockaddr *) &local_addr, &n ) != 0 || 00359 ( bind_ctx->fd = (int) socket( local_addr.ss_family, 00360 SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || 00361 setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, 00362 (const char *) &one, sizeof( one ) ) != 0 ) 00363 { 00364 return( MBEDTLS_ERR_NET_SOCKET_FAILED ); 00365 } 00366 00367 if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) 00368 { 00369 return( MBEDTLS_ERR_NET_BIND_FAILED ); 00370 } 00371 } 00372 00373 if( client_ip != NULL ) 00374 { 00375 if( client_addr.ss_family == AF_INET ) 00376 { 00377 struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; 00378 *ip_len = sizeof( addr4->sin_addr.s_addr ); 00379 00380 if( buf_size < *ip_len ) 00381 return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); 00382 00383 memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); 00384 } 00385 else 00386 { 00387 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; 00388 *ip_len = sizeof( addr6->sin6_addr.s6_addr ); 00389 00390 if( buf_size < *ip_len ) 00391 return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); 00392 00393 memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); 00394 } 00395 } 00396 00397 return( 0 ); 00398 } 00399 00400 /* 00401 * Set the socket blocking or non-blocking 00402 */ 00403 int mbedtls_net_set_block( mbedtls_net_context *ctx ) 00404 { 00405 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00406 !defined(EFI32) 00407 u_long n = 0; 00408 return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); 00409 #else 00410 return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) ); 00411 #endif 00412 } 00413 00414 int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) 00415 { 00416 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00417 !defined(EFI32) 00418 u_long n = 1; 00419 return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); 00420 #else 00421 return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) ); 00422 #endif 00423 } 00424 00425 /* 00426 * Portable usleep helper 00427 */ 00428 void mbedtls_net_usleep( unsigned long usec ) 00429 { 00430 #if defined(_WIN32) 00431 Sleep( ( usec + 999 ) / 1000 ); 00432 #else 00433 struct timeval tv; 00434 tv.tv_sec = usec / 1000000; 00435 #if defined(__unix__) || defined(__unix) || \ 00436 ( defined(__APPLE__) && defined(__MACH__) ) 00437 tv.tv_usec = (suseconds_t) usec % 1000000; 00438 #else 00439 tv.tv_usec = usec % 1000000; 00440 #endif 00441 select( 0, NULL, NULL, NULL, &tv ); 00442 #endif 00443 } 00444 00445 /* 00446 * Read at most 'len' characters 00447 */ 00448 int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) 00449 { 00450 int ret; 00451 int fd = ((mbedtls_net_context *) ctx)->fd; 00452 00453 if( fd < 0 ) 00454 return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); 00455 00456 ret = (int) read( fd, buf, len ); 00457 00458 if( ret < 0 ) 00459 { 00460 if( net_would_block( ctx ) != 0 ) 00461 return( MBEDTLS_ERR_SSL_WANT_READ ); 00462 00463 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00464 !defined(EFI32) 00465 if( WSAGetLastError() == WSAECONNRESET ) 00466 return( MBEDTLS_ERR_NET_CONN_RESET ); 00467 #else 00468 if( errno == EPIPE || errno == ECONNRESET ) 00469 return( MBEDTLS_ERR_NET_CONN_RESET ); 00470 00471 if( errno == EINTR ) 00472 return( MBEDTLS_ERR_SSL_WANT_READ ); 00473 #endif 00474 00475 return( MBEDTLS_ERR_NET_RECV_FAILED ); 00476 } 00477 00478 return( ret ); 00479 } 00480 00481 /* 00482 * Read at most 'len' characters, blocking for at most 'timeout' ms 00483 */ 00484 int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, 00485 uint32_t timeout ) 00486 { 00487 int ret; 00488 struct timeval tv; 00489 fd_set read_fds; 00490 int fd = ((mbedtls_net_context *) ctx)->fd; 00491 00492 if( fd < 0 ) 00493 return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); 00494 00495 FD_ZERO( &read_fds ); 00496 FD_SET( fd, &read_fds ); 00497 00498 tv.tv_sec = timeout / 1000; 00499 tv.tv_usec = ( timeout % 1000 ) * 1000; 00500 00501 ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); 00502 00503 /* Zero fds ready means we timed out */ 00504 if( ret == 0 ) 00505 return( MBEDTLS_ERR_SSL_TIMEOUT ); 00506 00507 if( ret < 0 ) 00508 { 00509 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00510 !defined(EFI32) 00511 if( WSAGetLastError() == WSAEINTR ) 00512 return( MBEDTLS_ERR_SSL_WANT_READ ); 00513 #else 00514 if( errno == EINTR ) 00515 return( MBEDTLS_ERR_SSL_WANT_READ ); 00516 #endif 00517 00518 return( MBEDTLS_ERR_NET_RECV_FAILED ); 00519 } 00520 00521 /* This call will not block */ 00522 return( mbedtls_net_recv( ctx, buf, len ) ); 00523 } 00524 00525 /* 00526 * Write at most 'len' characters 00527 */ 00528 int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) 00529 { 00530 int ret; 00531 int fd = ((mbedtls_net_context *) ctx)->fd; 00532 00533 if( fd < 0 ) 00534 return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); 00535 00536 ret = (int) write( fd, buf, len ); 00537 00538 if( ret < 0 ) 00539 { 00540 if( net_would_block( ctx ) != 0 ) 00541 return( MBEDTLS_ERR_SSL_WANT_WRITE ); 00542 00543 #if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ 00544 !defined(EFI32) 00545 if( WSAGetLastError() == WSAECONNRESET ) 00546 return( MBEDTLS_ERR_NET_CONN_RESET ); 00547 #else 00548 if( errno == EPIPE || errno == ECONNRESET ) 00549 return( MBEDTLS_ERR_NET_CONN_RESET ); 00550 00551 if( errno == EINTR ) 00552 return( MBEDTLS_ERR_SSL_WANT_WRITE ); 00553 #endif 00554 00555 return( MBEDTLS_ERR_NET_SEND_FAILED ); 00556 } 00557 00558 return( ret ); 00559 } 00560 00561 /* 00562 * Gracefully close the connection 00563 */ 00564 void mbedtls_net_free( mbedtls_net_context *ctx ) 00565 { 00566 if( ctx->fd == -1 ) 00567 return; 00568 00569 shutdown( ctx->fd, 2 ); 00570 close( ctx->fd ); 00571 00572 ctx->fd = -1; 00573 } 00574 00575 #endif /* MBEDTLS_NET_C */
Generated on Tue Jul 12 2022 12:52:45 by 1.7.2