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