Medical Imaging Interaction Toolkit  2018.4.99-a3d2e8fb
Medical Imaging Interaction Toolkit
mitkIGTLServer.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkIGTLServer.h"
14 #include <cstdio>
15 
16 #include <itksys/SystemTools.hxx>
17 #include <itkMutexLockHolder.h>
18 
19 #include <igtlServerSocket.h>
20 #include <igtlTrackingDataMessage.h>
21 #include <igtlImageMessage.h>
22 #include <igtl_status.h>
23 
25 IGTLDevice(ReadFully)
26 {
27  m_ReceiveListMutex = itk::FastMutexLock::New();
28  m_SentListMutex = itk::FastMutexLock::New();
29 }
30 
32 {
33  m_ReceiveListMutex = nullptr;
34  m_SentListMutex = nullptr;
35 }
36 
38 {
39  if (this->GetState() != Setup)
40  {
42  "Can only try to create a server if in setup mode";
43  return false;
44  }
45 
46  int portNumber = this->GetPortNumber();
47 
48  if (portNumber == -1)
49  {
50  //port number was not correct
51  return false;
52  }
53 
54  //create a new server socket
55  m_Socket = igtl::ServerSocket::New();
56 
57  //try to create the igtl server
58  int response = dynamic_cast<igtl::ServerSocket*>(m_Socket.GetPointer())->
59  CreateServer(portNumber);
60 
61  //check the response
62  if (response != 0)
63  {
65  "The server could not be created. Port: " << portNumber;
66  return false;
67  }
68 
69  // everything is initialized and connected so the communication can be started
70  this->SetState(Ready);
71 
72  return true;
73 }
74 
76 {
77  //remove all registered clients
78  m_SentListMutex->Lock();
79  m_ReceiveListMutex->Lock();
80  SocketListType allRegisteredSockets(m_RegisteredClients);
81  m_SentListMutex->Unlock();
82  m_ReceiveListMutex->Unlock();
83  this->StopCommunicationWithSocket(allRegisteredSockets);
84 
86 }
87 
89 {
90  igtl::Socket::Pointer socket;
91  //check if another igtl device wants to connect to this socket
92  socket =
93  ((igtl::ServerSocket*)(this->m_Socket.GetPointer()))->WaitForConnection(1);
94  //if there is a new connection the socket is not null
95  if (socket.IsNotNull())
96  {
97  //add the new client socket to the list of registered clients
98  m_SentListMutex->Lock();
99  m_ReceiveListMutex->Lock();
100  this->m_RegisteredClients.push_back(socket);
101  m_SentListMutex->Unlock();
102  m_ReceiveListMutex->Unlock();
103  //inform observers about this new client
104  this->InvokeEvent(NewClientConnectionEvent());
105  MITK_INFO("IGTLServer") << "Connected to a new client: " << socket;
106  }
107 }
108 
110 {
111  unsigned int status = IGTL_STATUS_OK;
112  SocketListType socketsToBeRemoved;
113 
114  //the server can be connected with several clients, therefore it has to check
115  //all registered clients
117  m_ReceiveListMutex->Lock();
118  auto it_end = this->m_RegisteredClients.end();
119  for (it = this->m_RegisteredClients.begin(); it != it_end; ++it)
120  {
121  //it is possible that ReceivePrivate detects that the current socket is
122  //already disconnected. Therefore, it is necessary to remove this socket
123  //from the registered clients list
124  status = this->ReceivePrivate(*it);
125  if (status == IGTL_STATUS_NOT_PRESENT)
126  {
127  //remember this socket for later, it is not a good idea to remove it
128  //from the list directly because we iterate over the list at this point
129  socketsToBeRemoved.push_back(*it);
130  MITK_WARN("IGTLServer") << "Lost connection to a client socket. ";
131  }
132  else if (status != 1)
133  {
134  MITK_DEBUG("IGTLServer") << "IGTL Message with status: " << status;
135  }
136  }
137  m_ReceiveListMutex->Unlock();
138  if (socketsToBeRemoved.size() > 0)
139  {
140  //remove the sockets that are not connected anymore
141  this->StopCommunicationWithSocket(socketsToBeRemoved);
142  //inform observers about loosing the connection to these sockets
143  this->InvokeEvent(LostConnectionEvent());
144  }
145 }
146 
148 {
149  //get the latest message from the queue
150  mitk::IGTLMessage::Pointer curMessage = this->m_MessageQueue->PullSendMessage();
151 
152  // there is no message => return
153  if (curMessage.IsNull())
154  return;
155 
156  //the server can be connected with several clients, therefore it has to check
157  //all registered clients
158  //sending a message to all registered clients might not be the best solution,
159  //it could be better to store the client together with the requested type. Then
160  //the data would be send to the appropriate client and to noone else.
161  //(I know it is no excuse but PLUS is doing exactly the same, they broadcast
162  //everything)
163  m_SentListMutex->Lock();
165  auto it_end =
166  this->m_RegisteredClients.end();
167  for (it = this->m_RegisteredClients.begin(); it != it_end; ++it)
168  {
169  //maybe there should be a check here if the current socket is still active
170  this->SendMessagePrivate(curMessage, *it);
171  MITK_DEBUG("IGTLServer") << "Sent IGTL Message";
172  }
173  m_SentListMutex->Unlock();
174 }
175 
177  SocketListType& toBeRemovedSockets)
178 {
179  for (auto i = toBeRemovedSockets.begin(); i != toBeRemovedSockets.end(); i++)
180  this->StopCommunicationWithSocket(*i);
181 }
182 
184 {
185  m_SentListMutex->Lock();
186  m_ReceiveListMutex->Lock();
187  auto i = m_RegisteredClients.begin();
188  auto end = m_RegisteredClients.end();
189  while (i != end)
190  {
191  if ((*i) == client)
192  {
193  // //close the socket
194  (*i)->CloseSocket();
195  //and remove it from the list
196  i = this->m_RegisteredClients.erase(i);
197  MITK_INFO("IGTLServer") << "Removed client socket from server client list.";
198  break;
199  }
200  else
201  {
202  ++i;
203  }
204  }
205  m_SentListMutex->Unlock();
206  m_ReceiveListMutex->Unlock();
207 }
208 
210 {
211  return this->m_RegisteredClients.size();
212 }
IGTLDeviceState GetState() const
Returns current object state (Setup, Ready or Running)
void Send() override
Call this method to send a message. The message will be read from the queue. So far the message is se...
std::list< igtl::Socket::Pointer > SocketListType
virtual int GetPortNumber()
Returns the port number of the device.
void SetState(IGTLDeviceState state)
change object state
~IGTLServer() override
void Connect() override
Call this method to check for other devices that want to connect to this one.
#define MITK_INFO
Definition: mitkLogMacros.h:18
bool OpenConnection() override
Initialize the connection for the IGTLServer.
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
itk::FastMutexLock::Pointer m_ReceiveListMutex
IGTLServer(bool ReadFully)
unsigned int ReceivePrivate(igtl::Socket *device)
Call this method to receive a message from the given device.
unsigned int SendMessagePrivate(mitk::IGTLMessage::Pointer msg, igtl::Socket::Pointer socket)
Sends a message.
#define MITK_WARN
Definition: mitkLogMacros.h:19
SocketListType::iterator SocketListIteratorType
An object of this class represents an exception of MITK. Please don&#39;t instantiate exceptions manually...
Definition: mitkException.h:45
virtual bool CloseConnection()
Closes the connection to the device.
bool CloseConnection() override
Closes the connection to the device.
void Receive() override
Call this method to receive a message.
itk::FastMutexLock::Pointer m_SentListMutex
mitk::IGTLMessageQueue::Pointer m_MessageQueue
Interface for all OpenIGTLink Devices.
#define mitkThrowException(classname)
igtl::Socket::Pointer m_Socket
virtual void StopCommunicationWithSocket(SocketListType &toBeRemovedSockets)
Stops the communication with the given sockets.
unsigned int GetNumberOfConnections() override
Returns the number of client connections of this device.
SocketListType m_RegisteredClients
A list with all registered clients.