~ubuntu-branches/ubuntu/raring/ibutils/raring-proposed

« back to all changes in this revision

Viewing changes to ibmgtsim/src/server.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Benoit Mortier
  • Date: 2010-01-11 22:22:00 UTC
  • Revision ID: james.westby@ubuntu.com-20100111222200-53kum2et5nh13rv3
Tags: upstream-1.2-OFED-1.4.2
ImportĀ upstreamĀ versionĀ 1.2-OFED-1.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2004 Mellanox Technologies LTD. All rights reserved.
 
3
 *
 
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:
 
9
 *
 
10
 *     Redistribution and use in source and binary forms, with or
 
11
 *     without modification, are permitted provided that the following
 
12
 *     conditions are met:
 
13
 *
 
14
 *      - Redistributions of source code must retain the above
 
15
 *        copyright notice, this list of conditions and the following
 
16
 *        disclaimer.
 
17
 *
 
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.
 
22
 *
 
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
 
30
 * SOFTWARE.
 
31
 *
 
32
 * $Id$
 
33
 */
 
34
 
 
35
#include "server.h"
 
36
#include "msgmgr.h"
 
37
#include "helper.h"
 
38
 
 
39
//////////////////////////////////////////////////////////////
 
40
//
 
41
// CLASS  IBMSClientConn
 
42
//
 
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() */
 
48
#include "sim.h"
 
49
 
 
50
/*
 
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.
 
54
*/
 
55
 
 
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  */
 
60
int
 
61
IBMSClientConn::handleBindMsg(
 
62
  ibms_bind_msg_t &msg)
 
63
{
 
64
  MSG_ENTER_FUNC;
 
65
  MSGREG(err1, 'E', "Fail to create a new mad processor.", "server");
 
66
 
 
67
  /* create a new client mad processor */
 
68
  IBMSClientMsgProcessor *madProcessor =
 
69
    new IBMSClientMsgProcessor(this, msg);
 
70
  if (madProcessor == NULL)
 
71
  {
 
72
    MSGSND(err1);
 
73
    MSG_EXIT_FUNC;
 
74
    return 1;
 
75
  }
 
76
 
 
77
  /* keep track of active mad processors */
 
78
  madProcessors.push_back(madProcessor);
 
79
 
 
80
  MSG_EXIT_FUNC;
 
81
  return 0;
 
82
}
 
83
 
 
84
/* destructor - needs to cleanup any binding done through this conn */
 
85
IBMSClientConn::~IBMSClientConn()
 
86
{
 
87
  MSG_ENTER_FUNC;
 
88
  /* NOTE: each mad processor will lock the node */
 
89
  for(list_pmad_proc::iterator lI = madProcessors.begin();
 
90
      lI != madProcessors.end();
 
91
      lI++)
 
92
  {
 
93
    delete *lI;
 
94
  }
 
95
  MSG_EXIT_FUNC;
 
96
}
 
97
 
 
98
//////////////////////////////////////////////////////////////
 
99
//
 
100
// CLASS  IBMSServer
 
101
//
 
102
 
 
103
IBMSServer::IBMSServer(IBMgtSim *pS, unsigned short portNum) :
 
104
  GenServer(portNum, sizeof(ibms_client_msg_t))
 
105
{
 
106
  MSG_ENTER_FUNC;
 
107
  char hostName[32];
 
108
  gethostname(hostName, sizeof(hostName)-1);
 
109
 
 
110
  pSim = pS;
 
111
 
 
112
  /* the generic gen server might fail */
 
113
  if (isAlive())
 
114
  {
 
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())
 
121
    {
 
122
      serverFile << hostName << " " << portNum << endl;
 
123
      serverFile.close();
 
124
    }
 
125
    else
 
126
    {
 
127
      MSGREG(err1, 'E', "Fail to create file:$", "server");
 
128
      MSGSND(err1, serverFileName);
 
129
    }
 
130
  }
 
131
  MSG_EXIT_FUNC;
 
132
}
 
133
 
 
134
/* cleaning up client when notified it is closing */
 
135
int IBMSServer::closingClient(
 
136
  int clientSock)
 
137
{
 
138
  MSG_ENTER_FUNC;
 
139
  map_sock_client::iterator sI = sockToClientMap.find(clientSock);
 
140
  if (sI != sockToClientMap.end())
 
141
  {
 
142
    IBMSClientConn *pClientConn = (*sI).second;
 
143
    sockToClientMap.erase(sI);
 
144
    delete pClientConn;
 
145
  }
 
146
  MSG_EXIT_FUNC;
 
147
  return(0);
 
148
}
 
