static int _mosquitto_reconnect(struct mosquitto *mosq, bool blocking) { int rc; struct _mosquitto_packet *packet; if(!mosq) return MOSQ_ERR_INVAL; if(!mosq->host || mosq->port <= 0) return MOSQ_ERR_INVAL; pthread_mutex_lock(&mosq->state_mutex); #ifdef WITH_SOCKS if(mosq->socks5_host){ mosq->state = mosq_cs_socks5_new; }else #endif { mosq->state = mosq_cs_new; } pthread_mutex_unlock(&mosq->state_mutex); pthread_mutex_lock(&mosq->msgtime_mutex); mosq->last_msg_in = mosquitto_time(); mosq->last_msg_out = mosquitto_time(); pthread_mutex_unlock(&mosq->msgtime_mutex); mosq->ping_t = 0; _mosquitto_packet_cleanup(&mosq->in_packet); pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; } while(mosq->current_out_packet){ packet = mosq->current_out_packet; /* Free data and reset values */ mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; } _mosquitto_packet_cleanup(packet); _mosquitto_free(packet); } pthread_mutex_unlock(&mosq->out_packet_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); _mosquitto_messages_reconnect_reset(mosq); #ifdef WITH_SOCKS if(mosq->socks5_host){ rc = _mosquitto_socket_connect(mosq, mosq->socks5_host, mosq->socks5_port, mosq->bind_address, blocking); }else #endif { rc = _mosquitto_socket_connect(mosq, mosq->host, mosq->port, mosq->bind_address, blocking); } if(rc>0){ return rc; } #ifdef WITH_SOCKS if(mosq->socks5_host){ return mosquitto__socks5_send(mosq); }else #endif { return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session); } }
int mosquitto__socks5_read(struct mosquitto *mosq) { ssize_t len; uint8_t *payload; uint8_t i; if(mosq->state == mosq_cs_socks5_start){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.payload[0] != 5){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } switch(mosq->in_packet.payload[1]){ case SOCKS_AUTH_NONE: _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_auth_ok; return mosquitto__socks5_send(mosq); case SOCKS_AUTH_USERPASS: _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_send_userpass; return mosquitto__socks5_send(mosq); default: _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_AUTH; } }else if(mosq->state == mosq_cs_socks5_userpass_reply){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.payload[0] != 1){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } if(mosq->in_packet.payload[1] == 0){ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_auth_ok; return mosquitto__socks5_send(mosq); }else{ i = mosq->in_packet.payload[1]; _mosquitto_packet_cleanup(&mosq->in_packet); switch(i){ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED: return MOSQ_ERR_AUTH; case SOCKS_REPLY_NETWORK_UNREACHABLE: case SOCKS_REPLY_HOST_UNREACHABLE: case SOCKS_REPLY_CONNECTION_REFUSED: return MOSQ_ERR_NO_CONN; case SOCKS_REPLY_GENERAL_FAILURE: case SOCKS_REPLY_TTL_EXPIRED: case SOCKS_REPLY_COMMAND_NOT_SUPPORTED: case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: return MOSQ_ERR_PROXY; default: return MOSQ_ERR_INVAL; } return MOSQ_ERR_PROXY; } }else if(mosq->state == mosq_cs_socks5_request){ while(mosq->in_packet.to_process > 0){ len = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process); if(len > 0){ mosq->in_packet.pos += len; mosq->in_packet.to_process -= len; }else{ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); switch(errno){ case 0: return MOSQ_ERR_PROXY; case COMPAT_ECONNRESET: return MOSQ_ERR_CONN_LOST; default: return MOSQ_ERR_ERRNO; } } } } if(mosq->in_packet.packet_length == 5){ /* First part of the packet has been received, we now know what else to expect. */ if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V4){ mosq->in_packet.to_process += 4+2-1; /* 4 bytes IPv4, 2 bytes port, -1 byte because we've already read the first byte */ mosq->in_packet.packet_length += 4+2-1; }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_IP_V6){ mosq->in_packet.to_process += 16+2-1; /* 16 bytes IPv6, 2 bytes port, -1 byte because we've already read the first byte */ mosq->in_packet.packet_length += 16+2-1; }else if(mosq->in_packet.payload[3] == SOCKS_ATYPE_DOMAINNAME){ if(mosq->in_packet.payload[4] > 0 && mosq->in_packet.payload[4] <= 255){ mosq->in_packet.to_process += mosq->in_packet.payload[4]; mosq->in_packet.packet_length += mosq->in_packet.payload[4]; } }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROTOCOL; } payload = _mosquitto_realloc(mosq->in_packet.payload, mosq->in_packet.packet_length); if(payload){ mosq->in_packet.payload = payload; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_NOMEM; } payload = _mosquitto_realloc(mosq->in_packet.payload, mosq->in_packet.packet_length); if(payload){ mosq->in_packet.payload = payload; }else{ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_NOMEM; } return MOSQ_ERR_SUCCESS; } /* Entire packet is now read. */ if(mosq->in_packet.payload[0] != 5){ _mosquitto_packet_cleanup(&mosq->in_packet); return MOSQ_ERR_PROXY; } if(mosq->in_packet.payload[1] == 0){ /* Auth passed */ _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_new; return _mosquitto_send_connect(mosq, mosq->keepalive, mosq->clean_session); }else{ i = mosq->in_packet.payload[1]; _mosquitto_packet_cleanup(&mosq->in_packet); mosq->state = mosq_cs_socks5_new; switch(i){ case SOCKS_REPLY_CONNECTION_NOT_ALLOWED: return MOSQ_ERR_AUTH; case SOCKS_REPLY_NETWORK_UNREACHABLE: case SOCKS_REPLY_HOST_UNREACHABLE: case SOCKS_REPLY_CONNECTION_REFUSED: return MOSQ_ERR_NO_CONN; case SOCKS_REPLY_GENERAL_FAILURE: case SOCKS_REPLY_TTL_EXPIRED: case SOCKS_REPLY_COMMAND_NOT_SUPPORTED: case SOCKS_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: return MOSQ_ERR_PROXY; default: return MOSQ_ERR_INVAL; } } }else{ return _mosquitto_packet_read(mosq); } return MOSQ_ERR_SUCCESS; }