PageRenderTime 73ms CodeModel.GetById 1ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 1ms

/src/messagereader.cc

https://github.com/dreibh/netperfmeter
C++ | 305 lines | 228 code | 26 blank | 51 comment | 62 complexity | 06484b500023c2cd5ed08e5855fd27a7 MD5 | raw file
  1/* $Id$
  2 *
  3 * Network Performance Meter
  4 * Copyright (C) 2009-2015 by Thomas Dreibholz
  5 *
  6 * This program is free software: you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License as published by
  8 * the Free Software Foundation, either version 3 of the License, or
  9 * (at your option) any later version.
 10
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 18 *
 19 * Contact: dreibh@iem.uni-due.de
 20 */
 21
 22#include "messagereader.h"
 23
 24#include <stdlib.h>
 25#include <assert.h>
 26#include <string.h>
 27#include <iostream>
 28
 29#include "tools.h"
 30
 31
 32// #define DEBUG_SOCKETS
 33// #define DEBUG_MESSAGEREADER
 34
 35
 36
 37// ###### Constructor #######################################################
 38MessageReader::MessageReader()
 39{
 40}
 41
 42
 43// ###### Destructor ########################################################
 44MessageReader::~MessageReader()
 45{
 46   std::map<int, Socket*>::iterator iterator = SocketMap.begin();
 47   while(iterator != SocketMap.end()) {
 48      Socket* socket = iterator->second;
 49      deregisterSocket(socket->SocketDescriptor);
 50      iterator = SocketMap.begin();
 51   }
 52}
 53
 54
 55// ###### Register a socket #################################################
 56bool MessageReader::registerSocket(const int    protocol,
 57                                   const int    sd,
 58                                   const size_t maxMessageSize)
 59{
 60   Socket*                          socket;
 61   std::map<int, Socket*>::iterator found = SocketMap.find(sd);
 62   if(found == SocketMap.end()) {
 63      assert(maxMessageSize >= sizeof(TLVHeader));
 64
 65      socket = new Socket;
 66      assert(socket != NULL);
 67      socket->MessageBuffer = new char[maxMessageSize];
 68      assert(socket->MessageBuffer != NULL);
 69      socket->MessageBufferSize = maxMessageSize;
 70      socket->MessageSize       = 0;
 71      socket->BytesRead         = 0;
 72      socket->Status            = Socket::MRS_WaitingForHeader;
 73      socket->Protocol          = protocol;
 74      socket->SocketDescriptor  = sd;
 75      socket->UseCount          = 1;
 76      SocketMap.insert(std::pair<int, Socket*>(sd, socket));
 77   }
 78   else {
 79      socket = found->second;
 80      socket->UseCount++;
 81   }
 82#ifdef DEBUG_SOCKETS
 83   printf("RegisterSocket: UseCount[sd=%d,proto=%d]=%u\n",
 84          socket->SocketDescriptor, socket->Protocol, (unsigned int)socket->UseCount);
 85#endif
 86   return(true);
 87}
 88
 89
 90// ###### Get all socket descriptors ########################################
 91size_t MessageReader::getAllSDs(int* sds, const size_t maxEntries)
 92{
 93   assert(maxEntries >= SocketMap.size());
 94   size_t count = 0;
 95   for(std::map<int, Socket*>::iterator iterator = SocketMap.begin(); iterator != SocketMap.end(); iterator++) {
 96      sds[count++] = iterator->second->SocketDescriptor;
 97   }
 98   return(count);
 99}
