diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index 4e015cc3d7e8eaed27656361ccce512dee056273..208e8aead8d26f95502bd2ef9ded956430c12d5e 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -231,7 +231,9 @@ extern "C" { NDB_MGM_SERVER_NOT_CONNECTED = 1010, /** Could not connect to socker */ NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET = 1011, - + /** Could not bind local address */ + NDB_MGM_BIND_ADDRESS = 1012, + /* Alloc node id failures */ /** Generic error, retry may succeed */ NDB_MGM_ALLOCID_ERROR = 1101, @@ -515,6 +517,15 @@ extern "C" { const char *ndb_mgm_get_connected_host(NdbMgmHandle handle); const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz); + /** + * Set local bindaddress + * @param arg - Srting of form "host[:port]" + * @note must be called before connect + * @note Error on binding local address will not be reported until connect + * @return 0 on success + */ + int ndb_mgm_set_bindaddress(NdbMgmHandle, const char * arg); + /** * Gets the connectstring used for a connection * diff --git a/ndb/include/mgmcommon/ConfigRetriever.hpp b/ndb/include/mgmcommon/ConfigRetriever.hpp index 1b4ecd56f809a834022596fc7a182fd3fbc8a372..89a1eb976c87b322115b3f5d945967f5ca84d7a5 100644 --- a/ndb/include/mgmcommon/ConfigRetriever.hpp +++ b/ndb/include/mgmcommon/ConfigRetriever.hpp @@ -28,7 +28,8 @@ class ConfigRetriever { public: ConfigRetriever(const char * _connect_string, - Uint32 version, Uint32 nodeType); + Uint32 version, Uint32 nodeType, + const char * _bind_address = 0); ~ConfigRetriever(); int do_connect(int no_retries, int retry_delay_in_seconds, int verbose); diff --git a/ndb/include/util/SocketClient.hpp b/ndb/include/util/SocketClient.hpp index bf1ad7d45d666870191613629d2b1de6da525d60..422560c8a7832a48a321943cab73bb11cd5cec8e 100644 --- a/ndb/include/util/SocketClient.hpp +++ b/ndb/include/util/SocketClient.hpp @@ -37,7 +37,8 @@ public: }; unsigned short get_port() { return m_port; }; char *get_server_name() { return m_server_name; }; - NDB_SOCKET_TYPE connect(); + int bind(const char* toaddress, unsigned short toport); + NDB_SOCKET_TYPE connect(const char* toaddress = 0, unsigned short port = 0); bool close(); }; diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp index c2b3e8235ebdee113f1cc3c9cb06c539983ae9e9..a0e3a4b74f372ff3564a010c21ac12e297840ae7 100644 --- a/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -45,7 +45,8 @@ //**************************************************************************** ConfigRetriever::ConfigRetriever(const char * _connect_string, - Uint32 version, Uint32 node_type) + Uint32 version, Uint32 node_type, + const char * _bindaddress) { DBUG_ENTER("ConfigRetriever::ConfigRetriever"); @@ -66,6 +67,15 @@ ConfigRetriever::ConfigRetriever(const char * _connect_string, setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); DBUG_VOID_RETURN; } + + if (_bindaddress) + { + if (ndb_mgm_set_bindaddress(m_handle, _bindaddress)) + { + setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); + DBUG_VOID_RETURN; + } + } resetError(); DBUG_VOID_RETURN; } diff --git a/ndb/src/common/util/SocketClient.cpp b/ndb/src/common/util/SocketClient.cpp index 821624eb5c40e7b4fd0193d829f00a1380a3f7c3..f4f2babf312d3eac7a947c93df89898ce847cf31 100644 --- a/ndb/src/common/util/SocketClient.cpp +++ b/ndb/src/common/util/SocketClient.cpp @@ -25,7 +25,7 @@ SocketClient::SocketClient(const char *server_name, unsigned short port, SocketA { m_auth= sa; m_port= port; - m_server_name= strdup(server_name); + m_server_name= server_name ? strdup(server_name) : 0; m_sockfd= NDB_INVALID_SOCKET; } @@ -45,13 +45,16 @@ SocketClient::init() if (m_sockfd != NDB_INVALID_SOCKET) NDB_CLOSE_SOCKET(m_sockfd); - memset(&m_servaddr, 0, sizeof(m_servaddr)); - m_servaddr.sin_family = AF_INET; - m_servaddr.sin_port = htons(m_port); - // Convert ip address presentation format to numeric format - if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name)) - return false; - + if (m_server_name) + { + memset(&m_servaddr, 0, sizeof(m_servaddr)); + m_servaddr.sin_family = AF_INET; + m_servaddr.sin_port = htons(m_port); + // Convert ip address presentation format to numeric format + if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name)) + return false; + } + m_sockfd= socket(AF_INET, SOCK_STREAM, 0); if (m_sockfd == NDB_INVALID_SOCKET) { return false; @@ -62,8 +65,45 @@ SocketClient::init() return true; } +int +SocketClient::bind(const char* bindaddress, unsigned short localport) +{ + if (m_sockfd == NDB_INVALID_SOCKET) + return -1; + + struct sockaddr_in local; + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = htons(localport); + // Convert ip address presentation format to numeric format + if (Ndb_getInAddr(&local.sin_addr, bindaddress)) + { + return errno ? errno : EINVAL; + } + + const int on = 1; + if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == -1) { + + int ret = errno; + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return errno; + } + + if (::bind(m_sockfd, (struct sockaddr*)&local, sizeof(local)) == -1) + { + int ret = errno; + NDB_CLOSE_SOCKET(m_sockfd); + m_sockfd= NDB_INVALID_SOCKET; + return ret; + } + + return 0; +} + NDB_SOCKET_TYPE -SocketClient::connect() +SocketClient::connect(const char *toaddress, unsigned short toport) { if (m_sockfd == NDB_INVALID_SOCKET) { @@ -74,6 +114,21 @@ SocketClient::connect() return NDB_INVALID_SOCKET; } } + + if (toaddress) + { + if (m_server_name) + free(m_server_name); + m_server_name = strdup(toaddress); + m_port = toport; + memset(&m_servaddr, 0, sizeof(m_servaddr)); + m_servaddr.sin_family = AF_INET; + m_servaddr.sin_port = htons(toport); + // Convert ip address presentation format to numeric format + if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name)) + return NDB_INVALID_SOCKET; + } + const int r = ::connect(m_sockfd, (struct sockaddr*) &m_servaddr, sizeof(m_servaddr)); if (r == -1) { NDB_CLOSE_SOCKET(m_sockfd); diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index 7d1a5ed2ff49f734081a8932994c6467b678c250..49f16dae3ddafe5569c5fc42ae251ff9df421950 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -58,7 +58,8 @@ NDB_STD_OPTS_VARS; // XXX should be my_bool ??? static int _daemon, _no_daemon, _foreground, _initial, _no_start; static int _initialstart; -static const char* _nowait_nodes; +static const char* _nowait_nodes = 0; +static const char* _bind_address = 0; extern Uint32 g_start_type; extern NdbNodeBitmask g_nowait_nodes; @@ -98,6 +99,10 @@ static struct my_option my_long_options[] = "Perform initial start", (gptr*) &_initialstart, (gptr*) &_initialstart, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, + { "bind-address", OPT_NOWAIT_NODES, + "Local bind address", + (gptr*) &_bind_address, (gptr*) &_bind_address, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; static void short_usage_sub(void) @@ -257,7 +262,9 @@ Configuration::fetch_configuration(){ m_mgmd_port= 0; m_config_retriever= new ConfigRetriever(getConnectString(), - NDB_VERSION, NODE_TYPE_DB); + NDB_VERSION, + NODE_TYPE_DB, + _bind_address); if (m_config_retriever->hasError()) { diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 4428b158b6b2c192f2eb2fde84d9a245b42b7678..6287e53541dc4d9924264cc5310c28786a6e75b3 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -107,6 +107,7 @@ struct ndb_mgm_handle { int mgmd_version_major; int mgmd_version_minor; int mgmd_version_build; + char * m_bindaddress; }; #define SET_ERROR(h, e, s) setError(h, e, __LINE__, s) @@ -162,6 +163,7 @@ ndb_mgm_create_handle() h->cfg_i = -1; h->errstream = stdout; h->m_name = 0; + h->m_bindaddress = 0; strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE); @@ -209,6 +211,22 @@ ndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv) DBUG_RETURN(0); } +extern "C" +int +ndb_mgm_set_bindaddress(NdbMgmHandle handle, const char * arg) +{ + DBUG_ENTER("ndb_mgm_set_bindaddress"); + if (handle->m_bindaddress) + free(handle->m_bindaddress); + + if (arg) + handle->m_bindaddress = strdup(arg); + else + handle->m_bindaddress = 0; + + DBUG_RETURN(0); +} + /** * Destroy a handle */ @@ -235,6 +253,8 @@ ndb_mgm_destroy_handle(NdbMgmHandle * handle) #endif (*handle)->cfg.~LocalConfig(); my_free((*handle)->m_name, MYF(MY_ALLOW_ZERO_PTR)); + if ((*handle)->m_bindaddress) + free((*handle)->m_bindaddress); my_free((char*)* handle,MYF(MY_ALLOW_ZERO_PTR)); * handle = 0; DBUG_VOID_RETURN; @@ -427,6 +447,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, BaseString::snprintf(logname, 64, "mgmapi.log"); handle->logfile = fopen(logname, "w"); #endif + char buf[1024]; /** * Do connect @@ -434,6 +455,50 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, LocalConfig &cfg= handle->cfg; NDB_SOCKET_TYPE sockfd= NDB_INVALID_SOCKET; Uint32 i; + int binderror = 0; + SocketClient s(0, 0); + if (!s.init()) + { + fprintf(handle->errstream, + "Unable to create socket, " + "while trying to connect with connect string: %s\n", + cfg.makeConnectString(buf,sizeof(buf))); + + setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, + "Unable to create socket, " + "while trying to connect with connect string: %s\n", + cfg.makeConnectString(buf,sizeof(buf))); + DBUG_RETURN(-1); + } + + if (handle->m_bindaddress) + { + BaseString::snprintf(buf, sizeof(buf), handle->m_bindaddress); + unsigned short portno = 0; + char * port = strchr(buf, ':'); + if (port != 0) + { + portno = atoi(port+1); + * port = 0; + } + int err; + if ((err = s.bind(buf, portno)) != 0) + { + fprintf(handle->errstream, + "Unable to bind local address %s errno: %d, " + "while trying to connect with connect string: %s\n", + handle->m_bindaddress, err, + cfg.makeConnectString(buf,sizeof(buf))); + + setError(handle, NDB_MGM_BIND_ADDRESS, __LINE__, + "Unable to bind local address %s errno: %d, " + "while trying to connect with connect string: %s\n", + handle->m_bindaddress, err, + cfg.makeConnectString(buf,sizeof(buf))); + DBUG_RETURN(-1); + } + } + while (sockfd == NDB_INVALID_SOCKET) { // do all the mgmt servers @@ -441,8 +506,7 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, { if (cfg.ids[i].type != MgmId_TCP) continue; - SocketClient s(cfg.ids[i].name.c_str(), cfg.ids[i].port); - sockfd = s.connect(); + sockfd = s.connect(cfg.ids[i].name.c_str(), cfg.ids[i].port); if (sockfd != NDB_INVALID_SOCKET) break; } @@ -450,19 +514,17 @@ ndb_mgm_connect(NdbMgmHandle handle, int no_retries, break; #ifndef DBUG_OFF { - char buf[1024]; DBUG_PRINT("info",("Unable to connect with connect string: %s", cfg.makeConnectString(buf,sizeof(buf)))); } #endif if (verbose > 0) { - char buf[1024]; - fprintf(handle->errstream, "Unable to connect with connect string: %s\n", + fprintf(handle->errstream, + "Unable to connect with connect string: %s\n", cfg.makeConnectString(buf,sizeof(buf))); verbose= -1; } if (no_retries == 0) { - char buf[1024]; setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, "Unable to connect with connect string: %s", cfg.makeConnectString(buf,sizeof(buf)));