1 /* Copyright (C) 2014 InfiniDB, Inc.
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18 /******************************************************************************
19 * $Id$
20 *
21 *****************************************************************************/
22
23 /** @file umsocketselector.cpp
24 * Used to iterate through available socket/port connections for a given UM,
25 * when sending response messages back to the UM.
26 */
27
28 #include "umsocketselector.h"
29 #ifdef _MSC_VER
30 #define WIN32_LEAN_AND_MEAN
31 #define NOMINMAX
32 #include <windows.h>
33 #include <winsock2.h>
34 #include <ws2tcpip.h>
35 #include <stdio.h>
36 #else
37 #include <arpa/inet.h>
38 #include <sys/socket.h>
39 #endif
40 #include <iostream>
41 #include <climits>
42 #include <sstream>
43 #include <cstring>
44 #include <limits>
45
46 #include "liboamcpp.h"
47 using namespace oam;
48
49 //#define NDEBUG
50 #include <cassert>
51
52 //#define LOAD_MODULE_DEBUG 1
53 //#define MOD_CONN_DEBUG 1
54 //#define SEL_CONN_DEBUG 1
55
56 namespace primitiveprocessor
57 {
58 /*static*/ const int32_t UmIPSocketConns::NEXT_IOSOCKET_UNASSIGNED = -1;
59 /*static*/ const int32_t UmModuleIPs::NEXT_IP_SOCKET_UNASSIGNED = -1;
60 /*static*/ UmSocketSelector* UmSocketSelector::fpUmSocketSelector = 0;
61
62 //------------------------------------------------------------------------------
63 // UmSocketSelector methods
64 //------------------------------------------------------------------------------
65 // UmSocketSelector Singleton accessor
66 //------------------------------------------------------------------------------
67 /* static */ UmSocketSelector*
instance()68 UmSocketSelector::instance()
69 {
70 if (fpUmSocketSelector == 0)
71 {
72 fpUmSocketSelector = new UmSocketSelector();
73 }
74
75 return fpUmSocketSelector;
76 }
77
78 //------------------------------------------------------------------------------
79 // UmSocketSelector constructor
80 //------------------------------------------------------------------------------
UmSocketSelector()81 UmSocketSelector::UmSocketSelector()
82 {
83 loadUMModuleInfo();
84 }
85
86 //------------------------------------------------------------------------------
87 // Returns the number of IP addresses defined in the Columnstore.xml file
88 // return - uint32_t; the total number of IP addresses in the Columnstore.xml file
89 //------------------------------------------------------------------------------
90 uint32_t
ipAddressCount() const91 UmSocketSelector::ipAddressCount() const
92 {
93 uint32_t ipCount = 0;
94
95 for (unsigned int i = 0; i < fUmModuleIPs.size(); ++i)
96 {
97 ipCount += fUmModuleIPs[i]->ipAddressCount();
98 }
99
100 return ipCount;
101 }
102
103 //------------------------------------------------------------------------------
104 // Loads the UM module information from the Columnstore.xml file, so that we have
105 // the list of IP addresses that are valid for each UM. Note that this method
106 // does not insure thread safeness, but that's okay because it is assumed that
107 // it will only be called once from the first call to instance().
108 //------------------------------------------------------------------------------
109 void
loadUMModuleInfo()110 UmSocketSelector::loadUMModuleInfo()
111 {
112 Oam oam;
113 ModuleTypeConfig moduleTypeConfig;
114 const std::string UM_MODTYPE("um");
115
116 oam.getSystemConfig(UM_MODTYPE, moduleTypeConfig);
117
118 int moduleCount = moduleTypeConfig.ModuleCount;
119 std::string moduleType = moduleTypeConfig.ModuleType;
120
121 #ifdef LOAD_MODULE_DEBUG
122 std::cout << "ModuleConfig for type: " << UM_MODTYPE << std::endl;
123 std::cout << "ModuleDesc = " << moduleTypeConfig.ModuleDesc << std::endl;
124 std::cout << "ModuleCount = " << moduleCount << std::endl;
125 std::cout << "RunType = " << moduleTypeConfig.RunType << std::endl;
126 #endif
127
128 if ( moduleCount > 0 )
129 {
130 //..Loop through the list of UM modules
131 for (DeviceNetworkList::iterator iter1 =
132 moduleTypeConfig.ModuleNetworkList.begin();
133 (iter1 != moduleTypeConfig.ModuleNetworkList.end());
134 ++iter1)
135 {
136 std::string moduleName = iter1->DeviceName;
137
138 #ifdef LOAD_MODULE_DEBUG
139 std::cout << "ModuleName-" << moduleName << std::endl;
140 #endif
141
142 //..Assign the UM index based on whether it is a new UM or one
143 // we have seen before
144 unsigned int umIdx = findOrAddUm( moduleName );
145
146 //..Get the list of IP addresses (NIC's) for this UM module
147 for (HostConfigList::iterator iter2 = iter1->hostConfigList.begin();
148 (iter2 != iter1->hostConfigList.end());
149 ++iter2)
150 {
151 std::string ipAddr = iter2->IPAddr;
152
153 #ifdef LOAD_MODULE_DEBUG
154 std::cout << " NIC-" << iter2->NicID <<
155 "; host-" << iter2->HostName <<
156 "; IP-" << ipAddr << std::endl;
157 #endif
158
159 struct in_addr ip;
160
161 if ( inet_aton(ipAddr.c_str(), &ip ) )
162 {
163 fIpAddressUmMap[ ip.s_addr ] = umIdx;
164 fUmModuleIPs[umIdx]->addIP( ip.s_addr );
165 }
166 else
167 {
168 std::cerr << "Invalid IP address in SystemModuleConfig "
169 "section: " << ipAddr << std::endl;
170 }
171 } // loop through the IP addresses for a UM module
172 } // loop through the list of UM modules
173 } // moduleCount > 0
174 }
175
176 //------------------------------------------------------------------------------
177 // Search for the specified moduleName, and return the applicable index from
178 // fUmModuleIPs, if it is found. Else add the new moduleName.
179 // return - unsigned int for the index into fUmModuleIPs for moduleName.
180 //------------------------------------------------------------------------------
181 unsigned int
findOrAddUm(const std::string & moduleName)182 UmSocketSelector::findOrAddUm( const std::string& moduleName )
183 {
184 unsigned int umIdx = std::numeric_limits<unsigned int>::max();
185
186 for (unsigned int i = 0; i < fUmModuleIPs.size(); ++i)
187 {
188 if (fUmModuleIPs[i]->moduleName() == moduleName)
189 {
190 umIdx = i;
191 return umIdx;
192 }
193 }
194
195 //..We have encountered a new UM module we should add to the list
196 fUmModuleIPs.push_back( SP_UM_MODIPS(new UmModuleIPs(moduleName)) );
197 umIdx = fUmModuleIPs.size() - 1;
198
199 return umIdx;
200 }
201
202 //------------------------------------------------------------------------------
203 // Add a new socket/port connection. It will be grouped with other
204 // socket/port connections belonging to the same UM.
205 // ios (in) - socket/port connection to be added
206 // writeLock (in) - mutex to use when writing to ios.
207 // return - boolean indicating whether socket/port connection was added.
208 //------------------------------------------------------------------------------
209 bool
addConnection(const SP_UM_IOSOCK & ios,const SP_UM_MUTEX & writeLock)210 UmSocketSelector::addConnection(
211 const SP_UM_IOSOCK& ios,
212 const SP_UM_MUTEX& writeLock )
213 {
214 bool bConnAdded = false;
215
216 sockaddr sa = ios->sa();
217 const sockaddr_in* sinp = reinterpret_cast<const sockaddr_in*>(&sa);
218 IpAddressUmMap_t::iterator mapIter =
219 fIpAddressUmMap.find ( sinp->sin_addr.s_addr );
220
221 // Add this socket/port connection to the UM connection list it belongs to.
222 if ( mapIter != fIpAddressUmMap.end() )
223 {
224 unsigned int umIdx = mapIter->second;
225 bConnAdded = fUmModuleIPs[umIdx]->addSocketConn( ios, writeLock );
226 }
227
228 if (!bConnAdded)
229 {
230 #ifdef SEL_CONN_DEBUG
231 std::ostringstream oss;
232 oss << "No UM/IP match found to add connection " << ios->toString() <<
233 std::endl;
234 std::cout << oss.str();
235 #endif
236 }
237
238 return bConnAdded;
239 }
240
241 //------------------------------------------------------------------------------
242 // Delete a socket/port connection from the UM for which it belongs.
243 // ioSock (in) - socket/port connection to be deleted
244 //------------------------------------------------------------------------------
245 void
delConnection(const messageqcpp::IOSocket & ios)246 UmSocketSelector::delConnection( const messageqcpp::IOSocket& ios )
247 {
248 sockaddr sa = ios.sa();
249 const sockaddr_in* sinp = reinterpret_cast<const sockaddr_in*>(&sa);
250 IpAddressUmMap_t::iterator mapIter =
251 fIpAddressUmMap.find ( sinp->sin_addr.s_addr );
252
253 if ( mapIter != fIpAddressUmMap.end() )
254 {
255 unsigned int umIdx = mapIter->second;
256 fUmModuleIPs[umIdx]->delSocketConn( ios );
257 }
258 }
259
260 //------------------------------------------------------------------------------
261 // Get the next socket/port connection belonging to the same UM as ios.
262 // The selected socket/port connection will be returned in outIos. It can
263 // then be used for sending the next response message back to the applicable
264 // UM module.
265 // ios (in) - socket/port connection where a UM request originated from
266 // outIos (out) - socket/port connection to use in sending the
267 // corresponding response
268 // writelock (out) - mutex lock to be used when writing to outIos
269 // return - bool indicating if socket/port connection was assigned to
270 // outIos
271 //------------------------------------------------------------------------------
272 bool
nextIOSocket(const messageqcpp::IOSocket & ios,SP_UM_IOSOCK & outIos,SP_UM_MUTEX & writeLock)273 UmSocketSelector::nextIOSocket(
274 const messageqcpp::IOSocket& ios,
275 SP_UM_IOSOCK& outIos,
276 SP_UM_MUTEX& writeLock )
277 {
278 sockaddr sa = ios.sa();
279 const sockaddr_in* sinp = reinterpret_cast<const sockaddr_in*>(&sa);
280 IpAddressUmMap_t::iterator mapIter =
281 fIpAddressUmMap.find ( sinp->sin_addr.s_addr );
282
283 if ( mapIter != fIpAddressUmMap.end() )
284 {
285 unsigned int umIdx = mapIter->second;
286
287 if (fUmModuleIPs[umIdx]->nextIOSocket( outIos, writeLock ))
288 {
289
290 #ifdef SEL_CONN_DEBUG
291 std::ostringstream oss;
292 oss << "UM " << fUmModuleIPs[umIdx]->moduleName() <<
293 "; in: " << ios.toString() <<
294 "; selected out: " << outIos->toString() << std::endl;
295 std::cout << oss.str();
296 #endif
297
298 return true;
299 }
300 }
301
302 //..This should not happen. Application is asking for next socket/port for
303 // a connection not in our UM module list.
304 return false;
305 }
306
307 //------------------------------------------------------------------------------
308 // Convert contents to string for logging, debugging, etc.
309 //------------------------------------------------------------------------------
310 const std::string
toString() const311 UmSocketSelector::toString() const
312 {
313 std::ostringstream oss;
314
315 oss << "IP Address to UM index map:" << std::endl;
316
317 for (IpAddressUmMap_t::const_iterator mapIter = fIpAddressUmMap.begin();
318 (mapIter != fIpAddressUmMap.end());
319 ++mapIter)
320 {
321 char ipString[INET_ADDRSTRLEN];
322 oss << " IPAddress: " <<
323 UmIPSocketConns::nwToString(mapIter->first, ipString) <<
324 " maps to UM: " << mapIter->second << std::endl;
325 }
326
327 for (unsigned int i = 0; i < fUmModuleIPs.size(); ++i)
328 {
329 oss << std::endl << fUmModuleIPs[i]->toString();
330 }
331
332 return oss.str();
333 }
334
335 //------------------------------------------------------------------------------
336 // UmModuleIPs methods
337 //------------------------------------------------------------------------------
338 // Add an IP address to be associated with this UM module.
339 // ip (in) - IP address to associate with this UM module (in network byte order)
340 //------------------------------------------------------------------------------
341 void
addIP(in_addr_t ip)342 UmModuleIPs::addIP( in_addr_t ip )
343 {
344 boost::mutex::scoped_lock lock( fUmModuleMutex );
345
346 #ifdef MOD_CONN_DEBUG
347 std::ostringstream oss;
348 char ipString[INET_ADDRSTRLEN];
349 oss << " UM " << fUmModuleName << "; adding IP: " <<
350 UmIPSocketConns::nwToString(ip, ipString) << std::endl;
351 std::cout << oss.str();
352 #endif
353
354 fUmIPSocketConns.push_back( SP_UM_IPCONNS(new UmIPSocketConns(ip)) );
355 }
356
357 //------------------------------------------------------------------------------
358 // Add a new socket/port connection to this UM. It will be grouped with other
359 // socket/port connections having the same IP address for this UM.
360 // ioSock (in) - socket/port connection to be added
361 // writeLock (in) - mutex to use when writing to ioSock.
362 // return - boolean indicating whether socket/port connection was added.
363 //------------------------------------------------------------------------------
364 bool
addSocketConn(const SP_UM_IOSOCK & ioSock,const SP_UM_MUTEX & writeLock)365 UmModuleIPs::addSocketConn(
366 const SP_UM_IOSOCK& ioSock,
367 const SP_UM_MUTEX& writeLock )
368 {
369 bool bConnAdded = false;
370
371 boost::mutex::scoped_lock lock( fUmModuleMutex );
372
373 for (unsigned int i = 0; i < fUmIPSocketConns.size(); ++i)
374 {
375 sockaddr sa = ioSock->sa();
376 const sockaddr_in* sinp = reinterpret_cast<const sockaddr_in*>(&sa);
377
378 if (fUmIPSocketConns[i]->ipAddress() == sinp->sin_addr.s_addr)
379 {
380
381 #ifdef MOD_CONN_DEBUG
382 std::ostringstream oss;
383 oss << "UM " << fUmModuleName << "; adding connection " <<
384 ioSock->toString() << std::endl;
385 std::cout << oss.str();
386 #endif
387
388 fUmIPSocketConns[i]->addSocketConn ( ioSock, writeLock );
389 bConnAdded = true;
390
391 //..Initialize fNextUmIPSocketIdx if this is the first socket/port
392 // connection for this UM.
393 if ( fNextUmIPSocketIdx == NEXT_IP_SOCKET_UNASSIGNED)
394 fNextUmIPSocketIdx = i;
395
396 break;
397 }
398 }
399
400 return bConnAdded;
401 }
402
403 //------------------------------------------------------------------------------
404 // Delete a socket/port connection from this UM.
405 // ioSock (in) - socket/port connection to be deleted
406 //------------------------------------------------------------------------------
407 void
delSocketConn(const messageqcpp::IOSocket & ioSock)408 UmModuleIPs::delSocketConn( const messageqcpp::IOSocket& ioSock )
409 {
410 boost::mutex::scoped_lock lock( fUmModuleMutex );
411
412 for (unsigned int i = 0; i < fUmIPSocketConns.size(); ++i)
413 {
414 sockaddr sa = ioSock.sa();
415 const sockaddr_in* sinp = reinterpret_cast<const sockaddr_in*>(&sa);
416
417 if (fUmIPSocketConns[i]->ipAddress() == sinp->sin_addr.s_addr)
418 {
419
420 #ifdef MOD_CONN_DEBUG
421 std::ostringstream oss;
422 oss << "UM " << fUmModuleName << "; deleting connection " <<
423 ioSock.toString() << std::endl;
424 std::cout << oss.str();
425 #endif
426
427 fUmIPSocketConns[i]->delSocketConn ( ioSock );
428
429 //..If we just deleted the last connection for this IP, then ad-
430 // vance fNextUmIPSocketIdx to an IP address having connections.
431 if (fUmIPSocketConns[i]->count() == 0)
432 {
433 advanceToNextIP();
434 }
435
436 break;
437 }
438 }
439 }
440
441 //------------------------------------------------------------------------------
442 // Get the next socket/port connection for this UM to use in sending a message
443 // to the applicable UM module.
444 // outIos (out) - socket/port connection to use in sending next msg
445 // writelock (out) - mutex lock to be used when writing to outIos
446 // return - bool indicating if socket/port connection was assigned to
447 // outIos
448 //------------------------------------------------------------------------------
449 bool
nextIOSocket(SP_UM_IOSOCK & outIos,SP_UM_MUTEX & writeLock)450 UmModuleIPs::nextIOSocket( SP_UM_IOSOCK& outIos, SP_UM_MUTEX& writeLock )
451 {
452 bool found = false;
453
454 boost::mutex::scoped_lock lock( fUmModuleMutex );
455
456 if ((fUmIPSocketConns.size() > 0) &&
457 (fNextUmIPSocketIdx != NEXT_IP_SOCKET_UNASSIGNED))
458 {
459 assert (fNextUmIPSocketIdx < static_cast<int>(fUmIPSocketConns.size()));
460 fUmIPSocketConns[fNextUmIPSocketIdx]->nextIOSocket( outIos, writeLock );
461 advanceToNextIP();
462 found = true;
463 }
464
465 return found;
466 }
467
468 //------------------------------------------------------------------------------
469 // Advance to the "next" available IP (for this UM), skipping over
470 // any IP's that have 0 socket/port connections. No mutex locking done, as
471 // the calling methods will have already locked a mutex.
472 //------------------------------------------------------------------------------
473 void
advanceToNextIP()474 UmModuleIPs::advanceToNextIP()
475 {
476 if ( fUmIPSocketConns.size() > 1 )
477 {
478 //..Search to end of IP list for an IP having 1 or more connections
479 for (int i = fNextUmIPSocketIdx + 1;
480 i < static_cast<int>(fUmIPSocketConns.size());
481 ++i)
482 {
483 if (fUmIPSocketConns[i]->count() > 0)
484 {
485 fNextUmIPSocketIdx = i;
486 return;
487 }
488 }
489
490 //..Wrap back around to the start of the list, to continue the search
491 for (int i = 0; i < fNextUmIPSocketIdx; ++i)
492 {
493 if (fUmIPSocketConns[i]->count() > 0)
494 {
495 fNextUmIPSocketIdx = i;
496 return;
497 }
498 }
499
500 fNextUmIPSocketIdx = NEXT_IP_SOCKET_UNASSIGNED;
501 }
502 else // special logic to handle 0 fUmIPSocketConns, or a single empty one
503 {
504 if ((fUmIPSocketConns.size() == 0) ||
505 (fUmIPSocketConns[0]->count() == 0))
506 {
507 fNextUmIPSocketIdx = NEXT_IP_SOCKET_UNASSIGNED;
508 }
509 }
510 }
511
512 //------------------------------------------------------------------------------
513 // Convert contents to string for logging, debugging, etc.
514 //------------------------------------------------------------------------------
515 const std::string
toString()516 UmModuleIPs::toString()
517 {
518 std::ostringstream oss;
519
520 boost::mutex::scoped_lock lock( fUmModuleMutex );
521 oss << "UM module name: " << fUmModuleName <<
522 "; nextUmIPIdx: " << fNextUmIPSocketIdx << std::endl;
523
524 for (unsigned int i = 0; i < fUmIPSocketConns.size(); ++i)
525 {
526 oss << fUmIPSocketConns[i]->toString();
527 }
528
529 return oss.str();
530 }
531
532 //------------------------------------------------------------------------------
533 // UmIPSocketConns methods
534 //------------------------------------------------------------------------------
535 // Add the specified socket/port to the connection list for the IP address
536 // represented by this UmIPSocketConns object.
537 // ioSock (in) - socket/port connection to be added
538 // writeLock (in) - mutex to use when writing to ioSock
539 //------------------------------------------------------------------------------
540 void
addSocketConn(const SP_UM_IOSOCK & ioSock,const SP_UM_MUTEX & writeLock)541 UmIPSocketConns::addSocketConn(
542 const SP_UM_IOSOCK& ioSock,
543 const SP_UM_MUTEX& writeLock )
544 {
545 UmIOSocketData sockData =
546 {
547 SP_UM_IOSOCK(ioSock), SP_UM_MUTEX(writeLock)
548 };
549 fIOSockets.push_back( sockData );
550
551 //..Initialize fNextIOSocketIdx when we add first connection
552 if (fIOSockets.size() == 1)
553 fNextIOSocketIdx = 0;
554 }
555
556 //------------------------------------------------------------------------------
557 // Delete the specified socket/port from the connection list for the IP address
558 // referenced by this UmIPSocketConns object.
559 // ioSock (in) - socket/port connection to be deleted
560 //
561 // Not normally a good thing to be using a std::vector if we are going to be
562 // deleting elements in the middle of the collection. Very inefficient.
563 // But this method won't be called often, and we are only dealing with a small
564 // collection. Plus we want to use a vector over a list, so that nextIOSocket()
565 // can benefit from quick random access.
566 //------------------------------------------------------------------------------
567 void
delSocketConn(const messageqcpp::IOSocket & ioSock)568 UmIPSocketConns::delSocketConn( const messageqcpp::IOSocket& ioSock )
569 {
570 for (unsigned int i = 0; i < fIOSockets.size(); ++i)
571 {
572 sockaddr sa1 = fIOSockets[i].fSock->sa();
573 const sockaddr_in* sinp1 = reinterpret_cast<const sockaddr_in*>(&sa1);
574 sockaddr sa2 = ioSock.sa();
575 const sockaddr_in* sinp2 = reinterpret_cast<const sockaddr_in*>(&sa2);
576
577 if (sinp1->sin_port == sinp2->sin_port)
578 {
579 fIOSockets.erase ( fIOSockets.begin() + i );
580
581 //..Adjust fNextIOSocketIdx
582 // 1a. decrement if fNextIOSocketIdx is after deleted connection
583 // 1b. reset to start of vector if we deleted the last connection
584 // 2. reset fNextIOSocketIdx to -1 if we have no more connections
585 if (fIOSockets.size() > 0)
586 {
587 if (fNextIOSocketIdx > static_cast<int>(i))
588 fNextIOSocketIdx--;
589
590 if ( fNextIOSocketIdx >= static_cast<int>(fIOSockets.size()) )
591 fNextIOSocketIdx = 0;
592 }
593 else
594 {
595 fNextIOSocketIdx = NEXT_IOSOCKET_UNASSIGNED;
596 }
597
598 break;
599 }
600 }
601 }
602
603 //------------------------------------------------------------------------------
604 // Get the next socket/port connection for this IP to use in sending a message
605 // to the applicable UM module.
606 // outIos (out) - socket/port connection to use in sending next msg
607 // writelock (out) - mutex lock to be used when writing to outIos
608 //------------------------------------------------------------------------------
609 void
nextIOSocket(SP_UM_IOSOCK & outIos,SP_UM_MUTEX & writeLock)610 UmIPSocketConns::nextIOSocket ( SP_UM_IOSOCK& outIos, SP_UM_MUTEX& writeLock )
611 {
612 assert (fIOSockets.size() > 0);
613 assert (fNextIOSocketIdx != NEXT_IOSOCKET_UNASSIGNED);
614 assert (fNextIOSocketIdx < static_cast<int>(fIOSockets.size()));
615
616 outIos = fIOSockets[fNextIOSocketIdx].fSock;
617 writeLock = fIOSockets[fNextIOSocketIdx].fMutex;
618
619 //..Update "next" index, being sure to wrap around to the start
620 // whenever we reach the end of the vector.
621 fNextIOSocketIdx++;
622
623 if (fNextIOSocketIdx >= static_cast<int>(fIOSockets.size()))
624 fNextIOSocketIdx = 0;
625 }
626
627 //------------------------------------------------------------------------------
628 // Convert network byte ordered IP address to a string.
629 // return - char* is returned with the IP address string.
630 //------------------------------------------------------------------------------
631 /* static */ char*
nwToString(in_addr_t addr,char * ipString)632 UmIPSocketConns::nwToString( in_addr_t addr, char* ipString )
633 {
634 in_addr addrStruct = { addr };
635 #ifndef _MSC_VER
636
637 if (!inet_ntop(AF_INET, &addrStruct, ipString, INET_ADDRSTRLEN))
638 #endif
639 strcpy(ipString, "unknown");
640
641 return ipString;
642 }
643
644 //------------------------------------------------------------------------------
645 // Convert contents to string for logging, debugging, etc.
646 //------------------------------------------------------------------------------
647 const std::string
toString() const648 UmIPSocketConns::toString() const
649 {
650 std::ostringstream oss;
651
652 char ipString[INET_ADDRSTRLEN];
653 oss << " IPAddress: " << UmIPSocketConns::nwToString(fIpAddress, ipString) <<
654 "; nextIOSocketIdx: " << fNextIOSocketIdx << std::endl;
655
656 for (unsigned int i = 0; i < fIOSockets.size(); ++i)
657 {
658 sockaddr sa = fIOSockets[i].fSock->sa();
659 const sockaddr_in* sinp = reinterpret_cast<const sockaddr_in*>(&sa);
660 oss << " port: " << ntohs(sinp->sin_port) <<
661 std::endl;
662 }
663
664 return oss.str();
665 }
666
667 } // end of primitiveprocessor namespace
668