Medical Imaging Interaction Toolkit  2016.11.0
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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "mitkIGTLServer.h"
18 #include <stdio.h>
19 
20 #include <itksys/SystemTools.hxx>
21 #include <itkMutexLockHolder.h>
22 
23 #include <igtlServerSocket.h>
24 #include <igtlTrackingDataMessage.h>
25 #include <igtlImageMessage.h>
26 #include <igtl_status.h>
27 
29 IGTLDevice(ReadFully)
30 {
33 }
34 
36 {
37  m_ReceiveListMutex = nullptr;
38  m_SentListMutex = nullptr;
39 }
40 
42 {
43  if (this->GetState() != Setup)
44  {
46  "Can only try to create a server if in setup mode";
47  return false;
48  }
49 
50  int portNumber = this->GetPortNumber();
51 
52  if (portNumber == -1)
53  {
54  //port number was not correct
55  return false;
56  }
57 
58  //create a new server socket
59  m_Socket = igtl::ServerSocket::New();
60 
61  //try to create the igtl server
62  int response = dynamic_cast<igtl::ServerSocket*>(m_Socket.GetPointer())->
63  CreateServer(portNumber);
64 
65  //check the response
66  if (response != 0)
67  {
69  "The server could not be created. Port: " << portNumber;
70  return false;
71  }
72 
73  // everything is initialized and connected so the communication can be started
74  this->SetState(Ready);
75 
76  return true;
77 }
78 
80 {
81  //remove all registered clients
82  m_SentListMutex->Lock();
83  m_ReceiveListMutex->Lock();
84  SocketListType allRegisteredSockets(m_RegisteredClients);
85  m_SentListMutex->Unlock();
86  m_ReceiveListMutex->Unlock();
87  this->StopCommunicationWithSocket(allRegisteredSockets);
88 
90 }
91 
93 {
94  igtl::Socket::Pointer socket;
95  //check if another igtl device wants to connect to this socket
96  socket =
97  ((igtl::ServerSocket*)(this->m_Socket.GetPointer()))->WaitForConnection(1);
98  //if there is a new connection the socket is not null
99  if (socket.IsNotNull())
100  {
101  //add the new client socket to the list of registered clients
102  m_SentListMutex->Lock();
103  m_ReceiveListMutex->Lock();
104  this->m_RegisteredClients.push_back(socket);
105  m_SentListMutex->Unlock();
106  m_ReceiveListMutex->Unlock();
107  //inform observers about this new client
108  this->InvokeEvent(NewClientConnectionEvent());
109  MITK_INFO("IGTLServer") << "Connected to a new client: " << socket;
110  }
111 }
112 
114 {
115  unsigned int status = IGTL_STATUS_OK;
116  SocketListType socketsToBeRemoved;
117 
118  //the server can be connected with several clients, therefore it has to check
119  //all registered clients
121  m_ReceiveListMutex->Lock();
122  auto it_end = this->m_RegisteredClients.end();
123  for (it = this->m_RegisteredClients.begin(); it != it_end; ++it)
124  {
125  //it is possible that ReceivePrivate detects that the current socket is
126  //already disconnected. Therefore, it is necessary to remove this socket
127  //from the registered clients list
128  status = this->ReceivePrivate(*it);
129  if (status == IGTL_STATUS_NOT_PRESENT)
130  {
131  //remember this socket for later, it is not a good idea to remove it
132  //from the list directly because we iterate over the list at this point
133  socketsToBeRemoved.push_back(*it);
134  MITK_WARN("IGTLServer") << "Lost connection to a client socket. ";
135  }
136  else if (status != 1)
137  {
138  MITK_WARN("IGTLServer") << "IGTL Message with status: " << status;
139  }
140  }
141  m_ReceiveListMutex->Unlock();
142  if (socketsToBeRemoved.size() > 0)
143  {
144  //remove the sockets that are not connected anymore
145  this->StopCommunicationWithSocket(socketsToBeRemoved);
146  //inform observers about loosing the connection to these sockets
147  this->InvokeEvent(LostConnectionEvent());
148  }
149 }
150 
152 {
153  igtl::MessageBase::Pointer curMessage;
154 
155  //get the latest message from the queue
156  curMessage = this->m_MessageQueue->PullSendMessage();
157 
158  // there is no message => return
159  if (curMessage.IsNull())
160  return;
161 
162  //the server can be connected with several clients, therefore it has to check
163  //all registered clients
164  //sending a message to all registered clients might not be the best solution,
165  //it could be better to store the client together with the requested type. Then
166  //the data would be send to the appropriate client and to noone else.
167  //(I know it is no excuse but PLUS is doing exactly the same, they broadcast
168  //everything)
169  m_SentListMutex->Lock();
171  auto it_end =
172  this->m_RegisteredClients.end();
173  for (it = this->m_RegisteredClients.begin(); it != it_end; ++it)
174  {
175  //maybe there should be a check here if the current socket is still active
176  this->SendMessagePrivate(curMessage.GetPointer(), *it);
177  MITK_DEBUG("IGTLServer") << "Sent IGTL Message";
178  }
179  m_SentListMutex->Unlock();
180 }
181 
183  SocketListType& toBeRemovedSockets)
184 {
185  for (auto i = toBeRemovedSockets.begin(); i != toBeRemovedSockets.end(); i++)
186  this->StopCommunicationWithSocket(*i);
187 }
188 
190 {
191  m_SentListMutex->Lock();
192  m_ReceiveListMutex->Lock();
193  auto i = m_RegisteredClients.begin();
194  auto end = m_RegisteredClients.end();
195  while (i != end)
196  {
197  if ((*i) == client)
198  {
199  // //close the socket
200  (*i)->CloseSocket();
201  //and remove it from the list
202  i = this->m_RegisteredClients.erase(i);
203  MITK_INFO("IGTLServer") << "Removed client socket from server client list.";
204  break;
205  }
206  else
207  {
208  ++i;
209  }
210  }
211  m_SentListMutex->Unlock();
212  m_ReceiveListMutex->Unlock();
213 }
214 
216 {
217  return this->m_RegisteredClients.size();
218 }
virtual 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
itk::SmartPointer< Self > Pointer
virtual void Connect() override
Call this method to check for other devices that want to connect to this one.
#define MITK_INFO
Definition: mitkLogMacros.h:22
virtual bool OpenConnection() override
Initialize the connection for the IGTLServer.
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
itk::FastMutexLock::Pointer m_ReceiveListMutex
IGTLServer(bool ReadFully)
#define MITK_WARN
Definition: mitkLogMacros.h:23
SocketListType::iterator SocketListIteratorType
An object of this class represents an exception of MITK. Please don't instantiate exceptions manually...
Definition: mitkException.h:49
virtual bool CloseConnection()
Closes the connection to the device.
virtual bool CloseConnection() override
Closes the connection to the device.
virtual void Receive() override
Call this method to receive a message.
itk::FastMutexLock::Pointer m_SentListMutex
Interface for all OpenIGTLink Devices.
#define mitkThrowException(classname)
virtual void StopCommunicationWithSocket(SocketListType &toBeRemovedSockets)
Stops the communication with the given sockets.
virtual unsigned int GetNumberOfConnections() override
Returns the number of client connections of this device.
static void Setup()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.