149
 
 
150
/* handle a connection message */
 
151
int IBMSServer::handleConnectionMsg(
 
152
  int clientSock,
 
153
  ibms_conn_msg_t &connMsg)
 
154
{
 
155
  MSG_ENTER_FUNC;
 
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");
 
160
 
 
161
  IBFabric *pFabric = pSim->getFabric();
 
162
 
 
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())
 
167
  {
 
168
    MSGSND(err1, connMsg.port_guid);
 
169
    MSG_EXIT_FUNC;
 
170
    return 1;
 
171
  }
 
172
 
 
173
  IBPort *pPort = (*pI).second;
 
174
  IBNode *pNode = pPort->p_node;
 
175
  IBMSNode *pMgtNode = ibmsGetIBNodeSimNode(pNode);
 
176
 
 
177
  MSGSND(inf1, pNode->name, pPort->num);
 
178
 
 
179
  /* we need to lock the map of the server to insert the new client */
 
180
  pthread_mutex_lock(&lock);
 
181
 
 
182
  /* if the client is not previously registered */
 
183
  map_sock_client::iterator sI = sockToClientMap.find(clientSock);
 
184
  if (sI != sockToClientMap.end())
 
185
  {
 
186
    MSGSND(err2, clientSock);
 
187
    pthread_mutex_unlock(&lock);
 
188
    MSG_EXIT_FUNC;
 
189
    return 1;
 
190
  }
 
191
 
 
192
  /* create a new client object */
 
193
  IBMSClientConn *clientConn =
 
194
    new IBMSClientConn(pMgtNode, pPort->num,
 
195
                       &connMsg.host[0], connMsg.in_msg_port);
 
196
 
 
197
  if (clientConn == NULL)
 
198
  {
 
199
    MSGSND(err3);
 
200
    pthread_mutex_unlock(&lock);
 
201
    MSG_EXIT_FUNC;
 
202
    return 1;
 
203
  }
 
204
 
 
205
  /* insert to the map */
 
206
  sockToClientMap[clientSock] = clientConn;
 
207
 
 
208
  /* unlock the map */
 
209
  pthread_mutex_unlock(&lock);
 
210
 
 
211
  MSG_EXIT_FUNC;
 
212
  return 0;
 
213
}
 
214
 
 
215
/* handle a disconnect message */
 
216
int
 
217
IBMSServer::handleDisconnectMsg(
 
218
  int clientSock,
 
219
  ibms_disconn_msg_t &discMsg)
 
220
{
 
221
  MSG_ENTER_FUNC;
 
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:$.",
 
225
         "server");
 
226
 
 
227
  IBFabric *pFabric = pSim->getFabric();
 
228
 
 
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())
 
233
  {
 
234
    MSGSND(err1, discMsg.port_guid);
 
235
    MSG_EXIT_FUNC;
 
236
    return 1;
 
237
  }
 
238
 
 
239
  IBPort *pPort = (*pI).second;
 
240
  IBNode *pNode = pPort->p_node;
 
241
 
 
242
  MSGSND(inf1, pNode->name, pPort->num);
 
243
 
 
244
  /* we need to lock the map of the server to delete the client */
 
245
  pthread_mutex_lock(&lock);
 
246
 
 
247
  /* if the client is not previously registered */
 
248
  map_sock_client::iterator sI = sockToClientMap.find(clientSock);
 
249
  if (sI == sockToClientMap.end())
 
250
  {
 
251
    MSGSND(err2, clientSock);
 
252
    pthread_mutex_unlock(&lock);
 
253
    MSG_EXIT_FUNC;
 
254
    return 1;
 
255
  }
 
256
 
 
257
  /* remove the connection from the list and delete it */
 
258
  IBMSClientConn *clientConn = (*sI).second;
 
259
  sockToClientMap.erase(sI);
 
260
 
 
261
  /* unlock the map */
 
262
  pthread_mutex_unlock(&lock);
 
263
 
 
264
  /*
 
265
         we need to delete the client itself not under the lock
 
266
         since otherwise we will run into deadlock with the node lock
 
267
  */
 
268
  delete clientConn;
 
269
 
 
270
  MSG_EXIT_FUNC;
 
271
  return 0;
 
272
}
 
273
 
 
274
/* handle a bind message */
 
275
int
 
276
IBMSServer::handleBindMsg(
 
277
  int clientSock,
 
278
  ibms_bind_msg_t &bindMsg)
 
