1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <IPCConfig.hpp>
27 
28 #include <TransporterRegistry.hpp>
29 
30 #include <mgmapi.h>
31 #include <mgmapi_configuration.hpp>
32 
33 
34 /* Return true if node with "nodeId" is a MGM node */
is_mgmd(Uint32 nodeId,const struct ndb_mgm_configuration & config)35 static bool is_mgmd(Uint32 nodeId,
36                     const struct ndb_mgm_configuration & config)
37 {
38   ndb_mgm_configuration_iterator iter(config, CFG_SECTION_NODE);
39   if (iter.find(CFG_NODE_ID, nodeId))
40     abort();
41   Uint32 type;
42   if(iter.get(CFG_TYPE_OF_SECTION, &type))
43     abort();
44 
45   return (type == NODE_TYPE_MGM);
46 }
47 
48 
49 bool
configureTransporters(Uint32 nodeId,const struct ndb_mgm_configuration & config,class TransporterRegistry & tr,bool transporter_to_self)50 IPCConfig::configureTransporters(Uint32 nodeId,
51                                  const struct ndb_mgm_configuration & config,
52                                  class TransporterRegistry & tr,
53                                  bool transporter_to_self)
54 {
55   bool result= true;
56 
57   DBUG_ENTER("IPCConfig::configureTransporters");
58 
59 
60   if (!is_mgmd(nodeId, config))
61   {
62 
63     /**
64      * Iterate over all MGM's and construct a connectstring
65      * create mgm_handle and give it to the Transporter Registry
66      */
67 
68     const char *separator= "";
69     BaseString connect_string;
70     ndb_mgm_configuration_iterator iter(config, CFG_SECTION_NODE);
71     for(iter.first(); iter.valid(); iter.next())
72     {
73       Uint32 type;
74       if(iter.get(CFG_TYPE_OF_SECTION, &type)) continue;
75       if(type != NODE_TYPE_MGM) continue;
76       const char* hostname;
77       Uint32 port;
78       if(iter.get(CFG_NODE_HOST, &hostname)) continue;
79       if( strlen(hostname) == 0 ) continue;
80       if(iter.get(CFG_MGM_PORT, &port)) continue;
81       connect_string.appfmt("%s%s:%u",separator,hostname,port);
82       separator= ",";
83     }
84     NdbMgmHandle h= ndb_mgm_create_handle();
85     if ( h && connect_string.length() > 0 )
86     {
87       ndb_mgm_set_connectstring(h,connect_string.c_str());
88       tr.set_mgm_handle(h);
89     }
90   }
91 
92 
93   /* Remove transporter to nodes that does not exist anymore */
94   for (int i= 1; i < MAX_NODES; i++)
95   {
96     ndb_mgm_configuration_iterator iter(config, CFG_SECTION_NODE);
97     if (tr.get_transporter(i) && iter.find(CFG_NODE_ID, i))
98     {
99       // Transporter exist in TransporterRegistry but not
100       // in configuration
101       ndbout_c("The connection to node %d could not "
102                "be removed at this time", i);
103       result= false; // Need restart
104     }
105   }
106 
107   TransporterConfiguration conf;
108   TransporterConfiguration loopback_conf;
109   ndb_mgm_configuration_iterator iter(config, CFG_SECTION_CONNECTION);
110   for(iter.first(); iter.valid(); iter.next()){
111 
112     bzero(&conf, sizeof(conf));
113     Uint32 nodeId1, nodeId2, remoteNodeId;
114     const char * remoteHostName= 0, * localHostName= 0;
115     if(iter.get(CFG_CONNECTION_NODE_1, &nodeId1)) continue;
116     if(iter.get(CFG_CONNECTION_NODE_2, &nodeId2)) continue;
117 
118     if(nodeId1 != nodeId && nodeId2 != nodeId) continue;
119     remoteNodeId = (nodeId == nodeId1 ? nodeId2 : nodeId1);
120 
121     if (nodeId1 == nodeId && nodeId2 == nodeId)
122     {
123       transporter_to_self = false; // One already present..ignore extra arg
124     }
125 
126     {
127       const char * host1= 0, * host2= 0;
128       iter.get(CFG_CONNECTION_HOSTNAME_1, &host1);
129       iter.get(CFG_CONNECTION_HOSTNAME_2, &host2);
130       localHostName  = (nodeId == nodeId1 ? host1 : host2);
131       remoteHostName = (nodeId == nodeId1 ? host2 : host1);
132     }
133 
134     Uint32 sendSignalId = 1;
135     Uint32 checksum = 1;
136     if(iter.get(CFG_CONNECTION_SEND_SIGNAL_ID, &sendSignalId)) continue;
137     if(iter.get(CFG_CONNECTION_CHECKSUM, &checksum)) continue;
138 
139     Uint32 type = ~0;
140     if(iter.get(CFG_TYPE_OF_SECTION, &type)) continue;
141 
142     Uint32 server_port= 0;
143     if(iter.get(CFG_CONNECTION_SERVER_PORT, &server_port)) break;
144 
145     Uint32 nodeIdServer= 0;
146     if(iter.get(CFG_CONNECTION_NODE_ID_SERVER, &nodeIdServer)) break;
147 
148     if(is_mgmd(nodeId1, config) || is_mgmd(nodeId2, config))
149     {
150       // All connections with MGM uses the mgm port as server
151       conf.isMgmConnection= true;
152     }
153     else
154       conf.isMgmConnection= false;
155 
156     Uint32 bindInAddrAny = 0;
157     iter.get(CFG_TCP_BIND_INADDR_ANY, &bindInAddrAny);
158 
159     if (nodeId == nodeIdServer && !conf.isMgmConnection) {
160       tr.add_transporter_interface(remoteNodeId,
161 				   !bindInAddrAny ? localHostName : "",
162 				   server_port);
163     }
164 
165     DBUG_PRINT("info", ("Transporter between this node %d and node %d using port %d, signalId %d, checksum %d",
166                nodeId, remoteNodeId, server_port, sendSignalId, checksum));
167     /*
168       This may be a dynamic port. It depends on when we're getting
169       our configuration. If we've been restarted, we'll be getting
170       a configuration with our old dynamic port in it, hence the number
171       here is negative (and we try the old port number first).
172 
173       On a first-run, server_port will be zero (with dynamic ports)
174 
175       If we're not using dynamic ports, we don't do anything.
176     */
177 
178     conf.localNodeId    = nodeId;
179     conf.remoteNodeId   = remoteNodeId;
180     conf.checksum       = checksum;
181     conf.signalId       = sendSignalId;
182     conf.s_port         = server_port;
183     conf.localHostName  = localHostName;
184     conf.remoteHostName = remoteHostName;
185     conf.serverNodeId   = nodeIdServer;
186 
187     switch(type){
188     case CONNECTION_TYPE_SHM:
189       if(iter.get(CFG_SHM_KEY, &conf.shm.shmKey)) break;
190       if(iter.get(CFG_SHM_BUFFER_MEM, &conf.shm.shmSize)) break;
191 
192       Uint32 signum;
193       if(iter.get(CFG_SHM_SIGNUM, &signum)) break;
194       conf.shm.signum= signum;
195 
196       conf.type = tt_SHM_TRANSPORTER;
197 
198       if(!tr.configureTransporter(&conf)){
199         DBUG_PRINT("error", ("Failed to configure SHM Transporter "
200                              "from %d to %d",
201 	           conf.localNodeId, conf.remoteNodeId));
202 	ndbout_c("Failed to configure SHM Transporter to node %d",
203                 conf.remoteNodeId);
204         result = false;
205       }
206       DBUG_PRINT("info", ("Configured SHM Transporter using shmkey %d, "
207 			  "buf size = %d", conf.shm.shmKey, conf.shm.shmSize));
208       break;
209 
210     case CONNECTION_TYPE_SCI:
211       if(iter.get(CFG_SCI_SEND_LIMIT, &conf.sci.sendLimit)) break;
212       if(iter.get(CFG_SCI_BUFFER_MEM, &conf.sci.bufferSize)) break;
213       if (nodeId == nodeId1) {
214         if(iter.get(CFG_SCI_HOST2_ID_0, &conf.sci.remoteSciNodeId0)) break;
215         if(iter.get(CFG_SCI_HOST2_ID_1, &conf.sci.remoteSciNodeId1)) break;
216       } else {
217         if(iter.get(CFG_SCI_HOST1_ID_0, &conf.sci.remoteSciNodeId0)) break;
218         if(iter.get(CFG_SCI_HOST1_ID_1, &conf.sci.remoteSciNodeId1)) break;
219       }
220       if (conf.sci.remoteSciNodeId1 == 0) {
221         conf.sci.nLocalAdapters = 1;
222       } else {
223         conf.sci.nLocalAdapters = 2;
224       }
225       conf.type = tt_SCI_TRANSPORTER;
226       if(!tr.configureTransporter(&conf)){
227         DBUG_PRINT("error", ("Failed to configure SCI Transporter "
228                              "from %d to %d",
229 	           conf.localNodeId, conf.remoteNodeId));
230 	ndbout_c("Failed to configure SCI Transporter to node %d",
231                  conf.remoteNodeId);
232         result = false;
233       } else {
234         DBUG_PRINT("info", ("Configured SCI Transporter: Adapters = %d, "
235 			    "remote SCI node id %d",
236                    conf.sci.nLocalAdapters, conf.sci.remoteSciNodeId0));
237         DBUG_PRINT("info", ("Host 1 = %s, Host 2 = %s, sendLimit = %d, "
238 			    "buf size = %d", conf.localHostName,
239 			    conf.remoteHostName, conf.sci.sendLimit,
240 			    conf.sci.bufferSize));
241         if (conf.sci.nLocalAdapters > 1) {
242           DBUG_PRINT("info", ("Fault-tolerant with 2 Remote Adapters, "
243 			      "second remote SCI node id = %d",
244 			      conf.sci.remoteSciNodeId1));
245         }
246       }
247      break;
248 
249     case CONNECTION_TYPE_TCP:
250       if(iter.get(CFG_TCP_SEND_BUFFER_SIZE, &conf.tcp.sendBufferSize)) break;
251       if(iter.get(CFG_TCP_RECEIVE_BUFFER_SIZE, &conf.tcp.maxReceiveSize)) break;
252 
253       const char * proxy;
254       if (!iter.get(CFG_TCP_PROXY, &proxy)) {
255 	if (strlen(proxy) > 0 && nodeId2 == nodeId) {
256 	  // TODO handle host:port
257 	  conf.s_port = atoi(proxy);
258 	}
259       }
260 
261       iter.get(CFG_TCP_SND_BUF_SIZE, &conf.tcp.tcpSndBufSize);
262       iter.get(CFG_TCP_RCV_BUF_SIZE, &conf.tcp.tcpRcvBufSize);
263       iter.get(CFG_TCP_MAXSEG_SIZE, &conf.tcp.tcpMaxsegSize);
264       iter.get(CFG_CONNECTION_OVERLOAD, &conf.tcp.tcpOverloadLimit);
265 
266       conf.type = tt_TCP_TRANSPORTER;
267 
268       if(!tr.configureTransporter(&conf)){
269 	ndbout_c("Failed to configure TCP Transporter to node %d",
270                  conf.remoteNodeId);
271         result= false;
272       }
273       DBUG_PRINT("info", ("Configured TCP Transporter: sendBufferSize = %d, "
274 			  "maxReceiveSize = %d", conf.tcp.sendBufferSize,
275 			  conf.tcp.maxReceiveSize));
276       loopback_conf = conf; // reuse it...
277       break;
278     default:
279       ndbout << "Unknown transporter type from: " << nodeId <<
280 	" to: " << remoteNodeId << endl;
281       break;
282     } // switch
283   } // for
284 
285   if (transporter_to_self)
286   {
287     loopback_conf.remoteNodeId = nodeId;
288     loopback_conf.localNodeId = nodeId;
289     loopback_conf.serverNodeId = 0; // always client
290     loopback_conf.remoteHostName = "localhost";
291     loopback_conf.localHostName = "localhost";
292     loopback_conf.s_port = 1; // prevent asking ndb_mgmd for port...
293     if (!tr.configureTransporter(&loopback_conf))
294     {
295       ndbout_c("Failed to configure Loopback Transporter");
296       result= false;
297     }
298   }
299 
300   DBUG_RETURN(result);
301 }
302 
303