static int mongo_set_blocking_status( mongo *conn ) { int flags; int blocking; blocking = ( conn->conn_timeout_ms == 0 ); if( blocking ) return MONGO_OK; else { if( ( flags = fcntl( conn->sock, F_GETFL ) ) == -1 ) { conn->err = MONGO_IO_ERROR; mongo_close_socket( conn->sock ); return MONGO_ERROR; } flags |= O_NONBLOCK; if( ( flags = fcntl( conn->sock, F_SETFL, flags ) ) == -1 ) { conn->err = MONGO_IO_ERROR; mongo_close_socket( conn->sock ); return MONGO_ERROR; } } return MONGO_OK; }
/* Find out whether the current connected node is master, and * verify that the node's replica set name matched the provided name */ static int mongo_replset_check_host( mongo *conn ) { bson out; bson_iterator it; bson_bool_t ismaster = 0; const char *set_name; out.data = NULL; if ( mongo_simple_int_command( conn, "admin", "ismaster", 1, &out ) == MONGO_OK ) { if( bson_find( &it, &out, "ismaster" ) ) ismaster = bson_iterator_bool( &it ); if( bson_find( &it, &out, "setName" ) ) { set_name = bson_iterator_string( &it ); if( strcmp( set_name, conn->replset->name ) != 0 ) { bson_destroy( &out ); conn->err = MONGO_CONN_BAD_SET_NAME; return MONGO_ERROR; } } } bson_destroy( &out ); if( ismaster ) { conn->replset->primary_connected = 1; } else { mongo_close_socket( conn->sock ); } return MONGO_OK; }
int mongo_replset_connect(mongo_connection* conn) { int res = 0; mongo_host_port* node; conn->sock = 0; conn->connected = 0; /* First iterate over the seed nodes to get the canonical list of hosts * from the replica set. Break out once we have a host list. */ node = conn->replset->seeds; while( node != NULL ) { res = mongo_socket_connect( conn, (const char*)&node->host, node->port ); if( res != MONGO_OK ) return MONGO_ERROR; mongo_replset_check_seed( conn ); if( conn->replset->hosts ) break; node = node->next; } /* Iterate over the host list, checking for the primary node. */ if( !conn->replset->hosts ) { conn->err = MONGO_CONN_CANNOT_FIND_PRIMARY; return MONGO_ERROR; } else { node = conn->replset->hosts; while( node != NULL ) { res = mongo_socket_connect( conn, (const char*)&node->host, node->port ); if( res == MONGO_OK ) { if( mongo_replset_check_host( conn ) != MONGO_OK ) return MONGO_ERROR; /* Primary found, so return. */ else if( conn->replset->primary_connected ) return MONGO_OK; /* No primary, so close the connection. */ else { mongo_close_socket( conn->sock ); conn->sock = 0; conn->connected = 0; } } node = node->next; } } conn->err = MONGO_CONN_CANNOT_FIND_PRIMARY; return MONGO_ERROR; }
int mongo_socket_connect( mongo *conn, const char *host, int port ) { struct sockaddr_in sa; socklen_t addressSize; int flag = 1; if( mongo_create_socket( conn ) != MONGO_OK ) return MONGO_ERROR; memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) ); sa.sin_family = AF_INET; sa.sin_port = htons( port ); sa.sin_addr.s_addr = inet_addr( host ); addressSize = sizeof( sa ); if ( connect( conn->sock, ( struct sockaddr * )&sa, addressSize ) == -1 ) { mongo_close_socket( conn->sock ); conn->connected = 0; conn->sock = 0; conn->err = MONGO_CONN_FAIL; return MONGO_ERROR; } setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * ) &flag, sizeof( flag ) ); if( conn->op_timeout_ms > 0 ) mongo_set_socket_op_timeout( conn, conn->op_timeout_ms ); conn->connected = 1; return MONGO_OK; }
/* Find out whether the current connected node is master, and * verify that the node's replica set name matched the provided name */ static int mongo_replset_check_host( mongo_connection* conn ) { bson out; bson_iterator it; bson_bool_t ismaster = 0; const char* set_name; out.data = NULL; out.owned = 1; if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out)) { if( bson_find(&it, &out, "ismaster") ) ismaster = bson_iterator_bool( &it ); if( bson_find( &it, &out, "setName" ) ) { set_name = bson_iterator_string( &it ); if( strcmp( set_name, conn->replset->name ) != 0 ) { return mongo_conn_bad_set_name; } } } bson_destroy( &out ); if(ismaster) { conn->replset->primary_connected = 1; } else { mongo_close_socket( conn->sock ); } return 0; }
static int mongo_socket_connect( mongo_connection * conn, const char * host, int port ){ struct sockaddr_in sa; socklen_t addressSize; memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) ); sa.sin_family = AF_INET; sa.sin_port = htons( port ); sa.sin_addr.s_addr = inet_addr( host ); addressSize = sizeof( sa ); conn->sock = socket( AF_INET, SOCK_STREAM, 0 ); if ( conn->sock < 0 ){ mongo_close_socket( conn->sock ); return mongo_conn_no_socket; } if ( connect( conn->sock, (struct sockaddr *)&sa, addressSize ) ){ return mongo_conn_fail; } setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one) ); conn->connected = 1; return 0; }
mongo_conn_return mongo_replset_connect(mongo_connection* conn) { int connect_error = 0; mongo_host_port* node; conn->sock = 0; conn->connected = 0; /* First iterate over the seed nodes to get the canonical list of hosts * from the replica set. Break out once we have a host list. */ node = conn->replset->seeds; while( node != NULL ) { connect_error = mongo_socket_connect( conn, (const char*)&node->host, node->port ); if( connect_error == 0 ) { if ( (connect_error = mongo_replset_check_seed( conn )) ) return connect_error; } if( conn->replset->hosts ) break; node = node->next; } /* Iterate over the host list, checking for the primary node. */ if( !conn->replset->hosts ) return mongo_conn_cannot_find_primary; else { node = conn->replset->hosts; while( node != NULL ) { connect_error = mongo_socket_connect( conn, (const char*)&node->host, node->port ); if( connect_error == 0 ) { if ( (connect_error = mongo_replset_check_host( conn )) ) return connect_error; /* Primary found, so return. */ else if( conn->replset->primary_connected ) return 0; /* No primary, so close the connection. */ else { mongo_close_socket( conn->sock ); conn->sock = 0; conn->connected = 0; } } node = node->next; } } return mongo_conn_cannot_find_primary; }
static int mongo_socket_connect( mongo_connection * conn, const char * host, int port ){ struct addrinfo* addrs = NULL; struct addrinfo hints; char port_str[12]; int ret; conn->sock = 0; conn->connected = 0; memset( &hints, 0, sizeof( hints ) ); hints.ai_family = AF_INET; sprintf( port_str, "%d", port ); conn->sock = socket( AF_INET, SOCK_STREAM, 0 ); if ( conn->sock < 0 ){ mongo_close_socket( conn->sock ); return mongo_conn_no_socket; } ret = getaddrinfo( host, port_str, &hints, &addrs ); if(ret) { fprintf( stderr, "getaddrinfo failed: %s", gai_strerror( ret ) ); return mongo_conn_fail; } if ( connect( conn->sock, addrs->ai_addr, addrs->ai_addrlen ) ){ mongo_close_socket( conn->sock ); freeaddrinfo( addrs ); return mongo_conn_fail; } setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one) ); conn->connected = 1; freeaddrinfo( addrs ); return 0; }
MONGO_EXPORT void mongo_disconnect( mongo *conn ) { if( ! conn->connected ) return; if( conn->replset ) { conn->replset->primary_connected = 0; mongo_replset_free_list( &conn->replset->hosts ); conn->replset->hosts = NULL; } mongo_close_socket( conn->sock ); conn->sock = 0; conn->connected = 0; }
static void mongo_replset_check_seed( mongo_connection* conn ) { bson out; bson hosts; const char* data; bson_iterator it; bson_iterator it_sub; const char* host_string; mongo_host_port *host_port = NULL; out.data = NULL; out.owned = 1; hosts.data = NULL; hosts.owned = 1; if( mongo_simple_int_command(conn, "admin", "ismaster", 1, &out) == MONGO_OK ) { if( bson_find( &it, &out, "hosts" ) ) { data = bson_iterator_value( &it ); bson_iterator_init( &it_sub, data ); /* Iterate over host list, adding each host to the * connection's host list. */ while( bson_iterator_next( &it_sub ) ) { host_string = bson_iterator_string( &it_sub ); host_port = bson_malloc( sizeof( mongo_host_port ) ); mongo_parse_host( host_string, host_port ); if( host_port ) { mongo_replset_add_node( &conn->replset->hosts, host_port->host, host_port->port ); free( host_port ); host_port = NULL; } } } } bson_destroy( &out ); bson_destroy( &hosts ); mongo_close_socket( conn->sock ); conn->sock = 0; conn->connected = 0; }
bson_bool_t mongo_disconnect( mongo_connection * conn ){ if( ! conn->connected ) return 1; if( conn->replset ) { conn->replset->primary_connected = 0; mongo_replset_free_list( &conn->replset->hosts ); conn->replset->hosts = NULL; return mongo_replset_connect( conn ); } mongo_close_socket( conn->sock ); conn->sock = 0; conn->connected = 0; return 0; }
int mongo_socket_connect( mongo *conn, const char *host, int port ) { struct addrinfo *addrs = NULL; struct addrinfo hints; int flag = 1; char port_str[12]; int ret; conn->sock = 0; conn->connected = 0; memset( &hints, 0, sizeof( hints ) ); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; bson_sprintf( port_str, "%d", port ); if( mongo_create_socket( conn ) != MONGO_OK ) return MONGO_ERROR; if( (ret = getaddrinfo( host, port_str, &hints, &addrs )) != 0 ) { bson_errprintf( "getaddrinfo failed: %s", gai_strerror( ret ) ); conn->err = MONGO_CONN_ADDR_FAIL; return MONGO_ERROR; } if ( connect( conn->sock, addrs->ai_addr, addrs->ai_addrlen ) == -1 ) { mongo_close_socket( conn->sock ); freeaddrinfo( addrs ); conn->err = MONGO_CONN_FAIL; return MONGO_ERROR; } setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * )&flag, sizeof( flag ) ); if( conn->op_timeout_ms > 0 ) mongo_set_socket_op_timeout( conn, conn->op_timeout_ms ); conn->connected = 1; freeaddrinfo( addrs ); return MONGO_OK; }
int mongo_socket_connect( mongo *conn, const char *host, int port ) { char port_str[NI_MAXSERV]; int status; struct addrinfo ai_hints; struct addrinfo *ai_list = NULL; struct addrinfo *ai_ptr = NULL; conn->sock = 0; conn->connected = 0; sprintf(port_str,"%d",port); bson_sprintf( port_str, "%d", port ); memset( &ai_hints, 0, sizeof( ai_hints ) ); #ifdef AI_ADDRCONFIG ai_hints.ai_flags = AI_ADDRCONFIG; #endif ai_hints.ai_family = AF_UNSPEC; ai_hints.ai_socktype = SOCK_STREAM; status = getaddrinfo( host, port_str, &ai_hints, &ai_list ); if ( status != 0 ) { bson_errprintf( "getaddrinfo failed: %s", gai_strerror( status ) ); conn->err = MONGO_CONN_ADDR_FAIL; return MONGO_ERROR; } for ( ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) { conn->sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol ); if ( conn->sock < 0 ) { conn->sock = 0; continue; } status = connect( conn->sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen ); if ( status != 0 ) { mongo_close_socket( conn->sock ); conn->sock = 0; continue; } if ( ai_ptr->ai_protocol == IPPROTO_TCP ) { int flag = 1; setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( void * ) &flag, sizeof( flag ) ); if ( conn->op_timeout_ms > 0 ) mongo_set_socket_op_timeout( conn, conn->op_timeout_ms ); } conn->connected = 1; break; } freeaddrinfo( ai_list ); if ( ! conn->connected ) { conn->err = MONGO_CONN_FAIL; return MONGO_ERROR; } return MONGO_OK; }
void mongo_connection_close(mongo_connection *con, int why) { mongo_close_socket((int) (long) con->socket, why); }
/** * This function does the actual connecting * The results of this function are stored in mongo_connection->socket, * which is a void* to be able to store various different backends * (f.e. the PHP io_streams stores a php_stream*) * * Returns an integer (masquerading as a void*) on success, NULL on failure. */ void* mongo_connection_connect(mongo_con_manager *manager, mongo_server_def *server, mongo_server_options *options, char **error_message) { struct sockaddr* sa; struct sockaddr_in si; socklen_t sn; int family; struct timeval tval; int connected; int status; int tmp_socket; #ifdef WIN32 WORD version; WSADATA wsaData; int size, error; u_long no = 0; const char yes = 1; #else struct sockaddr_un su; uint size; int yes = 1; #endif *error_message = NULL; #ifdef WIN32 family = AF_INET; sa = (struct sockaddr*)(&si); sn = sizeof(si); version = MAKEWORD(2,2); error = WSAStartup(version, &wsaData); if (error != 0) { return NULL; } /* create socket */ tmp_socket = socket(family, SOCK_STREAM, 0); if (tmp_socket == INVALID_SOCKET) { *error_message = strdup(strerror(errno)); return NULL; } #else /* domain socket */ if (server->port == 0) { family = AF_UNIX; sa = (struct sockaddr*)(&su); sn = sizeof(su); } else { family = AF_INET; sa = (struct sockaddr*)(&si); sn = sizeof(si); } /* create socket */ if ((tmp_socket = socket(family, SOCK_STREAM, 0)) == -1) { *error_message = strdup(strerror(errno)); return NULL; } #endif /* TODO: Move this to within the loop & use real timeout setting */ /* connection timeout: set in ms (current default 1 sec) */ tval.tv_sec = options->connectTimeoutMS <= 0 ? 1 : options->connectTimeoutMS / 1000; tval.tv_usec = options->connectTimeoutMS <= 0 ? 0 : (options->connectTimeoutMS % 1000) * 1000; /* get addresses */ if (mongo_util_connect__sockaddr(sa, family, server->host, server->port, error_message) == 0) { goto error; } setsockopt(tmp_socket, SOL_SOCKET, SO_KEEPALIVE, &yes, INT_32); setsockopt(tmp_socket, IPPROTO_TCP, TCP_NODELAY, &yes, INT_32); #ifdef WIN32 ioctlsocket(tmp_socket, FIONBIO, (u_long*)&yes); #else fcntl(tmp_socket, F_SETFL, FLAGS|O_NONBLOCK); #endif /* connect */ status = connect(tmp_socket, sa, sn); if (status < 0) { #ifdef WIN32 errno = WSAGetLastError(); if (errno != WSAEINPROGRESS && errno != WSAEWOULDBLOCK) { #else if (errno != EINPROGRESS) { #endif *error_message = strdup(strerror(errno)); goto error; } while (1) { fd_set rset, wset, eset; FD_ZERO(&rset); FD_SET(tmp_socket, &rset); FD_ZERO(&wset); FD_SET(tmp_socket, &wset); FD_ZERO(&eset); FD_SET(tmp_socket, &eset); if (select(tmp_socket+1, &rset, &wset, &eset, &tval) == 0) { *error_message = malloc(256); snprintf(*error_message, 256, "Timed out after %d ms", options->connectTimeoutMS); goto error; } /* if our descriptor has an error */ if (FD_ISSET(tmp_socket, &eset)) { *error_message = strdup(strerror(errno)); goto error; } /* if our descriptor is ready break out */ if (FD_ISSET(tmp_socket, &wset) || FD_ISSET(tmp_socket, &rset)) { break; } } size = sn; connected = getpeername(tmp_socket, sa, &size); if (connected == -1) { *error_message = strdup(strerror(errno)); goto error; } } /* reset flags */ #ifdef WIN32 ioctlsocket(tmp_socket, FIONBIO, &no); #else fcntl(tmp_socket, F_SETFL, FLAGS); #endif return (void *) (long) tmp_socket; error: mongo_close_socket(tmp_socket, MONGO_CLOSE_BROKEN); return NULL; } static void mongo_close_socket(int socket, int why) { #ifdef WIN32 shutdown(socket, SD_BOTH); closesocket(socket); WSACleanup(); #else shutdown(socket, SHUT_RDWR); close(socket); #endif }
static int mongo_replset_check_seed( mongo_connection* conn ) { bson out; bson hosts; const char* data; bson_iterator it; bson_iterator it_sub; const char* host_string; char* host; int len, idx, port, split; out.data = NULL; out.owned = 1; hosts.data = NULL; hosts.owned = 1; if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out)) { if( bson_find( &it, &out, "hosts" ) ) { data = bson_iterator_value( &it ); bson_iterator_init( &it_sub, data ); /* Iterate over host list, adding each host to the * connection's host list. */ while( bson_iterator_next( &it_sub ) ) { host_string = bson_iterator_string( &it_sub ); len = split = idx = 0; /* Split the host_port string at the ':' */ while(1) { if( *(host_string + len) == 0) break; if( *(host_string + len) == ':' ) split = len; len++; } /* If 'split' is set, we know the that port exists; * Otherwise, we set the default port. */ if( len > 0 ) { idx = split ? split : len; host = (char *)bson_malloc( idx + 1 ); memcpy( host, host_string, idx ); memcpy( host + idx, "\0", 1 ); if( split ) port = atoi( host_string + idx + 1 ); else port = 27017; mongo_replset_add_node( &conn->replset->hosts, host, port ); } } } } bson_destroy( &out ); bson_destroy( &hosts ); mongo_close_socket( conn->sock ); conn->sock = 0; conn->connected = 0; return 0; }