279
{
 
280
  MSG_ENTER_FUNC;
 
281
  int status;
 
282
 
 
283
  MSGREG(err1, 'E', "Socket $ was not previously connected.", "server");
 
284
 
 
285
  pthread_mutex_lock(&lock);
 
286
 
 
287
  /* find the client conn for the given sock */
 
288
  map_sock_client::iterator sI = sockToClientMap.find(clientSock);
 
289
 
 
290
  /* if none then fail */
 
291
  if (sI == sockToClientMap.end())
 
292
  {
 
293
    MSGSND(err1, clientSock);
 
294
    pthread_mutex_unlock(&lock);
 
295
    MSG_EXIT_FUNC;
 
296
    return 1;
 
297
  }
 
298
 
 
299
  IBMSClientConn *pClient = (*sI).second;
 
300
  IBMSNode *pSimNode = pClient->pSimNode;
 
301
 
 
302
  pthread_mutex_unlock(&lock);
 
303
 
 
304
  /* now that we know the client we can pre-lock the node */
 
305
  pthread_mutex_lock(&pSimNode->lock);
 
306
  pthread_mutex_lock(&lock);
 
307
 
 
308
  /* to be safe we find again */
 
309
  sI = sockToClientMap.find(clientSock);
 
310
  if (sI == sockToClientMap.end())
 
311
  {
 
312
    MSGSND(err1, clientSock);
 
313
    pthread_mutex_unlock(&lock);
 
314
         pthread_mutex_unlock(&pSimNode->lock);
 
315
    MSG_EXIT_FUNC;
 
316
    return 1;
 
317
  }
 
318
 
 
319
  status = (*sI).second->handleBindMsg(bindMsg);
 
320
 
 
321
  pthread_mutex_unlock(&lock);
 
322
  pthread_mutex_unlock(&pSimNode->lock);
 
323
 
 
324
  MSG_EXIT_FUNC;
 
325
  return(status);
 
326
}
 
327
 
 
328
/* handle a bind message */
 
329
int
 
330
IBMSServer::handleCapMsg(
 
331
  int clientSock,
 
332
  ibms_cap_msg_t &capMsg)
 
333
{
 
334
  MSG_ENTER_FUNC;
 
335
  MSGREG(err1, 'E', "Socket $ was not previously connected.", "server");
 
336
 
 
337
  pthread_mutex_lock(&lock);
 
338
 
 
339
  /* find the client conn for the given sock */
 
340
  map_sock_client::iterator sI = sockToClientMap.find(clientSock);
 
341
 
 
342
  /* if none then fail */
 
343
  if (sI == sockToClientMap.end())
 
344
  {
 
345
    MSGSND(err1, clientSock);
 
346
    pthread_mutex_unlock(&lock);
 
347
    MSG_EXIT_FUNC;
 
348
    return 1;
 
349
  }
 
350
 
 
351
  /* if we know the client we know the port number and node */
 
352
  IBMSClientConn *pCli = (*sI).second;
 
353
 
 
354
  ib_port_info_t *pPortInfo =
 
355
    &(pCli->getSimNode()->nodePortsInfo[pCli->getIbPortNum()]);
 
356
 
 
357
  pthread_mutex_unlock(&lock);
 
358
 
 
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 );
 
363
 
 
364
  MSG_EXIT_FUNC;
 
365
  return(0);
 
366
}
 
367
 
 
368
/* handle a mad message */
 
369
int
 
370
IBMSServer::handleMadMsg(
 
371
  int clientSock,
 
372
  ibms_mad_msg_t &madMsg)
 
373
{
 
374
  MSG_ENTER_FUNC;
 
375
  int status;
 
376
  MSGREG(err1, 'E', "Socket $ was not previously connected.", "server");
 
377
 
 
378
  pthread_mutex_lock(&lock);
 
379
 
 
380
  /* find the client conn for the given sock */
 
381
  map_sock_client::iterator sI = sockToClientMap.find(clientSock);
 
382
 
 
383
  /* if none then fail */
 
384
  if (sI == sockToClientMap.end())
 
385
  {
 
386
    MSGSND(err1, clientSock);
 
387
    pthread_mutex_unlock(&lock);
 
388
    MSG_EXIT_FUNC;
 
389
    return 1;
 
390
  }
 
391
 
 
392
  IBMSClientConn *pClientConn = (*sI).second;
 
393
 
 
394
  /* we need to replace the source lid with the lid of the port */
 
395
  madMsg.addr.slid =
 
396
    cl_hton16(
 
397
      pClientConn->getSimNode()->nodePortsInfo[pClientConn->getIbPortNum()].base_lid);
 
398
 
 
399
  status = pSim->getDispatcher()->dispatchMad(
 
400
    pClientConn->getSimNode(),
 
401
    pClientConn->getIbPortNum(),
 
402
    madMsg);
 
403
 
 
404
  pthread_mutex_unlock(&lock);
 
405
 
 
406
  MSG_EXIT_FUNC;
 
407
  return status;
 
408
}
 
