void TCP_Transporter::setSocketOptions(){ int sockOptKeepAlive = 1; if (setsockopt(theSocket, SOL_SOCKET, SO_RCVBUF, (char*)&sockOptRcvBufSize, sizeof(sockOptRcvBufSize)) < 0) { #ifdef DEBUG_TRANSPORTER g_eventLogger.error("The setsockopt SO_RCVBUF error code = %d", InetErrno); #endif }//if if (setsockopt(theSocket, SOL_SOCKET, SO_SNDBUF, (char*)&sockOptSndBufSize, sizeof(sockOptSndBufSize)) < 0) { #ifdef DEBUG_TRANSPORTER g_eventLogger.error("The setsockopt SO_SNDBUF error code = %d", InetErrno); #endif }//if if (setsockopt(theSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&sockOptKeepAlive, sizeof(sockOptKeepAlive)) < 0) { ndbout_c("The setsockopt SO_KEEPALIVE error code = %d", InetErrno); }//if //----------------------------------------------- // Set the TCP_NODELAY option so also small packets are sent // as soon as possible //----------------------------------------------- if (setsockopt(theSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&sockOptNodelay, sizeof(sockOptNodelay)) < 0) { #ifdef DEBUG_TRANSPORTER g_eventLogger.error("The setsockopt TCP_NODELAY error code = %d", InetErrno); #endif }//if }
int TCP_Transporter::doReceive() { // Select-function must return the socket for read // before this method is called // It reads the external TCP/IP interface once Uint32 size = receiveBuffer.sizeOfBuffer - receiveBuffer.sizeOfData; if(size > 0){ const int nBytesRead = recv(theSocket, receiveBuffer.insertPtr, size < maxReceiveSize ? size : maxReceiveSize, 0); if (nBytesRead > 0) { receiveBuffer.sizeOfData += nBytesRead; receiveBuffer.insertPtr += nBytesRead; if(receiveBuffer.sizeOfData > receiveBuffer.sizeOfBuffer){ #ifdef DEBUG_TRANSPORTER g_eventLogger.error("receiveBuffer.sizeOfData(%d) > receiveBuffer.sizeOfBuffer(%d)", receiveBuffer.sizeOfData, receiveBuffer.sizeOfBuffer); g_eventLogger.error("nBytesRead = %d", nBytesRead); #endif g_eventLogger.error("receiveBuffer.sizeOfData(%d) > receiveBuffer.sizeOfBuffer(%d)", receiveBuffer.sizeOfData, receiveBuffer.sizeOfBuffer); report_error(TE_INVALID_MESSAGE_LENGTH); return 0; } receiveCount ++; receiveSize += nBytesRead; if(receiveCount == reportFreq){ reportReceiveLen(get_callback_obj(), remoteNodeId, receiveCount, receiveSize); receiveCount = 0; receiveSize = 0; } return nBytesRead; } else { #if defined DEBUG_TRANSPORTER g_eventLogger.error("Receive Failure(disconnect==%d) to node = %d nBytesSent = %d " "errno = %d strerror = %s", DISCONNECT_ERRNO(InetErrno, nBytesRead), remoteNodeId, nBytesRead, InetErrno, (char*)ndbstrerror(InetErrno)); #endif if(DISCONNECT_ERRNO(InetErrno, nBytesRead)){ // The remote node has closed down doDisconnect(); report_disconnect(InetErrno); } } return nBytesRead; } else { return 0; } }
void TransporterRegistry::startReceiving() { DBUG_ENTER("TransporterRegistry::startReceiving"); #ifdef NDB_SHM_TRANSPORTER m_shm_own_pid = getpid(); if (g_ndb_shm_signum) { DBUG_PRINT("info",("Install signal handler for signum %d", g_ndb_shm_signum)); struct sigaction sa; NdbThread_set_shm_sigmask(FALSE); sigemptyset(&sa.sa_mask); sa.sa_handler = shm_sig_handler; sa.sa_flags = 0; int ret; while((ret = sigaction(g_ndb_shm_signum, &sa, 0)) == -1 && errno == EINTR); if(ret != 0) { DBUG_PRINT("error",("Install failed")); g_eventLogger.error("Failed to install signal handler for" " SHM transporter, signum %d, errno: %d (%s)", g_ndb_shm_signum, errno, strerror(errno)); } } #endif // NDB_SHM_TRANSPORTER DBUG_VOID_RETURN; }
bool TransporterRegistry::start_service(SocketServer& socket_server) { DBUG_ENTER("TransporterRegistry::start_service"); if (m_transporter_interface.size() > 0 && !nodeIdSpecified) { g_eventLogger.error("TransporterRegistry::startReceiving: localNodeId not specified"); DBUG_RETURN(false); } for (unsigned i= 0; i < m_transporter_interface.size(); i++) { Transporter_interface &t= m_transporter_interface[i]; unsigned short port= (unsigned short)t.m_s_service_port; if(t.m_s_service_port<0) port= -t.m_s_service_port; // is a dynamic port TransporterService *transporter_service = new TransporterService(new SocketAuthSimple("ndbd", "ndbd passwd")); if(!socket_server.setup(transporter_service, &port, t.m_interface)) { DBUG_PRINT("info", ("Trying new port")); port= 0; if(t.m_s_service_port>0 || !socket_server.setup(transporter_service, &port, t.m_interface)) { /* * If it wasn't a dynamically allocated port, or * our attempts at getting a new dynamic port failed */ g_eventLogger.error("Unable to setup transporter service port: %s:%d!\n" "Please check if the port is already used,\n" "(perhaps the node is already running)", t.m_interface ? t.m_interface : "*", t.m_s_service_port); delete transporter_service; DBUG_RETURN(false); } } t.m_s_service_port= (t.m_s_service_port<=0)?-port:port; // -`ve if dynamic DBUG_PRINT("info", ("t.m_s_service_port = %d",t.m_s_service_port)); transporter_service->setTransporterRegistry(this); } DBUG_RETURN(true); }
bool TCP_Transporter::setSocketNonBlocking(NDB_SOCKET_TYPE socket){ int flags; flags = fcntl(socket, F_GETFL, 0); if (flags < 0) { #ifdef DEBUG_TRANSPORTER g_eventLogger.error("Set non-blocking server error1: %s", strerror(InetErrno)); #endif }//if flags |= NDB_NONBLOCK; if (fcntl(socket, F_SETFL, flags) == -1) { #ifdef DEBUG_TRANSPORTER g_eventLogger.error("Set non-blocking server error2: %s", strerror(InetErrno)); #endif }//if return true; }
bool TCP_Transporter::doSend() { // If no sendbuffers are used nothing is done // Sends the contents of the SendBuffers until they are empty // or until select does not select the socket for write. // Before calling send, the socket must be selected for write // using "select" // It writes on the external TCP/IP interface until the send buffer is empty // and as long as write is possible (test it using select) // Empty the SendBuffers bool sent_any = true; while (m_sendBuffer.dataSize > 0) { const char * const sendPtr = m_sendBuffer.sendPtr; const Uint32 sizeToSend = m_sendBuffer.sendDataSize; const int nBytesSent = send(theSocket, sendPtr, sizeToSend, 0); if (nBytesSent > 0) { sent_any = true; m_sendBuffer.bytesSent(nBytesSent); sendCount ++; sendSize += nBytesSent; if(sendCount == reportFreq) { reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize); sendCount = 0; sendSize = 0; } } else { if (nBytesSent < 0 && InetErrno == EAGAIN && sent_any) break; // Send failed #if defined DEBUG_TRANSPORTER g_eventLogger.error("Send Failure(disconnect==%d) to node = %d nBytesSent = %d " "errno = %d strerror = %s", DISCONNECT_ERRNO(InetErrno, nBytesSent), remoteNodeId, nBytesSent, InetErrno, (char*)ndbstrerror(InetErrno)); #endif if(DISCONNECT_ERRNO(InetErrno, nBytesSent)){ doDisconnect(); report_disconnect(InetErrno); } return false; } } return true; }
bool TransporterRegistry::connect_client(NdbMgmHandle *h) { DBUG_ENTER("TransporterRegistry::connect_client(NdbMgmHandle)"); Uint32 mgm_nodeid= ndb_mgm_get_mgmd_nodeid(*h); if(!mgm_nodeid) { g_eventLogger.error("%s: %d", __FILE__, __LINE__); return false; } Transporter * t = theTransporters[mgm_nodeid]; if (!t) { g_eventLogger.error("%s: %d", __FILE__, __LINE__); return false; } DBUG_RETURN(t->connect_client(connect_ndb_mgmd(h))); }
/** * Given a connected NdbMgmHandle, turns it into a transporter * and returns the socket. */ NDB_SOCKET_TYPE TransporterRegistry::connect_ndb_mgmd(NdbMgmHandle *h) { struct ndb_mgm_reply mgm_reply; if ( h==NULL || *h == NULL ) { g_eventLogger.error("%s: %d", __FILE__, __LINE__); return NDB_INVALID_SOCKET; } for(unsigned int i=0;i < m_transporter_interface.size();i++) if (m_transporter_interface[i].m_s_service_port < 0 && ndb_mgm_set_connection_int_parameter(*h, get_localNodeId(), m_transporter_interface[i].m_remote_nodeId, CFG_CONNECTION_SERVER_PORT, m_transporter_interface[i].m_s_service_port, &mgm_reply) < 0) { g_eventLogger.error("Error: %s: %d", ndb_mgm_get_latest_error_desc(*h), ndb_mgm_get_latest_error(*h)); g_eventLogger.error("%s: %d", __FILE__, __LINE__); ndb_mgm_destroy_handle(h); return NDB_INVALID_SOCKET; } /** * convert_to_transporter also disposes of the handle (i.e. we don't leak * memory here. */ NDB_SOCKET_TYPE sockfd= ndb_mgm_convert_to_transporter(h); if ( sockfd == NDB_INVALID_SOCKET) { g_eventLogger.error("Error: %s: %d", ndb_mgm_get_latest_error_desc(*h), ndb_mgm_get_latest_error(*h)); g_eventLogger.error("%s: %d", __FILE__, __LINE__); ndb_mgm_destroy_handle(h); } return sockfd; }
bool TCP_Transporter::setSocketNonBlocking(NDB_SOCKET_TYPE socket){ unsigned long ul = 1; if(ioctlsocket(socket, FIONBIO, &ul)) { #ifdef DEBUG_TRANSPORTER g_eventLogger.error("Set non-blocking server error3: %d", InetErrno); #endif }//if return true; }
/***************************************************************************** * ~Ndb(); * * Remark: Disconnect with the database. *****************************************************************************/ Ndb::~Ndb() { DBUG_ENTER("Ndb::~Ndb()"); DBUG_PRINT("enter",("this: 0x%lx", (long) this)); if (m_sys_tab_0) getDictionary()->removeTableGlobal(*m_sys_tab_0, 0); assert(theImpl->m_ev_op == 0); // user should return NdbEventOperation's for (NdbEventOperationImpl *op= theImpl->m_ev_op; op; op=op->m_next) { if (op->m_state == NdbEventOperation::EO_EXECUTING && op->stop()) g_eventLogger.error("stopping NdbEventOperation failed in Ndb destructor"); op->m_magic_number= 0; } doDisconnect(); /* Disconnect from transporter to stop signals from coming in */ if (theImpl->m_transporter_facade != NULL && theNdbBlockNumber > 0) { theImpl->m_transporter_facade->close(theNdbBlockNumber, theFirstTransId); } delete theEventBuffer; releaseTransactionArrays(); delete []theConnectionArray; if(theCommitAckSignal != NULL) { delete theCommitAckSignal; theCommitAckSignal = NULL; } delete theImpl; #ifdef POORMANSPURIFY #ifdef POORMANSGUI ndbout << "cnewSignals=" << cnewSignals << endl; ndbout << "cfreeSignals=" << cfreeSignals << endl; ndbout << "cgetSignals=" << cgetSignals << endl; ndbout << "creleaseSignals=" << creleaseSignals << endl; #endif // Poor mans purifier assert(cnewSignals == cfreeSignals); assert(cgetSignals == creleaseSignals); #endif DBUG_VOID_RETURN; }
bool Transporter::connect_client(NDB_SOCKET_TYPE sockfd) { if(m_connected) return true; if (sockfd == NDB_INVALID_SOCKET) return false; DBUG_ENTER("Transporter::connect_client"); DBUG_PRINT("info",("port %d isMgmConnection=%d",m_s_port,isMgmConnection)); SocketOutputStream s_output(sockfd); SocketInputStream s_input(sockfd); // send info about own id // send info about own transporter type s_output.println("%d %d", localNodeId, m_type); // get remote id int nodeId, remote_transporter_type= -1; char buf[256]; if (s_input.gets(buf, 256) == 0) { NDB_CLOSE_SOCKET(sockfd); DBUG_RETURN(false); } int r= sscanf(buf, "%d %d", &nodeId, &remote_transporter_type); switch (r) { case 2: break; case 1: // we're running version prior to 4.1.9 // ok, but with no checks on transporter configuration compatability break; default: NDB_CLOSE_SOCKET(sockfd); DBUG_RETURN(false); } DBUG_PRINT("info", ("nodeId=%d remote_transporter_type=%d", nodeId, remote_transporter_type)); if (remote_transporter_type != -1) { if (remote_transporter_type != m_type) { DBUG_PRINT("error", ("Transporter types mismatch this=%d remote=%d", m_type, remote_transporter_type)); NDB_CLOSE_SOCKET(sockfd); g_eventLogger.error("Incompatible configuration: transporter type " "mismatch with node %d", nodeId); DBUG_RETURN(false); } } else if (m_type == tt_SHM_TRANSPORTER) { g_eventLogger.warning("Unable to verify transporter compatability with node %d", nodeId); } { struct sockaddr_in addr; SOCKET_SIZE_TYPE addrlen= sizeof(addr); getpeername(sockfd, (struct sockaddr*)&addr, &addrlen); m_connect_address= (&addr)->sin_addr; } bool res = connect_client_impl(sockfd); if(res){ m_connected = true; m_errorCount = 0; } DBUG_RETURN(res); }
bool TransporterRegistry::connect_server(NDB_SOCKET_TYPE sockfd) { DBUG_ENTER("TransporterRegistry::connect_server"); // read node id from client // read transporter type int nodeId, remote_transporter_type= -1; SocketInputStream s_input(sockfd); char buf[256]; if (s_input.gets(buf, 256) == 0) { DBUG_PRINT("error", ("Could not get node id from client")); DBUG_RETURN(false); } int r= sscanf(buf, "%d %d", &nodeId, &remote_transporter_type); switch (r) { case 2: break; case 1: // we're running version prior to 4.1.9 // ok, but with no checks on transporter configuration compatability break; default: DBUG_PRINT("error", ("Error in node id from client")); DBUG_RETURN(false); } DBUG_PRINT("info", ("nodeId=%d remote_transporter_type=%d", nodeId,remote_transporter_type)); //check that nodeid is valid and that there is an allocated transporter if ( nodeId < 0 || nodeId >= (int)maxTransporters) { DBUG_PRINT("error", ("Node id out of range from client")); DBUG_RETURN(false); } if (theTransporters[nodeId] == 0) { DBUG_PRINT("error", ("No transporter for this node id from client")); DBUG_RETURN(false); } //check that the transporter should be connected if (performStates[nodeId] != TransporterRegistry::CONNECTING) { DBUG_PRINT("error", ("Transporter in wrong state for this node id from client")); DBUG_RETURN(false); } Transporter *t= theTransporters[nodeId]; // send info about own id (just as response to acknowledge connection) // send info on own transporter type SocketOutputStream s_output(sockfd); s_output.println("%d %d", t->getLocalNodeId(), t->m_type); if (remote_transporter_type != -1) { if (remote_transporter_type != t->m_type) { DBUG_PRINT("error", ("Transporter types mismatch this=%d remote=%d", t->m_type, remote_transporter_type)); g_eventLogger.error("Incompatible configuration: Transporter type " "mismatch with node %d", nodeId); // wait for socket close for 1 second to let message arrive at client { fd_set a_set; FD_ZERO(&a_set); FD_SET(sockfd, &a_set); struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; select(sockfd+1, &a_set, 0, 0, &timeout); } DBUG_RETURN(false); } } else if (t->m_type == tt_SHM_TRANSPORTER) { g_eventLogger.warning("Unable to verify transporter compatability with node %d", nodeId); } // setup transporter (transporter responsible for closing sockfd) t->connect_server(sockfd); DBUG_RETURN(true); }