/src/messagereader.cc
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}