2
* Copyright (c) 2004 Mellanox Technologies LTD. All rights reserved.
4
* This software is available to you under a choice of one of two
5
* licenses. You may choose to be licensed under the terms of the GNU
6
* General Public License (GPL) Version 2, available from the file
7
* COPYING in the main directory of this source tree, or the
8
* OpenIB.org BSD license below:
10
* Redistribution and use in source and binary forms, with or
11
* without modification, are permitted provided that the following
14
* - Redistributions of source code must retain the above
15
* copyright notice, this list of conditions and the following
18
* - Redistributions in binary form must reproduce the above
19
* copyright notice, this list of conditions and the following
20
* disclaimer in the documentation and/or other materials
21
* provided with the distribution.
23
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39
//////////////////////////////////////////////////////////////
41
// CLASS IBMSClientConn
43
#include <fstream> /* for C++ file IO */
44
#include <sys/socket.h> /* for socket(), bind(), and connect() */
45
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
46
#include <unistd.h> /* for gethostname() */
47
#include <string.h> /* for memset() */
51
One instance of this class exists for each connected client.
52
The instance is created when the client sends the connect message,
53
providing the port guid it attaches to.
56
/* handle client request - should be called under lock */
57
/* NOTE: to avoid deadlocks we require the node to be
58
locked before. We are using special constructor for
59
the MADProcessor marking the node is preLocked */
61
IBMSClientConn::handleBindMsg(
65
MSGREG(err1, 'E', "Fail to create a new mad processor.", "server");
67
/* create a new client mad processor */
68
IBMSClientMsgProcessor *madProcessor =
69
new IBMSClientMsgProcessor(this, msg);
70
if (madProcessor == NULL)
77
/* keep track of active mad processors */
78
madProcessors.push_back(madProcessor);
84
/* destructor - needs to cleanup any binding done through this conn */
85
IBMSClientConn::~IBMSClientConn()
88
/* NOTE: each mad processor will lock the node */
89
for(list_pmad_proc::iterator lI = madProcessors.begin();
90
lI != madProcessors.end();
98
//////////////////////////////////////////////////////////////
103
IBMSServer::IBMSServer(IBMgtSim *pS, unsigned short portNum) :
104
GenServer(portNum, sizeof(ibms_client_msg_t))
108
gethostname(hostName, sizeof(hostName)-1);
112
/* the generic gen server might fail */
115
/* write down the server port into the appropriate file */
116
std::ofstream serverFile;
117
string serverFileName(pSim->getSimulatorDir());
118
serverFileName += "/ibmgtsim.server";
119
serverFile.open(serverFileName.c_str());
120
if (!serverFile.fail())
122
serverFile << hostName << " " << portNum << endl;
127
MSGREG(err1, 'E', "Fail to create file:$", "server");
128
MSGSND(err1, serverFileName);
134
/* cleaning up client when notified it is closing */
135
int IBMSServer::closingClient(
139
map_sock_client::iterator sI = sockToClientMap.find(clientSock);
140
if (sI != sockToClientMap.end())
142
IBMSClientConn *pClientConn = (*sI).second;
143
sockToClientMap.erase(sI);
150
/* handle a connection message */
151
int IBMSServer::handleConnectionMsg(
153
ibms_conn_msg_t &connMsg)
156
MSGREG(err1, 'E', "Given port guid:$ does not exists in fabric.", "server");
157
MSGREG(err2, 'E', "Socket $ has previously connected.", "server");
158
MSGREG(err3, 'E', "Fail to create client connection.", "server");
159
MSGREG(inf1, 'V', "Received connection requests to node:$ port:$.", "server");
161
IBFabric *pFabric = pSim->getFabric();
163
/* validate the given guid exists */
164
map_guid_pport::const_iterator pI =
165
pFabric->PortByGuid.find(connMsg.port_guid);
166
if (pI == pFabric->PortByGuid.end())
168
MSGSND(err1, connMsg.port_guid);
173
IBPort *pPort = (*pI).second;
174
IBNode *pNode = pPort->p_node;
175
IBMSNode *pMgtNode = ibmsGetIBNodeSimNode(pNode);
177
MSGSND(inf1, pNode->name, pPort->num);
179
/* we need to lock the map of the server to insert the new client */
180
pthread_mutex_lock(&lock);
182
/* if the client is not previously registered */
183
map_sock_client::iterator sI = sockToClientMap.find(clientSock);
184
if (sI != sockToClientMap.end())
186
MSGSND(err2, clientSock);
187
pthread_mutex_unlock(&lock);
192
/* create a new client object */
193
IBMSClientConn *clientConn =
194
new IBMSClientConn(pMgtNode, pPort->num,
195
&connMsg.host[0], connMsg.in_msg_port);
197
if (clientConn == NULL)
200
pthread_mutex_unlock(&lock);
205
/* insert to the map */
206
sockToClientMap[clientSock] = clientConn;
209
pthread_mutex_unlock(&lock);
215
/* handle a disconnect message */
217
IBMSServer::handleDisconnectMsg(
219
ibms_disconn_msg_t &discMsg)
222
MSGREG(err1, 'E', "Given port guid:$ does not exists in fabric.", "server");
223
MSGREG(err2, 'E', "Socket $ was not previously connected.", "server");
224
MSGREG(inf1, 'V', "Received disconnect requests from node:$ port:$.",
227
IBFabric *pFabric = pSim->getFabric();
229
/* validate the given guid exists */
230
map_guid_pport::const_iterator pI =
231
pFabric->PortByGuid.find(discMsg.port_guid);
232
if (pI == pFabric->PortByGuid.end())
234
MSGSND(err1, discMsg.port_guid);
239
IBPort *pPort = (*pI).second;
240
IBNode *pNode = pPort->p_node;
242
MSGSND(inf1, pNode->name, pPort->num);
244
/* we need to lock the map of the server to delete the client */
245
pthread_mutex_lock(&lock);
247
/* if the client is not previously registered */
248
map_sock_client::iterator sI = sockToClientMap.find(clientSock);
249
if (sI == sockToClientMap.end())
251
MSGSND(err2, clientSock);
252
pthread_mutex_unlock(&lock);
257
/* remove the connection from the list and delete it */
258
IBMSClientConn *clientConn = (*sI).second;
259
sockToClientMap.erase(sI);
262
pthread_mutex_unlock(&lock);
265
we need to delete the client itself not under the lock
266
since otherwise we will run into deadlock with the node lock
274
/* handle a bind message */
276
IBMSServer::handleBindMsg(
278
ibms_bind_msg_t &bindMsg)
283
MSGREG(err1, 'E', "Socket $ was not previously connected.", "server");
285
pthread_mutex_lock(&lock);
287
/* find the client conn for the given sock */
288
map_sock_client::iterator sI = sockToClientMap.find(clientSock);
290
/* if none then fail */
291
if (sI == sockToClientMap.end())
293
MSGSND(err1, clientSock);
294
pthread_mutex_unlock(&lock);
299
IBMSClientConn *pClient = (*sI).second;
300
IBMSNode *pSimNode = pClient->pSimNode;
302
pthread_mutex_unlock(&lock);
304
/* now that we know the client we can pre-lock the node */
305
pthread_mutex_lock(&pSimNode->lock);
306
pthread_mutex_lock(&lock);
308
/* to be safe we find again */
309
sI = sockToClientMap.find(clientSock);
310
if (sI == sockToClientMap.end())
312
MSGSND(err1, clientSock);
313
pthread_mutex_unlock(&lock);
314
pthread_mutex_unlock(&pSimNode->lock);
319
status = (*sI).second->handleBindMsg(bindMsg);
321
pthread_mutex_unlock(&lock);
322
pthread_mutex_unlock(&pSimNode->lock);
328
/* handle a bind message */
330
IBMSServer::handleCapMsg(
332
ibms_cap_msg_t &capMsg)
335
MSGREG(err1, 'E', "Socket $ was not previously connected.", "server");
337
pthread_mutex_lock(&lock);
339
/* find the client conn for the given sock */
340
map_sock_client::iterator sI = sockToClientMap.find(clientSock);
342
/* if none then fail */
343
if (sI == sockToClientMap.end())
345
MSGSND(err1, clientSock);
346
pthread_mutex_unlock(&lock);
351
/* if we know the client we know the port number and node */
352
IBMSClientConn *pCli = (*sI).second;
354
ib_port_info_t *pPortInfo =
355
&(pCli->getSimNode()->nodePortsInfo[pCli->getIbPortNum()]);
357
pthread_mutex_unlock(&lock);
359
/* OK we got the port info - now set/clr the capability mask */
360
pPortInfo->capability_mask =
361
(~capMsg.mask & pPortInfo->capability_mask) |
362
( capMsg.mask & capMsg.capabilities );
368
/* handle a mad message */
370
IBMSServer::handleMadMsg(
372
ibms_mad_msg_t &madMsg)
376
MSGREG(err1, 'E', "Socket $ was not previously connected.", "server");
378
pthread_mutex_lock(&lock);
380
/* find the client conn for the given sock */
381
map_sock_client::iterator sI = sockToClientMap.find(clientSock);
383
/* if none then fail */
384
if (sI == sockToClientMap.end())
386
MSGSND(err1, clientSock);
387
pthread_mutex_unlock(&lock);
392
IBMSClientConn *pClientConn = (*sI).second;
394
/* we need to replace the source lid with the lid of the port */
397
pClientConn->getSimNode()->nodePortsInfo[pClientConn->getIbPortNum()].base_lid);
399
status = pSim->getDispatcher()->dispatchMad(
400
pClientConn->getSimNode(),
401
pClientConn->getIbPortNum(),
404
pthread_mutex_unlock(&lock);
410
/* handle client request -
411
either create a new client conn or pass it there */
412
/* return 1 on error 0 otherwise */
413
int IBMSServer::proccessClientMsg(
415
int reqLen, char request[],
416
int &resLen, char *(pResponse[]) )
420
MSGREG(err1, 'E', "Message is not of ibms_client_msg_t size ($ != $)",
422
MSGREG(inf1, 'V', "Received:\n$","server");
424
if (reqLen != sizeof(ibms_client_msg_t))
426
MSGSND(err1, reqLen, sizeof(ibms_client_msg_t));
431
ibms_client_msg_t *p_req = (ibms_client_msg_t*)request;
432
MSGSND(inf1, ibms_get_msg_str(p_req));
434
/* allocate new response */
435
/* NOTE: the allocated buffer for the response is deallocated by
436
the call from the GenServer::clientThreadMain */
437
resLen = sizeof(ibms_response_t);
438
*pResponse = new char[sizeof(ibms_response_t)];
439
ibms_response_t *pResp = (ibms_response_t *)(*pResponse);
440
memset(pResp, 0, sizeof(ibms_response_t));
442
switch (p_req->msg_type)
444
case IBMS_CLI_MSG_CONN:
445
pResp->status = handleConnectionMsg(clientSock, p_req->msg.conn);
447
case IBMS_CLI_MSG_DISCONN:
448
pResp->status = handleDisconnectMsg(clientSock, p_req->msg.disc);
450
case IBMS_CLI_MSG_BIND:
451
pResp->status = handleBindMsg(clientSock, p_req->msg.bind);
453
case IBMS_CLI_MSG_CAP:
454
pResp->status = handleCapMsg(clientSock, p_req->msg.cap);
456
case IBMS_CLI_MSG_MAD:
457
pResp->status = handleMadMsg(clientSock, p_req->msg.mad);
459
case IBMS_CLI_MSG_QUIT:
460
MSGREG(inf2, 'V', "Asked to quit. Quitting...","server");
469
/* we always succeed for now */
475
//////////////////////////////////////////////////////////////
477
// CLASS IBMSClientMsgProcessor
481
Specialization of IBMSMadProcessor - this processor is being created
482
for each "BIND" command requested by the client. It should handle
483
forwarding of the MAD that it got to the client by invoking the
487
/* if filter is matched - forward the mad msg to the client send() */
489
IBMSClientMsgProcessor::processMad(
491
ibms_mad_msg_t &madMsg)
495
ibms_response_t response;
496
ibms_client_msg_t fwdMsg;
499
MSGREG(inf1, 'V', "Forwarding MAD tid:$ to client node:$ port:$","server");
500
MSGREG(inf2, 'V', "Ignoring MAD tid:$ node:$ port:$ != cli port:$","server");
502
fwdMsg.msg_type = IBMS_CLI_MSG_MAD;
503
fwdMsg.msg.mad = madMsg;
505
IBNode *pNode = pClient->getSimNode()->getIBNode();
507
/* ignore mads arriving on the other port */
508
if ((inPort != 0) && (pClient->getIbPortNum() != inPort))
510
MSGSND(inf2, cl_ntoh64(fwdMsg.msg.mad.header.trans_id),
511
pNode->name, inPort, pClient->getIbPortNum());
516
MSGSND(inf1, cl_ntoh64(fwdMsg.msg.mad.header.trans_id),
517
pNode->name, pClient->getIbPortNum());
519
/* get the clientConn object */
520
/* invoke its sendMsg with the provided message */
521
pClient->sendMsg(sizeof(ibms_client_msg_t), (char*)&fwdMsg,
522
respSize, (char *)&response);