100
101
102// ###### Deregister a socket ###############################################
103bool MessageReader::deregisterSocket(const int sd)
104{
105   std::map<int, Socket*>::iterator found = SocketMap.find(sd);
106   if(found != SocketMap.end()) {
107      Socket* socket = found->second;
108      socket->UseCount--;
109#ifdef DEBUG_SOCKETS
110      printf("DeregisterSocket: UseCount[sd=%d,proto=%d]=%u\n",
111             socket->SocketDescriptor, socket->Protocol, (unsigned int)socket->UseCount);
112#endif
113      if(socket->UseCount == 0) {
114         SocketMap.erase(found);
115         delete [] socket->MessageBuffer;
116         delete socket;
117         return(true);
118      }
119      return(false);   // Socket is still in use!
120   }
121   return(true);
122}
123
124
125// ###### Receive full message ##############################################
126ssize_t MessageReader::receiveMessage(const int        sd,
127                                      void*            buffer,
128                                      size_t           bufferSize,
129                                      sockaddr*        from,
130                                      socklen_t*       fromSize,
131                                      sctp_sndrcvinfo* sinfo,
132                                      int*             msgFlags)
133{
134   Socket* socket = getSocket(sd);
135   if(socket != NULL) {
136      // ====== Find out the number of bytes to read ========================
137      ssize_t received;
138      size_t  bytesToRead;
139      if( (socket->Protocol == IPPROTO_SCTP) ||
140          (socket->Protocol == IPPROTO_TCP)  ||
141          (socket->Protocol == IPPROTO_MPTCP) ) {
142         // SCTP and TCP can return partial messages upon recv() calls. TCP
143         // may event return multiple messages, if the buffer size is large enough!
144         if(socket->Status == Socket::MRS_WaitingForHeader) {
145            assert(sizeof(TLVHeader) >= socket->BytesRead);
146            bytesToRead = sizeof(TLVHeader) - socket->BytesRead;
147         }
148         else if(socket->Status == Socket::MRS_PartialRead) {
149            bytesToRead = socket->MessageSize - socket->BytesRead;
150         }
151         else {
152            if(socket->Protocol != IPPROTO_TCP) {
153               // An error occurred before. Reset and try again ...
154               socket->Status    = Socket::MRS_WaitingForHeader;
155               socket->BytesRead = 0;
156               bytesToRead       = sizeof(TLVHeader);
157            }
158            else {
159               // Not useful to retry when synchronization has been lost for TCP!
160               return(MRRM_STREAM_ERROR);
161            }
162         }
163         assert(bytesToRead + socket->BytesRead <= socket->MessageBufferSize);
164      }
165      else {
166         // DCCP and UDP will always return only a single message on recv() calls.
167         bytesToRead = socket->MessageBufferSize;
168      }
169
170
171      // ====== Read from socket ============================================
172      int dummyFlags;
173      if(msgFlags == NULL) {
174         dummyFlags = 0;
175         msgFlags   = &dummyFlags;
176      }
177      if(socket->Protocol == IPPROTO_SCTP) {
178         received = sctp_recvmsg(socket->SocketDescriptor,
179                                 (char*)&socket->MessageBuffer[socket->BytesRead], bytesToRead,
180                                 from, fromSize, sinfo, msgFlags);
181      }
182      else {
183         received = ext_recvfrom(socket->SocketDescriptor,
184                                 (char*)&socket->MessageBuffer[socket->BytesRead], bytesToRead,
185                                 *msgFlags, from, fromSize);
186      }
187      // printf("recv(%d)=%d, eor=%d\n", socket->SocketDescriptor, received, ((*msgFlags & MSG_EOR) != 0));
188
189
190      // ====== Handle received data ========================================
191      if(received > 0) {
192         socket->BytesRead += (size_t)received;
193         // ====== Handle message header ====================================
194         if(socket->Status == Socket::MRS_WaitingForHeader) {
195            // ====== Handle SCTP notification header =======================
196            if((socket->Protocol == IPPROTO_SCTP) && (*msgFlags & MSG_NOTIFICATION)) {
197               socket->MessageSize = sizeof(sctp_notification);   // maximum length
198               socket->Status      = Socket::MRS_PartialRead;
199               // SCTP notification has no TLV header, but must be handled like
200               // a message. The actual length of the notification is unknown, we
201               // need to look for MSG_EOF!
202            }
203            // ====== Handle TLV header =====================================
204            else {
205               if(socket->BytesRead >= sizeof(TLVHeader)) {
206                  const TLVHeader* header = (const TLVHeader*)socket->MessageBuffer;
207#ifdef DEBUG_MESSAGEREADER
208                  printf("Socket %d:   T=%u F=%02x L=%u   [Header]\n",
209                          socket->SocketDescriptor,
210                          (unsigned int)header->Type, (unsigned int)header->Flags,
211                         ntohs(header->Length));
212#endif
213                  socket->MessageSize = ntohs(header->Length);
214                  if(socket->MessageSize < sizeof(TLVHeader)) {
215                     std::cerr << "ERROR: Message size < TLV size!" << std::endl;
216                     socket->Status = Socket::MRS_StreamError;
217                     return(MRRM_STREAM_ERROR);
218                  }
219                  else if(socket->MessageSize > socket->MessageBufferSize) {
220                     std::cerr << "ERROR: Message too large to fit buffer!" << std::endl;
221                     socket->Status = Socket::MRS_StreamError;
222                     return(MRRM_STREAM_ERROR);
223                  }
224                  socket->Status = Socket::MRS_PartialRead;
225               }
226               else {
227                  return(MRRM_PARTIAL_READ);
228               }
229            }
230            // Continue here with MRS_PartialRead status!
231            // (will return MRRM_PARTIAL_READ, or message on header-only message)
232         }
233
234         // ====== Handle message payload ===================================
235         if(socket->Status == Socket::MRS_PartialRead) {
236#ifdef DEBUG_MESSAGEREADER
237            printf("Socket %d:   T=%u F=%02x L=%u   [%u/%u]\n",
238                   socket->SocketDescriptor,
239                   ((const TLVHeader*)socket->MessageBuffer)->Type,
240                   ((const TLVHeader*)socket->MessageBuffer)->Flags,
241                   ntohs(((const TLVHeader*)socket->MessageBuffer)->Length),
242                   (unsigned int)socket->BytesRead,
243                   (unsigned int)socket->MessageSize);
244#endif
245
246            // ====== Partially read message ================================
247            if(socket->BytesRead < socket->MessageSize) {
248               if(socket->Protocol == IPPROTO_SCTP) {
249                  if(*msgFlags & MSG_EOR) {   // end of SCTP message
250                     if(!(*msgFlags & MSG_NOTIFICATION)) {   // data message
251                        std::cerr << "ERROR: SCTP message end before TLV message end!" << std::endl
252                                  << "       Read " << socket->BytesRead
253                                  << ", expected " << socket->MessageSize << std::endl;
254                        socket->Status = Socket::MRS_StreamError;
255                        return(MRRM_STREAM_ERROR);
256                     }
257                     // This is the end of the SCTP notification. The message
258                     // is complete here. Return it to the caller.
259                     socket->MessageSize = socket->BytesRead;
260                  }
261                  else {
262                     return(MRRM_PARTIAL_READ);
263                  }
264               }
265               else {
266                  return(MRRM_PARTIAL_READ);
267               }
268            }
269
270            // ====== Completed reading =====================================
271            if(socket->MessageSize > bufferSize) {
272               std::cerr << "ERROR: Buffer size for MessageReader::receiveMessage() is too small!"
273                         << std::endl;
274               socket->Status = Socket::MRS_StreamError;
275               return(MRRM_STREAM_ERROR);
276            }
277            if((socket->Protocol == IPPROTO_SCTP) && (!(*msgFlags & MSG_EOR))) {
278               std::cerr << "ERROR: TLV message end does not match with SCTP message end!"
279                         << std::endl;
280               socket->Status = Socket::MRS_StreamError;
281               return(MRRM_STREAM_ERROR);
282            }
283            received = socket->MessageSize;
284            memcpy(buffer, socket->MessageBuffer, socket->MessageSize);
285            socket->Status      = Socket::MRS_WaitingForHeader;
286            socket->MessageSize = 0;
287            socket->BytesRead   = 0;
288            return(received);
289         }
290         return(MRRM_BAD_SOCKET);
291      }
292      // ====== Handle read errors ==========================================
293      else if(received < 0) {
294         return(MRRM_SOCKET_ERROR);
295      }
296      else {   // received == 0
297         return(received);
298      }
299   }
300   else {
301      std::cerr << "ERROR: Unknown socket " << sd
302                << " given in call of MessageReader::receiveMessage()!" << std::endl;
303      return(MRRM_BAD_SOCKET);
304   }
305}