409
 
 
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(
 
414
  int clientSock,
 
415
  int reqLen, char request[],
 
416
  int &resLen, char *(pResponse[]) )
 
417
{
 
418
 
 
419
  MSG_ENTER_FUNC;
 
420
  MSGREG(err1, 'E', "Message is not of ibms_client_msg_t size ($ != $)",
 
421
         "server");
 
422
  MSGREG(inf1, 'V', "Received:\n$","server");
 
423
 
 
424
  if (reqLen != sizeof(ibms_client_msg_t))
 
425
  {
 
426
    MSGSND(err1, reqLen, sizeof(ibms_client_msg_t));
 
427
    MSG_EXIT_FUNC;
 
428
    return 1;
 
429
  }
 
430
 
 
431
  ibms_client_msg_t *p_req = (ibms_client_msg_t*)request;
 
432
  MSGSND(inf1, ibms_get_msg_str(p_req));
 
433
 
 
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));
 
441
 
 
442
  switch (p_req->msg_type)
 
443
  {
 
444
  case IBMS_CLI_MSG_CONN:
 
445
    pResp->status = handleConnectionMsg(clientSock, p_req->msg.conn);
 
446
    break;
 
447
  case IBMS_CLI_MSG_DISCONN:
 
448
    pResp->status = handleDisconnectMsg(clientSock, p_req->msg.disc);
 
449
    break;
 
450
  case IBMS_CLI_MSG_BIND:
 
451
    pResp->status = handleBindMsg(clientSock, p_req->msg.bind);
 
452
    break;
 
453
  case IBMS_CLI_MSG_CAP:
 
454
    pResp->status = handleCapMsg(clientSock, p_req->msg.cap);
 
455
    break;
 
456
  case IBMS_CLI_MSG_MAD:
 
457
    pResp->status = handleMadMsg(clientSock, p_req->msg.mad);
 
458
    break;
 
459
  case IBMS_CLI_MSG_QUIT:
 
460
    MSGREG(inf2, 'V', "Asked to quit. Quitting...","server");
 
461
    MSGSND(inf2);
 
462
    usleep(100000);
 
463
    exit(0);
 
464
    break;
 
465
  default:
 
466
    break;
 
467
  }
 
468
 
 
469
  /* we always succeed for now */
 
470
 
 
471
  MSG_EXIT_FUNC;
 
472
  return 0;
 
473
}
 
474
 
 
475
//////////////////////////////////////////////////////////////
 
476
//
 
477
// CLASS  IBMSClientMsgProcessor
 
478
//
 
479
 
 
480
/*
 
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
 
484
  client send method.
 
485
*/
 
486
 
 
487
/* if filter is matched - forward the mad msg to the client send() */
 
488
int
 
489
IBMSClientMsgProcessor::processMad(
 
490
  uint8_t inPort,
 
491
  ibms_mad_msg_t &madMsg)
 
492
{
 
493
  MSG_ENTER_FUNC;
 
494
 
 
495
  ibms_response_t response;
 
496
  ibms_client_msg_t fwdMsg;
 
497
  int respSize;
 
498
 
 
499
  MSGREG(inf1, 'V', "Forwarding MAD tid:$ to client node:$ port:$","server");
 
500
  MSGREG(inf2, 'V', "Ignoring MAD tid:$ node:$ port:$ != cli port:$","server");
 
501
 
 
502
  fwdMsg.msg_type = IBMS_CLI_MSG_MAD;
 
503
  fwdMsg.msg.mad = madMsg;
 
504
 
 
505
  IBNode *pNode = pClient->getSimNode()->getIBNode();
 
506
 
 
507
  /* ignore mads arriving on the other port */
 
508
  if ((inPort != 0) && (pClient->getIbPortNum() != inPort))
 
509
  {
 
510
    MSGSND(inf2, cl_ntoh64(fwdMsg.msg.mad.header.trans_id),
 
511
           pNode->name, inPort, pClient->getIbPortNum());
 
512
    MSG_EXIT_FUNC;
 
513
    return 0;
 
514
  }
 
515
 
 
516
  MSGSND(inf1, cl_ntoh64(fwdMsg.msg.mad.header.trans_id),
 
517
         pNode->name, pClient->getIbPortNum());
 
518
 
 
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);
 
523
 
 
524
  MSG_EXIT_FUNC;
 
525
  return 0;
 
526
}