2014-05-07 22:27:00 +00:00
/*
2016-07-08 08:42:24 +00:00
Copyright ( c ) 2009 - 2016 Roger Light < roger @ atchoo . org >
2014-05-07 22:27:00 +00:00
All rights reserved . This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1 .0
and Eclipse Distribution License v1 .0 which accompany this distribution .
The Eclipse Public License is available at
http : //www.eclipse.org/legal/epl-v10.html
and the Eclipse Distribution License is available at
http : //www.eclipse.org/org/documents/edl-v10.php.
Contributors :
Roger Light - initial implementation and documentation .
*/
# include <assert.h>
# include <errno.h>
# include <fcntl.h>
# include <stdio.h>
# include <string.h>
# ifndef WIN32
# include <netdb.h>
# include <sys/socket.h>
# include <unistd.h>
# else
# include <winsock2.h>
# include <ws2tcpip.h>
# endif
2014-11-12 20:47:16 +00:00
# ifdef __ANDROID__
2014-05-07 22:27:00 +00:00
# include <linux/in.h>
# include <linux/in6.h>
# include <sys/endian.h>
# endif
# ifdef __FreeBSD__
# include <netinet / in.h>
# endif
# ifdef __SYMBIAN32__
# include <netinet/in.h>
# endif
# ifdef __QNX__
# ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
# endif
# include <net/netbyte.h>
# include <netinet/in.h>
# endif
# ifdef WITH_TLS
2014-06-28 00:38:58 +00:00
# include <openssl/conf.h>
# include <openssl/engine.h>
2014-05-07 22:27:00 +00:00
# include <openssl/err.h>
# include <tls_mosq.h>
# endif
# ifdef WITH_BROKER
2016-07-08 09:10:04 +00:00
# include "mosquitto_broker_internal.h"
2014-05-06 09:47:00 +00:00
# ifdef WITH_WEBSOCKETS
# include <libwebsockets.h>
# endif
2014-05-07 22:27:00 +00:00
# else
2015-04-29 20:37:47 +00:00
# include "read_handle.h"
2014-05-07 22:27:00 +00:00
# endif
2015-04-29 20:37:47 +00:00
# include "logging_mosq.h"
# include "memory_mosq.h"
# include "mqtt3_protocol.h"
# include "net_mosq.h"
# include "time_mosq.h"
# include "util_mosq.h"
2014-05-07 22:27:00 +00:00
2015-05-21 16:15:33 +00:00
# include "config.h"
2015-04-29 20:23:59 +00:00
2014-05-07 22:27:00 +00:00
# ifdef WITH_TLS
int tls_ex_index_mosq = - 1 ;
# endif
2015-09-22 09:03:57 +00:00
int net__init ( void )
2014-05-07 22:27:00 +00:00
{
# ifdef WIN32
WSADATA wsaData ;
2015-09-22 09:03:57 +00:00
if ( WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsaData ) ! = 0 ) {
return MOSQ_ERR_UNKNOWN ;
}
2014-05-07 22:27:00 +00:00
# endif
# ifdef WITH_SRV
ares_library_init ( ARES_LIB_INIT_ALL ) ;
# endif
# ifdef WITH_TLS
SSL_load_error_strings ( ) ;
SSL_library_init ( ) ;
OpenSSL_add_all_algorithms ( ) ;
if ( tls_ex_index_mosq = = - 1 ) {
tls_ex_index_mosq = SSL_get_ex_new_index ( 0 , " client context " , NULL , NULL , NULL ) ;
}
# endif
2015-09-22 09:03:57 +00:00
return MOSQ_ERR_SUCCESS ;
2014-05-07 22:27:00 +00:00
}
2015-05-18 08:29:22 +00:00
void net__cleanup ( void )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
2014-06-28 00:38:58 +00:00
ERR_remove_state ( 0 ) ;
ENGINE_cleanup ( ) ;
CONF_modules_unload ( 1 ) ;
2014-05-07 22:27:00 +00:00
ERR_free_strings ( ) ;
EVP_cleanup ( ) ;
CRYPTO_cleanup_all_ex_data ( ) ;
# endif
# ifdef WITH_SRV
ares_library_cleanup ( ) ;
# endif
# ifdef WIN32
WSACleanup ( ) ;
# endif
}
/* Close a socket associated with a context and set it to -1.
* Returns 1 on failure ( context is NULL )
* Returns 0 on success .
*/
2014-06-23 16:57:35 +00:00
# ifdef WITH_BROKER
2015-05-18 08:29:22 +00:00
int net__socket_close ( struct mosquitto_db * db , struct mosquitto * mosq )
2014-06-23 16:57:35 +00:00
# else
2015-05-18 08:29:22 +00:00
int net__socket_close ( struct mosquitto * mosq )
2014-06-23 16:57:35 +00:00
# endif
2014-05-07 22:27:00 +00:00
{
int rc = 0 ;
assert ( mosq ) ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
SSL_shutdown ( mosq - > ssl ) ;
SSL_free ( mosq - > ssl ) ;
mosq - > ssl = NULL ;
}
if ( mosq - > ssl_ctx ) {
SSL_CTX_free ( mosq - > ssl_ctx ) ;
mosq - > ssl_ctx = NULL ;
}
# endif
2014-10-26 21:17:08 +00:00
if ( ( int ) mosq - > sock > = 0 ) {
2014-06-23 16:57:35 +00:00
# ifdef WITH_BROKER
HASH_DELETE ( hh_sock , db - > contexts_by_sock , mosq ) ;
# endif
2014-05-07 22:27:00 +00:00
rc = COMPAT_CLOSE ( mosq - > sock ) ;
mosq - > sock = INVALID_SOCKET ;
2014-06-29 22:16:10 +00:00
# ifdef WITH_WEBSOCKETS
} else if ( mosq - > sock = = WEBSOCKET_CLIENT ) {
if ( mosq - > state ! = mosq_cs_disconnecting ) {
mosq - > state = mosq_cs_disconnect_ws ;
}
2014-06-30 22:30:43 +00:00
if ( mosq - > wsi ) {
libwebsocket_callback_on_writable ( mosq - > ws_context , mosq - > wsi ) ;
}
2014-06-29 22:16:10 +00:00
mosq - > sock = INVALID_SOCKET ;
# endif
2014-05-07 22:27:00 +00:00
}
2014-06-03 15:21:46 +00:00
# ifdef WITH_BROKER
if ( mosq - > listener ) {
mosq - > listener - > client_count - - ;
assert ( mosq - > listener - > client_count > = 0 ) ;
mosq - > listener = NULL ;
}
# endif
2014-05-07 22:27:00 +00:00
return rc ;
}
2015-04-29 20:23:59 +00:00
2014-05-07 22:27:00 +00:00
# ifdef REAL_WITH_TLS_PSK
static unsigned int psk_client_callback ( SSL * ssl , const char * hint ,
char * identity , unsigned int max_identity_len ,
unsigned char * psk , unsigned int max_psk_len )
{
struct mosquitto * mosq ;
int len ;
mosq = SSL_get_ex_data ( ssl , tls_ex_index_mosq ) ;
if ( ! mosq ) return 0 ;
snprintf ( identity , max_identity_len , " %s " , mosq - > tls_psk_identity ) ;
2015-04-19 21:10:59 +00:00
len = mosquitto__hex2bin ( mosq - > tls_psk , psk , max_psk_len ) ;
2014-05-07 22:27:00 +00:00
if ( len < 0 ) return 0 ;
return len ;
}
# endif
2015-04-29 20:23:59 +00:00
2015-09-03 16:46:55 +00:00
int net__try_connect ( struct mosquitto * mosq , const char * host , uint16_t port , mosq_sock_t * sock , const char * bind_address , bool blocking )
2014-05-07 22:27:00 +00:00
{
struct addrinfo hints ;
struct addrinfo * ainfo , * rp ;
struct addrinfo * ainfo_bind , * rp_bind ;
int s ;
2014-10-24 20:28:24 +00:00
int rc = MOSQ_ERR_SUCCESS ;
2014-05-07 22:27:00 +00:00
# ifdef WIN32
uint32_t val = 1 ;
# endif
* sock = INVALID_SOCKET ;
memset ( & hints , 0 , sizeof ( struct addrinfo ) ) ;
2014-10-24 21:39:09 +00:00
# ifdef WITH_TLS
if ( mosq - > tls_cafile | | mosq - > tls_capath | | mosq - > tls_psk ) {
hints . ai_family = PF_INET ;
} else
# endif
{
hints . ai_family = PF_UNSPEC ;
}
2014-05-07 22:27:00 +00:00
hints . ai_flags = AI_ADDRCONFIG ;
hints . ai_socktype = SOCK_STREAM ;
s = getaddrinfo ( host , NULL , & hints , & ainfo ) ;
if ( s ) {
errno = s ;
return MOSQ_ERR_EAI ;
}
if ( bind_address ) {
s = getaddrinfo ( bind_address , NULL , & hints , & ainfo_bind ) ;
if ( s ) {
freeaddrinfo ( ainfo ) ;
errno = s ;
return MOSQ_ERR_EAI ;
}
}
for ( rp = ainfo ; rp ! = NULL ; rp = rp - > ai_next ) {
* sock = socket ( rp - > ai_family , rp - > ai_socktype , rp - > ai_protocol ) ;
if ( * sock = = INVALID_SOCKET ) continue ;
if ( rp - > ai_family = = PF_INET ) {
( ( struct sockaddr_in * ) rp - > ai_addr ) - > sin_port = htons ( port ) ;
} else if ( rp - > ai_family = = PF_INET6 ) {
( ( struct sockaddr_in6 * ) rp - > ai_addr ) - > sin6_port = htons ( port ) ;
} else {
2014-05-27 21:03:01 +00:00
COMPAT_CLOSE ( * sock ) ;
2014-05-07 22:27:00 +00:00
continue ;
}
if ( bind_address ) {
for ( rp_bind = ainfo_bind ; rp_bind ! = NULL ; rp_bind = rp_bind - > ai_next ) {
if ( bind ( * sock , rp_bind - > ai_addr , rp_bind - > ai_addrlen ) = = 0 ) {
break ;
}
}
if ( ! rp_bind ) {
COMPAT_CLOSE ( * sock ) ;
continue ;
}
}
if ( ! blocking ) {
/* Set non-blocking */
2015-05-18 08:29:22 +00:00
if ( net__socket_nonblock ( * sock ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( * sock ) ;
continue ;
}
}
rc = connect ( * sock , rp - > ai_addr , rp - > ai_addrlen ) ;
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( rc = = 0 | | errno = = EINPROGRESS | | errno = = COMPAT_EWOULDBLOCK ) {
2014-10-24 20:28:24 +00:00
if ( rc < 0 & & ( errno = = EINPROGRESS | | errno = = COMPAT_EWOULDBLOCK ) ) {
rc = MOSQ_ERR_CONN_PENDING ;
}
2014-05-07 22:27:00 +00:00
if ( blocking ) {
/* Set non-blocking */
2015-05-18 08:29:22 +00:00
if ( net__socket_nonblock ( * sock ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( * sock ) ;
continue ;
}
}
break ;
}
COMPAT_CLOSE ( * sock ) ;
* sock = INVALID_SOCKET ;
}
freeaddrinfo ( ainfo ) ;
if ( bind_address ) {
freeaddrinfo ( ainfo_bind ) ;
}
if ( ! rp ) {
return MOSQ_ERR_ERRNO ;
}
2014-10-24 20:28:24 +00:00
return rc ;
2014-05-07 22:27:00 +00:00
}
2015-04-29 20:23:59 +00:00
2015-01-27 23:33:36 +00:00
# ifdef WITH_TLS
2016-05-16 20:57:31 +00:00
void net__print_ssl_error ( struct mosquitto * mosq )
{
char ebuf [ 256 ] ;
unsigned long e ;
e = ERR_get_error ( ) ;
while ( e ) {
log__printf ( mosq , MOSQ_LOG_ERR , " OpenSSL Error: %s " , ERR_error_string ( e , ebuf ) ) ;
e = ERR_get_error ( ) ;
}
}
2015-05-18 08:29:22 +00:00
int net__socket_connect_tls ( struct mosquitto * mosq )
2015-01-27 23:33:36 +00:00
{
2016-05-14 20:45:02 +00:00
int ret , err ;
2015-01-27 23:33:36 +00:00
ret = SSL_connect ( mosq - > ssl ) ;
2016-05-14 20:45:02 +00:00
if ( ret ! = 1 ) {
err = SSL_get_error ( mosq - > ssl , ret ) ;
# ifdef WIN32
if ( err = = SSL_ERROR_SYSCALL ) {
mosq - > want_connect = true ;
return MOSQ_ERR_SUCCESS ;
}
# endif
if ( err = = SSL_ERROR_WANT_READ ) {
2015-01-27 23:33:36 +00:00
mosq - > want_connect = true ;
/* We always try to read anyway */
2016-05-14 20:45:02 +00:00
} else if ( err = = SSL_ERROR_WANT_WRITE ) {
2015-01-27 23:33:36 +00:00
mosq - > want_write = true ;
mosq - > want_connect = true ;
} else {
COMPAT_CLOSE ( mosq - > sock ) ;
mosq - > sock = INVALID_SOCKET ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2015-01-27 23:33:36 +00:00
return MOSQ_ERR_TLS ;
}
} else {
mosq - > want_connect = false ;
}
return MOSQ_ERR_SUCCESS ;
}
# endif
2015-04-29 20:23:59 +00:00
2014-05-07 22:27:00 +00:00
/* Create a socket and connect it to 'ip' on port 'port'.
* Returns - 1 on failure ( ip is NULL , socket creation / connection error )
* Returns sock number on success .
*/
2015-05-18 08:29:22 +00:00
int net__socket_connect ( struct mosquitto * mosq , const char * host , uint16_t port , const char * bind_address , bool blocking )
2014-05-07 22:27:00 +00:00
{
2015-03-29 09:43:08 +00:00
mosq_sock_t sock = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
int rc ;
# ifdef WITH_TLS
int ret ;
BIO * bio ;
# endif
if ( ! mosq | | ! host | | ! port ) return MOSQ_ERR_INVAL ;
2015-05-18 08:29:22 +00:00
rc = net__try_connect ( mosq , host , port , & sock , bind_address , blocking ) ;
2014-10-24 20:28:24 +00:00
if ( rc > 0 ) return rc ;
2014-05-07 22:27:00 +00:00
# ifdef WITH_TLS
if ( mosq - > tls_cafile | | mosq - > tls_capath | | mosq - > tls_psk ) {
# if OPENSSL_VERSION_NUMBER >= 0x10001000L
2016-02-09 23:02:46 +00:00
if ( ! mosq - > tls_version ) {
mosq - > ssl_ctx = SSL_CTX_new ( SSLv23_client_method ( ) ) ;
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.2 " ) ) {
2014-05-07 22:27:00 +00:00
mosq - > ssl_ctx = SSL_CTX_new ( TLSv1_2_client_method ( ) ) ;
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1.1 " ) ) {
mosq - > ssl_ctx = SSL_CTX_new ( TLSv1_1_client_method ( ) ) ;
} else if ( ! strcmp ( mosq - > tls_version , " tlsv1 " ) ) {
mosq - > ssl_ctx = SSL_CTX_new ( TLSv1_client_method ( ) ) ;
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Protocol %s not supported. " , mosq - > tls_version ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sock ) ;
return MOSQ_ERR_INVAL ;
}
# else
if ( ! mosq - > tls_version | | ! strcmp ( mosq - > tls_version , " tlsv1 " ) ) {
mosq - > ssl_ctx = SSL_CTX_new ( TLSv1_client_method ( ) ) ;
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Protocol %s not supported. " , mosq - > tls_version ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sock ) ;
return MOSQ_ERR_INVAL ;
}
# endif
if ( ! mosq - > ssl_ctx ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to create TLS context. " ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
# if OPENSSL_VERSION_NUMBER >= 0x10000000
/* Disable compression */
SSL_CTX_set_options ( mosq - > ssl_ctx , SSL_OP_NO_COMPRESSION ) ;
# endif
# ifdef SSL_MODE_RELEASE_BUFFERS
/* Use even less memory per SSL connection. */
SSL_CTX_set_mode ( mosq - > ssl_ctx , SSL_MODE_RELEASE_BUFFERS ) ;
# endif
if ( mosq - > tls_ciphers ) {
ret = SSL_CTX_set_cipher_list ( mosq - > ssl_ctx , mosq - > tls_ciphers ) ;
if ( ret = = 0 ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to set TLS ciphers. Check cipher list \" %s \" . " , mosq - > tls_ciphers ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
}
if ( mosq - > tls_cafile | | mosq - > tls_capath ) {
ret = SSL_CTX_load_verify_locations ( mosq - > ssl_ctx , mosq - > tls_cafile , mosq - > tls_capath ) ;
if ( ret = = 0 ) {
# ifdef WITH_BROKER
if ( mosq - > tls_cafile & & mosq - > tls_capath ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_cafile \" %s \" and bridge_capath \" %s \" . " , mosq - > tls_cafile , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
} else if ( mosq - > tls_cafile ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_cafile \" %s \" . " , mosq - > tls_cafile ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check bridge_capath \" %s \" . " , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
}
# else
if ( mosq - > tls_cafile & & mosq - > tls_capath ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" and capath \" %s \" . " , mosq - > tls_cafile , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
} else if ( mosq - > tls_cafile ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check cafile \" %s \" . " , mosq - > tls_cafile ) ;
2014-05-07 22:27:00 +00:00
} else {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load CA certificates, check capath \" %s \" . " , mosq - > tls_capath ) ;
2014-05-07 22:27:00 +00:00
}
# endif
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
if ( mosq - > tls_cert_reqs = = 0 ) {
SSL_CTX_set_verify ( mosq - > ssl_ctx , SSL_VERIFY_NONE , NULL ) ;
} else {
2015-04-19 21:10:59 +00:00
SSL_CTX_set_verify ( mosq - > ssl_ctx , SSL_VERIFY_PEER , mosquitto__server_certificate_verify ) ;
2014-05-07 22:27:00 +00:00
}
if ( mosq - > tls_pw_callback ) {
SSL_CTX_set_default_passwd_cb ( mosq - > ssl_ctx , mosq - > tls_pw_callback ) ;
SSL_CTX_set_default_passwd_cb_userdata ( mosq - > ssl_ctx , mosq ) ;
}
if ( mosq - > tls_certfile ) {
ret = SSL_CTX_use_certificate_chain_file ( mosq - > ssl_ctx , mosq - > tls_certfile ) ;
if ( ret ! = 1 ) {
# ifdef WITH_BROKER
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client certificate, check bridge_certfile \" %s \" . " , mosq - > tls_certfile ) ;
2014-05-07 22:27:00 +00:00
# else
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client certificate \" %s \" . " , mosq - > tls_certfile ) ;
2014-05-07 22:27:00 +00:00
# endif
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
}
if ( mosq - > tls_keyfile ) {
ret = SSL_CTX_use_PrivateKey_file ( mosq - > ssl_ctx , mosq - > tls_keyfile , SSL_FILETYPE_PEM ) ;
if ( ret ! = 1 ) {
# ifdef WITH_BROKER
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client key file, check bridge_keyfile \" %s \" . " , mosq - > tls_keyfile ) ;
2014-05-07 22:27:00 +00:00
# else
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Unable to load client key file \" %s \" . " , mosq - > tls_keyfile ) ;
2014-05-07 22:27:00 +00:00
# endif
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
ret = SSL_CTX_check_private_key ( mosq - > ssl_ctx ) ;
if ( ret ! = 1 ) {
2015-05-18 07:53:21 +00:00
log__printf ( mosq , MOSQ_LOG_ERR , " Error: Client certificate/key are inconsistent. " ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
}
# ifdef REAL_WITH_TLS_PSK
} else if ( mosq - > tls_psk ) {
SSL_CTX_set_psk_client_callback ( mosq - > ssl_ctx , psk_client_callback ) ;
# endif
}
mosq - > ssl = SSL_new ( mosq - > ssl_ctx ) ;
if ( ! mosq - > ssl ) {
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
SSL_set_ex_data ( mosq - > ssl , tls_ex_index_mosq , mosq ) ;
bio = BIO_new_socket ( sock , BIO_NOCLOSE ) ;
if ( ! bio ) {
COMPAT_CLOSE ( sock ) ;
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_TLS ;
}
SSL_set_bio ( mosq - > ssl , bio , bio ) ;
2015-01-27 23:33:36 +00:00
mosq - > sock = sock ;
2015-05-18 08:29:22 +00:00
if ( net__socket_connect_tls ( mosq ) ) {
2015-01-27 23:33:36 +00:00
return MOSQ_ERR_TLS ;
2014-05-07 22:27:00 +00:00
}
2015-01-27 23:33:36 +00:00
2014-05-07 22:27:00 +00:00
}
# endif
mosq - > sock = sock ;
2014-10-24 20:28:24 +00:00
return rc ;
2014-05-07 22:27:00 +00:00
}
2015-05-18 08:29:22 +00:00
ssize_t net__read ( struct mosquitto * mosq , void * buf , size_t count )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
int ret ;
int err ;
# endif
assert ( mosq ) ;
errno = 0 ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
ret = SSL_read ( mosq - > ssl , buf , count ) ;
if ( ret < = 0 ) {
err = SSL_get_error ( mosq - > ssl , ret ) ;
if ( err = = SSL_ERROR_WANT_READ ) {
ret = - 1 ;
errno = EAGAIN ;
} else if ( err = = SSL_ERROR_WANT_WRITE ) {
ret = - 1 ;
mosq - > want_write = true ;
errno = EAGAIN ;
} else {
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
errno = EPROTO ;
}
}
return ( ssize_t ) ret ;
} else {
/* Call normal read/recv */
# endif
# ifndef WIN32
return read ( mosq - > sock , buf , count ) ;
# else
return recv ( mosq - > sock , buf , count , 0 ) ;
# endif
# ifdef WITH_TLS
}
# endif
}
2015-05-18 08:29:22 +00:00
ssize_t net__write ( struct mosquitto * mosq , void * buf , size_t count )
2014-05-07 22:27:00 +00:00
{
# ifdef WITH_TLS
int ret ;
int err ;
# endif
assert ( mosq ) ;
errno = 0 ;
# ifdef WITH_TLS
if ( mosq - > ssl ) {
2016-01-13 21:32:01 +00:00
mosq - > want_write = false ;
2014-05-07 22:27:00 +00:00
ret = SSL_write ( mosq - > ssl , buf , count ) ;
if ( ret < 0 ) {
err = SSL_get_error ( mosq - > ssl , ret ) ;
if ( err = = SSL_ERROR_WANT_READ ) {
ret = - 1 ;
errno = EAGAIN ;
} else if ( err = = SSL_ERROR_WANT_WRITE ) {
ret = - 1 ;
mosq - > want_write = true ;
errno = EAGAIN ;
} else {
2016-05-16 20:57:31 +00:00
net__print_ssl_error ( mosq ) ;
2014-05-07 22:27:00 +00:00
errno = EPROTO ;
}
}
return ( ssize_t ) ret ;
} else {
/* Call normal write/send */
# endif
# ifndef WIN32
return write ( mosq - > sock , buf , count ) ;
# else
return send ( mosq - > sock , buf , count , 0 ) ;
# endif
# ifdef WITH_TLS
}
# endif
}
2015-05-18 08:29:22 +00:00
int net__socket_nonblock ( int sock )
2014-05-07 22:27:00 +00:00
{
# ifndef WIN32
int opt ;
/* Set non-blocking */
opt = fcntl ( sock , F_GETFL , 0 ) ;
if ( opt = = - 1 ) {
COMPAT_CLOSE ( sock ) ;
return 1 ;
}
if ( fcntl ( sock , F_SETFL , opt | O_NONBLOCK ) = = - 1 ) {
/* If either fcntl fails, don't want to allow this client to connect. */
COMPAT_CLOSE ( sock ) ;
return 1 ;
}
# else
2014-07-22 09:28:55 +00:00
unsigned long opt = 1 ;
2014-05-07 22:27:00 +00:00
if ( ioctlsocket ( sock , FIONBIO , & opt ) ) {
COMPAT_CLOSE ( sock ) ;
return 1 ;
}
# endif
return 0 ;
}
# ifndef WITH_BROKER
2015-09-03 16:46:55 +00:00
int net__socketpair ( mosq_sock_t * pairR , mosq_sock_t * pairW )
2014-05-07 22:27:00 +00:00
{
# ifdef WIN32
int family [ 2 ] = { AF_INET , AF_INET6 } ;
int i ;
struct sockaddr_storage ss ;
struct sockaddr_in * sa = ( struct sockaddr_in * ) & ss ;
struct sockaddr_in6 * sa6 = ( struct sockaddr_in6 * ) & ss ;
socklen_t ss_len ;
2015-03-29 09:43:08 +00:00
mosq_sock_t spR , spW ;
2014-05-07 22:27:00 +00:00
2015-03-29 09:43:08 +00:00
mosq_sock_t listensock ;
2014-05-07 22:27:00 +00:00
2015-03-29 09:43:08 +00:00
* pairR = INVALID_SOCKET ;
* pairW = INVALID_SOCKET ;
2014-05-07 22:27:00 +00:00
for ( i = 0 ; i < 2 ; i + + ) {
memset ( & ss , 0 , sizeof ( ss ) ) ;
if ( family [ i ] = = AF_INET ) {
sa - > sin_family = family [ i ] ;
sa - > sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
sa - > sin_port = 0 ;
ss_len = sizeof ( struct sockaddr_in ) ;
} else if ( family [ i ] = = AF_INET6 ) {
sa6 - > sin6_family = family [ i ] ;
sa6 - > sin6_addr = in6addr_loopback ;
sa6 - > sin6_port = 0 ;
ss_len = sizeof ( struct sockaddr_in6 ) ;
} else {
return MOSQ_ERR_INVAL ;
}
listensock = socket ( family [ i ] , SOCK_STREAM , IPPROTO_TCP ) ;
if ( listensock = = - 1 ) {
continue ;
}
if ( bind ( listensock , ( struct sockaddr * ) & ss , ss_len ) = = - 1 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
if ( listen ( listensock , 1 ) = = - 1 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
memset ( & ss , 0 , sizeof ( ss ) ) ;
ss_len = sizeof ( ss ) ;
if ( getsockname ( listensock , ( struct sockaddr * ) & ss , & ss_len ) < 0 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
if ( family [ i ] = = AF_INET ) {
sa - > sin_family = family [ i ] ;
sa - > sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
ss_len = sizeof ( struct sockaddr_in ) ;
} else if ( family [ i ] = = AF_INET6 ) {
sa6 - > sin6_family = family [ i ] ;
sa6 - > sin6_addr = in6addr_loopback ;
ss_len = sizeof ( struct sockaddr_in6 ) ;
}
spR = socket ( family [ i ] , SOCK_STREAM , IPPROTO_TCP ) ;
if ( spR = = - 1 ) {
COMPAT_CLOSE ( listensock ) ;
continue ;
}
2015-05-18 08:29:22 +00:00
if ( net__socket_nonblock ( spR ) ) {
2015-12-18 21:58:38 +00:00
COMPAT_CLOSE ( spR ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( listensock ) ;
continue ;
}
if ( connect ( spR , ( struct sockaddr * ) & ss , ss_len ) < 0 ) {
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( errno ! = EINPROGRESS & & errno ! = COMPAT_EWOULDBLOCK ) {
COMPAT_CLOSE ( spR ) ;
COMPAT_CLOSE ( listensock ) ;
continue ;
}
}
spW = accept ( listensock , NULL , 0 ) ;
if ( spW = = - 1 ) {
# ifdef WIN32
errno = WSAGetLastError ( ) ;
# endif
if ( errno ! = EINPROGRESS & & errno ! = COMPAT_EWOULDBLOCK ) {
COMPAT_CLOSE ( spR ) ;
COMPAT_CLOSE ( listensock ) ;
continue ;
}
}
2015-05-18 08:29:22 +00:00
if ( net__socket_nonblock ( spW ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( spR ) ;
2015-12-18 21:58:38 +00:00
COMPAT_CLOSE ( spW ) ;
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( listensock ) ;
continue ;
}
COMPAT_CLOSE ( listensock ) ;
* pairR = spR ;
* pairW = spW ;
return MOSQ_ERR_SUCCESS ;
}
return MOSQ_ERR_UNKNOWN ;
# else
int sv [ 2 ] ;
if ( socketpair ( AF_UNIX , SOCK_STREAM , 0 , sv ) = = - 1 ) {
return MOSQ_ERR_ERRNO ;
}
2015-05-18 08:29:22 +00:00
if ( net__socket_nonblock ( sv [ 0 ] ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sv [ 0 ] ) ;
COMPAT_CLOSE ( sv [ 1 ] ) ;
return MOSQ_ERR_ERRNO ;
}
2015-05-18 08:29:22 +00:00
if ( net__socket_nonblock ( sv [ 1 ] ) ) {
2014-05-07 22:27:00 +00:00
COMPAT_CLOSE ( sv [ 0 ] ) ;
COMPAT_CLOSE ( sv [ 1 ] ) ;
return MOSQ_ERR_ERRNO ;
}
* pairR = sv [ 0 ] ;
* pairW = sv [ 1 ] ;
return MOSQ_ERR_SUCCESS ;
# endif
}
# endif