Code:
26 File: SocketUtils.cpp
27
28 Contains: Implements utility functions defined in SocketUtils.h
29
30
31
32
33 */
34
35 #include <string.h>
36
37 #ifndef __Win32__
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #include <sys/ioctl.h>
44
45 #if __FreeBSD__
46 #include <ifaddrs.h>
47 #endif
48 #include <unistd.h>
49 #include <sys/utsname.h>
50
51 #if __solaris__
52 #include <sys/sockio.h>
53 #endif
54 #endif
55
56 #include "SocketUtils.h"
57
58 #ifdef SIOCGIFNUM
59 #define USE_SIOCGIFNUM 1
60 #endif
61
62 #ifdef TRUCLUSTER /* Tru64 Cluster Alias support */
63
64 #include <clua/clua.h>
65 #include <sys/clu.h>
66
67 static clua_status_t (*clua_getaliasaddress_vector) (struct sockaddr *, int *);
68 static char *(*clua_error_vector) (clua_status_t);
69
70 #define clua_getaliasaddress (*clua_getaliasaddress_vector)
71 #define clua_error (*clua_error_vector)
72
73 struct clucall_vector clua_vectors[] = {
74 { "clua_getaliasaddress", &clua_getaliasaddress_vector },
75 { "clua_error", &clua_error_vector },
76 { NULL, NULL } /* END OF LIST */
77 };
78
79 #endif /* TRUCLUSTER */
80
81 UInt32 SocketUtils::sNumIPAddrs = 0;
82 SocketUtils::IPAddrInfo* SocketUtils::sIPAddrInfoArray = NULL;
83 OSMutex SocketUtils::sMutex;
84
85 #if __FreeBSD__
86
87 //Complete rewrite for FreeBSD.
88 //The non-FreeBSD version really needs to be rewritten - it's a bit of a mess...
89 void SocketUtils::Initialize(Bool16 lookupDNSName)
90 {
91 struct ifaddrs* ifap;
92 struct ifaddrs* currentifap;
93 struct sockaddr_in* sockaddr;
94 int result = 0;
95
96 result = getifaddrs(&ifap);
97
98 //Count them first
99 currentifap = ifap;
100 while( currentifap != NULL )
101 {
102 sockaddr = (struct sockaddr_in*)currentifap->ifa_addr;
103 if (sockaddr->sin_family == AF_INET)
104 sNumIPAddrs++;
105 currentifap = currentifap->ifa_next;
106 }
107
108
109 //allocate the IPAddrInfo array. Unfortunately we can't allocate this
110 //array the proper way due to a GCC bug
111 UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs];
112 ::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs);
113 sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem;
114
115 int addrArrayIndex = 0;
116 currentifap = ifap;
117 while( currentifap != NULL )
118 {
119 sockaddr = (struct sockaddr_in*)currentifap->ifa_addr;
120
121 if (sockaddr->sin_family == AF_INET)
122 {
123 char* theAddrStr = ::inet_ntoa(sockaddr->sin_addr);
124
125 //store the IP addr
126 sIPAddrInfoArray[addrArrayIndex].fIPAddr = ntohl(sockaddr->sin_addr.s_addr);
127
128 //store the IP addr as a string
129 sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
130 sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Le n + 2];
131 ::strcpy(sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Ptr, theAddrStr);
132
133 struct hostent* theDNSName = NULL;
134 if (lookupDNSName) //convert this addr to a dns name, and store it
135 { theDNSName = ::gethostbyaddr((char *)&sockaddr->sin_addr, sizeof(sockaddr->sin_addr), AF_INET);
136 }
137
138 if (theDNSName != NULL)
139 {
140 sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
141 sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[addrArrayIndex].fDNSName Str.Len + 2];
142 ::strcpy(sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr, theDNSName->h_name);
143 }
144 else
145 {
146 //if we failed to look up the DNS name, just store the IP addr as a string
147 sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Len = sIPAddrInfoArray[addrArrayIndex].fIPAddrStr.Len;
148 sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[addrArrayIndex].fDNSName Str.Len + 2];
149 ::strcpy(sIPAddrInfoArray[addrArrayIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[addrArrayIndex].fIPAddrSt r.Ptr);
150 }
151
152 addrArrayIndex++;
153 }
154
155 currentifap = currentifap->ifa_next;
156 }
157
158
159 }
160
161 #else //__FreeBSD__
162
163 //Version for all non-FreeBSD platforms.
164
165 void SocketUtils::Initialize(Bool16 lookupDNSName)
166 {
167 #if defined(__Win32__) || defined(USE_SIOCGIFNUM)
168
169 int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
170 if (tempSocket == -1)
171 return;
172
173 #ifdef __Win32__
174
175 static const UInt32 kMaxAddrBufferSize = 2048;
176 char inBuffer[kMaxAddrBufferSize];
177 char outBuffer[kMaxAddrBufferSize];
178 UInt32 theReturnedSize = 0;
179
180 //
181 // Use the WSAIoctl function call to get a list of IP addresses
182 int theErr = ::WSAIoctl( tempSocket, SIO_GET_INTERFACE_LIST,
183 inBuffer, kMaxAddrBufferSize,
184 outBuffer, kMaxAddrBufferSize,
185 &theReturnedSize,
186 NULL,
187 NULL);
188 Assert(theErr == 0);
189 if (theErr != 0)
190 return;
191
192 Assert((theReturnedSize % sizeof(INTERFACE_INFO)) == 0);
193 LPINTERFACE_INFO addrListP = (LPINTERFACE_INFO)&outBuffer[0];
194
195 sNumIPAddrs = theReturnedSize / sizeof(INTERFACE_INFO);
196 #else
197 #if defined(USE_SIOCGIFNUM)
198 if (::ioctl(tempSocket, SIOCGIFNUM, (char*)&sNumIPAddrs) == -1)
199 {
200 #ifdef MAXIFS
201 sNumIPAddrs = MAXIFS;
202 #else
203 sNumIPAddrs = 64;
204 #endif
205 }
206 #else
207 #error
208 #endif
209 struct ifconf ifc;
210 ::memset(&ifc,0,sizeof(ifc));
211 ifc.ifc_len = sNumIPAddrs * sizeof(struct ifreq);
212 ifc.ifc_buf = (caddr_t)new struct ifreq[sNumIPAddrs];
213 Assert(ifc.ifc_buf != NULL);
214
215 ::memset(ifc.ifc_buf, '\0', ifc.ifc_len);
216 int theErr = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
217 Assert(theErr == 0);
218 if (theErr != 0)
219 return;
220 struct ifreq* ifr = (struct ifreq*)ifc.ifc_buf;
221 #endif
222
223 //allocate the IPAddrInfo array. Unfortunately we can't allocate this
224 //array the proper way due to a GCC bug
225 UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs];
226 ::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs);
227 sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem;
228
229 //for (UInt32 addrCount = 0; addrCount < sNumIPAddrs; addrCount++)
230 UInt32 currentIndex = 0;
231 for (UInt32 theIfCount = sNumIPAddrs, addrCount = 0;
232 addrCount < theIfCount; addrCount++)
233 {
234 #ifdef __Win32__
235 // We *should* count the loopback interface as a valid interface.
236 //if (addrListP[addrCount].iiFlags & IFF_LOOPBACK)
237 //{
238 // Don't count loopback addrs
239 // sNumIPAddrs--;
240 // continue;
241 //}
242 //if (addrListP[addrCount].iiFlags & IFF_LOOPBACK)
243 // if (lookupDNSName) // The playlist broadcaster doesn't care
244 // Assert(addrCount > 0); // If the loopback interface is interface 0, we've got problems
245
246 struct sockaddr_in* theAddr = (struct sockaddr_in*)&addrListP[addrCount].iiAddress;
247 #elif defined(USE_SIOCGIFNUM)
248 if (ifr[addrCount].ifr_addr.sa_family != AF_INET)
249 {
250 sNumIPAddrs--;
251 continue;
252 }
253 struct ifreq ifrf;
254 ::memset(&ifrf,0,sizeof(ifrf));
255 ::strncpy(ifrf.ifr_name, ifr[addrCount].ifr_name, sizeof(ifrf.ifr_name));
256 theErr = ::ioctl(tempSocket, SIOCGIFFLAGS, (char *) &ifrf);
257 Assert(theErr != -1);
258
259 #ifndef __solaris__
260 /* Skip things which aren't interesting */
261 if ((ifrf.ifr_flags & IFF_UP) == 0 ||
262 (ifrf.ifr_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0)
263 {
264 sNumIPAddrs--;
265 continue;
266 }
267 if (ifrf.ifr_flags & IFF_LOOPBACK)
268 {
269 Assert(addrCount > 0); // If the loopback interface is interface 0, we've got problems
270 }
271 #endif
272
273 struct sockaddr_in* theAddr = (struct sockaddr_in*)&ifr[addrCount].ifr_addr;
274 #if 0
275 puts(ifr[addrCount].ifr_name);
276 #endif
277 #else
278 #error
279 #endif
280
281 char* theAddrStr = ::inet_ntoa(theAddr->sin_addr);
282
283 //store the IP addr
284 sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(theAddr->sin_addr.s_addr);
285
286 //store the IP addr as a string
287 sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
288 sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2];
289 ::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr);
290
291
292 struct hostent* theDNSName = NULL;
293 if (lookupDNSName) //convert this addr to a dns name, and store it
294 { theDNSName = ::gethostbyaddr((char *)&theAddr->sin_addr, sizeof(theAddr->sin_addr), AF_INET);
295 }
296
297 if (theDNSName != NULL)
298 {
299 sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
300 sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
301 ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name);
302 }
303 else
304 {
305 //if we failed to look up the DNS name, just store the IP addr as a string
306 sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len;
307 sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2];
308 ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr);
309 }
310 //move onto the next array index
311 currentIndex++;
312
313 }
314 #ifdef __Win32__
315 ::closesocket(tempSocket);
316 #elif defined(USE_SIOCGIFNUM)
317 delete[] ifc.ifc_buf;
318 ::close(tempSocket);
319 #else
320 #error
321 #endif
322
323 #else // !__Win32__
324
325 //Most of this code is similar to the SIOCGIFCONF code presented in Stevens,
326 //Unix Network Programming, section 16.6
327
328 //Use the SIOCGIFCONF ioctl call to iterate through the network interfaces
329 static const UInt32 kMaxAddrBufferSize = 2048;
330
331 struct ifconf ifc;
332 ::memset(&ifc,0,sizeof(ifc));
333 struct ifreq* ifr;
334 char buffer[kMaxAddrBufferSize];
335
336 int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
337 if (tempSocket == -1)
338 return;
339
340 ifc.ifc_len = kMaxAddrBufferSize;
341 ifc.ifc_buf = buffer;
342
343 #if __linux__ || __linuxppc__ || __solaris__ || __MacOSX__ || __sgi__ || __osf__
344 int err = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);
345 #elif __FreeBSD__
346 int err = ::ioctl(tempSocket, OSIOCGIFCONF, (char*)&ifc);
347 #else
348 #error
349 #endif
350 if (err == -1)
351 return;
352
353 #if __FreeBSD__
354 int netdev1, netdev2;
355 struct ifreq *netdevifr;
356 netdevifr = ifc.ifc_req;
357 netdev1 = ifc.ifc_len / sizeof(struct ifreq);
358 for (netdev2=netdev1-1; netdev2>=0; netdev2--)
359 {
360 if (ioctl(tempSocket, SIOCGIFADDR, &netdevifr[netdev2]) != 0)
361 continue;
362 }
363 #endif
364
365 ::close(tempSocket);
366 tempSocket = -1;
367
368 //walk through the list of IP addrs twice. Once to find out how many,
369 //the second time to actually grab their information
370 char* ifReqIter = NULL;
371 sNumIPAddrs = 0;
372
373 for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
374 {
375 ifr = (struct ifreq*)ifReqIter;
376 if (!SocketUtils::IncrementIfReqIter(&ifReqIter, ifr))
377 return;
378
379 // Some platforms have lo as the first interface, so we have code to
380 // work around this problem below
381 //if (::strncmp(ifr->ifr_name, "lo", 2) == 0)
382 // Assert(sNumIPAddrs > 0); // If the loopback interface is interface 0, we've got problems
383
384 //Only count interfaces in the AF_INET family.
385 if (ifr->ifr_addr.sa_family == AF_INET)
386 sNumIPAddrs++;
387 }
388
389 #ifdef TRUCLUSTER
390
391 int clusterAliases = 0;
392
393 if (clu_is_member())
394 {
395 /* loading the vector table */
396 if (clua_getaliasaddress_vector == NULL)
397 {
398 clucall_stat clustat;
399 struct sockaddr_in sin;
400
401 clustat = clucall_load("libclua.so", clua_vectors);
402 int context = 0;
403 clua_status_t addr_err;
404
405 if (clua_getaliasaddress_vector != NULL)
406 while ( (addr_err = clua_getaliasaddress
407 ((struct sockaddr*)&sin, &context)) == CLUA_SUCCESS )
408 {
409 sNumIPAddrs++;
410 clusterAliases++;
411 }
412 }
413
414 }
415
416 #endif // TRUCLUSTER
417
418 //allocate the IPAddrInfo array. Unfortunately we can't allocate this
419 //array the proper way due to a GCC bug
420 UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs];
421 ::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs);
422 sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem;
423
424 //Now extract all the necessary information about each interface
425 //and put it into the array
426 UInt32 currentIndex = 0;
427
428 #ifdef TRUCLUSTER
429 // Do these cluster aliases first so they'll be first in the list
430 if (clusterAliases > 0)
431 {
432 int context = 0;
433 struct sockaddr_in sin;
434 clua_status_t addr_err;
435
436 while ( (addr_err = clua_getaliasaddress ((struct sockaddr*)&sin, &context)) == CLUA_SUCCESS )
437 {
438 char* theAddrStr = ::inet_ntoa(sin.sin_addr);
439
440 //store the IP addr
441 sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(sin.sin_addr.s_addr);
442
443 //store the IP addr as a string
444 sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
445 sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAd drStr.Len + 2];
446 ::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr);
447
448 //convert this addr to a dns name, and store it
449 struct hostent* theDNSName = ::gethostbyaddr((char *)&sin.sin_addr,
450 sizeof(sin.sin_addr), AF_INET );
451 if (theDNSName != NULL)
452 {
453 sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
454 sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentInd ex].fDNSNameStr.Len + 2];
455 ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name);
456 }
457 else
458 {
459 //if we failed to look up the DNS name, just store the IP addr as a string
460 sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAd drStr.Len;
461 sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentInd ex].fDNSNameStr.Len + 2];
462 ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentInde x].fIPAddrStr.Ptr);
463 }
464
465 currentIndex++;
466 }
467 }
468 #endif // TRUCLUSTER
469
470 for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);)
471 {
472 ifr = (struct ifreq*)ifReqIter;
473 if (!SocketUtils::IncrementIfReqIter(&ifReqIter, ifr))
474 {
475 Assert(0);//we should have already detected this error
476 return;
477 }
478
479 //Only count interfaces in the AF_INET family
480 if (ifr->ifr_addr.sa_family == AF_INET)
481 {
483 char* theAddrStr = ::inet_ntoa(addrPtr->sin_addr);
484
485 //store the IP addr
486 sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(addrPtr->sin_addr.s_addr);
487
488 //store the IP addr as a string
489 sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr);
490 sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2];
491 ::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr);
492
493 struct hostent* theDNSName = NULL;
494 if (lookupDNSName) //convert this addr to a dns name, and store it
495 { theDNSName = ::gethostbyaddr((char *)&addrPtr->sin_addr, sizeof(addrPtr->sin_addr), AF_INET);
496 }
497
498 if (theDNSName != NULL)
499 {
500 sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name);
501 sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr. Len + 2];
502 ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name);
503 }
504 else
505 {
506 //if we failed to look up the DNS name, just store the IP addr as a string
507 sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len;
508 sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr. Len + 2];
509 ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Pt r);
510 }
511
512 //move onto the next array index
513 currentIndex++;
514 }
515 }
516
517 Assert(currentIndex == sNumIPAddrs);
518 #endif
519
520 //
521 // If LocalHost is the first element in the array, switch it to be the second.
522 // The first element is supposed to be the "default" interface on the machine,
523 // which should really always be en0.
524 if ((sNumIPAddrs > 1) && (::strcmp(sIPAddrInfoArray[0].fIPAddrStr.Ptr, "127.0.0.1") == 0))
525 {
526 UInt32 tempIP = sIPAddrInfoArray[1].fIPAddr;
527 sIPAddrInfoArray[1].fIPAddr = sIPAddrInfoArray[0].fIPAddr;
528 sIPAddrInfoArray[0].fIPAddr = tempIP;
529 StrPtrLen tempIPStr(sIPAddrInfoArray[1].fIPAddrStr);
530 sIPAddrInfoArray[1].fIPAddrStr = sIPAddrInfoArray[0].fIPAddrStr;
531 sIPAddrInfoArray[0].fIPAddrStr = tempIPStr;
532 StrPtrLen tempDNSStr(sIPAddrInfoArray[1].fDNSNameStr);
533 sIPAddrInfoArray[1].fDNSNameStr = sIPAddrInfoArray[0].fDNSNameStr;
534 sIPAddrInfoArray[0].fDNSNameStr = tempDNSStr;
535 }
536 }
537 #endif //__FreeBSD__
538
539
540
541 #ifndef __Win32__
542 Bool16 SocketUtils::IncrementIfReqIter(char** inIfReqIter, ifreq* ifr)
543 {
544 //returns true if successful, false otherwise
545
546 #if __MacOSX__
547 *inIfReqIter += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
548
549 //if the length of the addr is 0, use the family to determine
550 //what the addr size is
551 if (ifr->ifr_addr.sa_len == 0)
552 #else
553 *inIfReqIter += sizeof(ifr->ifr_name) + 0;
554 #endif
555 {
556 switch (ifr->ifr_addr.sa_family)
557 {
558 case AF_INET:
559 *inIfReqIter += sizeof(struct sockaddr_in);
560 break;
561 default:
562 *inIfReqIter += sizeof(struct sockaddr);
563 // Assert(0);
564 // sNumIPAddrs = 0;
565 // return false;
566 }
567 }
568 return true;
569 }
570 #endif
571
572 Bool16 SocketUtils::IsMulticastIPAddr(UInt32 inAddress)
573 {
574 return ((inAddress>>8) & 0x00f00000) == 0x00e00000; // multicast addresses == "class D" == 0xExxxxxxx == 1,1,1,0 ,<28 bits>
575 }
576
577 Bool16 SocketUtils::IsLocalIPAddr(UInt32 inAddress)
578 {
579 for (UInt32 x = 0; x < sNumIPAddrs; x++)
580 if (sIPAddrInfoArray[x].fIPAddr == inAddress)
581 return true;
582 return false;
583 }
584
585 void SocketUtils::ConvertAddrToString(const struct in_addr& theAddr, StrPtrLen* ioStr)
586 {
587 //re-entrant version of code below
588 //inet_ntop(AF_INET, &theAddr, ioStr->Ptr, ioStr->Len);
589 //ioStr->Len = ::strlen(ioStr->Ptr);
590
591 sMutex.Lock();
592 char* addr = inet_ntoa(theAddr);
593 strcpy(ioStr->Ptr, addr);
594 ioStr->Len = ::strlen(ioStr->Ptr);
595 sMutex.Unlock();
596 }
597
598 UInt32 SocketUtils::ConvertStringToAddr(const char* inAddrStr)
599 {
600 return ntohl(::inet_addr(inAddrStr));
601 }
602
How do I declare a variable of the right type, then do a memcpy() in this case?