PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/messagereader.cc

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