SOCK_Dgram_Bcast.cpp

Go to the documentation of this file.
00001 // SOCK_Dgram_Bcast.cpp,v 4.45 2006/05/30 10:57:22 jwillemsen Exp
00002 
00003 #include "ace/SOCK_Dgram_Bcast.h"
00004 
00005 #include "ace/Log_Msg.h"
00006 #include "ace/ACE.h"
00007 #include "ace/OS_NS_string.h"
00008 #include "ace/os_include/net/os_if.h"
00009 #include "ace/OS_NS_netdb.h"
00010 #include "ace/OS_Memory.h"
00011 
00012 #if !defined (__ACE_INLINE__)
00013 #include "ace/SOCK_Dgram_Bcast.inl"
00014 #endif /* __ACE_INLINE__ */
00015 
00016 ACE_RCSID(ace, SOCK_Dgram_Bcast, "SOCK_Dgram_Bcast.cpp,v 4.45 2006/05/30 10:57:22 jwillemsen Exp")
00017 
00018 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00019 
00020 ACE_ALLOC_HOOK_DEFINE(ACE_SOCK_Dgram_Bcast)
00021 
00022 ACE_Bcast_Node::ACE_Bcast_Node (ACE_INET_Addr &addr,
00023                                 ACE_Bcast_Node *next)
00024   : bcast_addr_ (addr),
00025     next_ (next)
00026 {
00027   ACE_TRACE ("ACE_Bcast_Node::ACE_Bcast_Node");
00028 }
00029 
00030 void
00031 ACE_SOCK_Dgram_Bcast::dump (void) const
00032 {
00033 #if defined (ACE_HAS_DUMP)
00034   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::dump");
00035 #endif /* ACE_HAS_DUMP */
00036 }
00037 
00038 // Close up and release resources.
00039 
00040 int
00041 ACE_SOCK_Dgram_Bcast::close (void)
00042 {
00043   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::close");
00044 
00045   ACE_Bcast_Node *temp = this->if_list_;
00046   this->if_list_ = 0;
00047 
00048   // Release the dynamically allocated memory.
00049 
00050   while (temp != 0)
00051     {
00052       ACE_Bcast_Node *hold = temp->next_;
00053       delete temp;
00054       temp = hold;
00055     }
00056 
00057   // Shut down the descriptor.
00058   return ACE_SOCK::close ();
00059 }
00060 
00061 // Here's the simple-minded constructor.
00062 
00063 ACE_SOCK_Dgram_Bcast::ACE_SOCK_Dgram_Bcast (void)
00064   : if_list_ (0)
00065 {
00066   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::ACE_SOCK_Dgram_Bcast");
00067 }
00068 
00069 // Here's the general-purpose constructor used by a connectionless
00070 // datagram ``server''...
00071 
00072 ACE_SOCK_Dgram_Bcast::ACE_SOCK_Dgram_Bcast (const ACE_Addr &local,
00073                                             int protocol_family,
00074                                             int protocol,
00075                                             int reuse_addr,
00076                                             const ACE_TCHAR *host_name)
00077   : ACE_SOCK_Dgram (local, protocol_family, protocol, reuse_addr),
00078     if_list_ (0)
00079 {
00080   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::ACE_SOCK_Dgram_Bcast");
00081 
00082   if (this->mk_broadcast (host_name) == -1)
00083     ACE_ERROR ((LM_ERROR,
00084                 ACE_LIB_TEXT ("%p\n"),
00085                 ACE_LIB_TEXT ("ACE_SOCK_Dgram_Bcast")));
00086 }
00087 
00088 // Here's the general-purpose open routine.
00089 
00090 int
00091 ACE_SOCK_Dgram_Bcast::open (const ACE_Addr &local,
00092                             int protocol_family,
00093                             int protocol,
00094                             int reuse_addr,
00095                             const ACE_TCHAR *host_name)
00096 {
00097   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::open");
00098 
00099   if (this->ACE_SOCK_Dgram::open (local, protocol_family,
00100                                   protocol, reuse_addr) == -1)
00101     return -1;
00102 
00103   return this->mk_broadcast (host_name);
00104 }
00105 
00106 // Make broadcast available for Datagram socket.
00107 
00108 int
00109 ACE_SOCK_Dgram_Bcast::mk_broadcast (const ACE_TCHAR *host_name)
00110 {
00111   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::mk_broadcast");
00112 
00113   int one = 1;
00114 
00115   if (ACE_OS::setsockopt (this->get_handle (),
00116                           SOL_SOCKET,
00117                           SO_BROADCAST,
00118                           (char *) &one,
00119                           sizeof one) == -1)
00120     ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
00121                       "ACE_SOCK_Dgram_Bcast::mk_broadcast: setsockopt failed"),
00122                       -1);
00123 
00124 #if !defined (ACE_WIN32) && !defined(__INTERIX)
00125   ACE_HANDLE s = this->get_handle ();
00126 
00127   char buf[BUFSIZ];
00128   struct ifconf ifc;
00129 
00130   ifc.ifc_len = sizeof buf;
00131   ifc.ifc_buf = buf;
00132 
00133   // Get interface structure and initialize the addresses using UNIX
00134   // techniques.
00135   if (ACE_OS::ioctl (s,
00136                      SIOCGIFCONF,
00137                      (char *) &ifc) == -1)
00138     ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
00139                       "ACE_SOCK_Dgram_Bcast::mk_broadcast: ioctl (get interface configuration)"),
00140                       ACE_INVALID_HANDLE);
00141 
00142   struct ifreq *ifr = ifc.ifc_req;
00143 
00144   struct sockaddr_in host_addr;
00145 
00146   // Get host ip address
00147   if (host_name)
00148     {
00149       hostent *hp = ACE_OS::gethostbyname (ACE_TEXT_ALWAYS_CHAR (host_name));
00150 
00151       if (hp == 0)
00152         return -1;
00153       else
00154 #if defined(_UNICOS)
00155         {
00156           ACE_UINT64 haddr;  // a place to put the address
00157           char * haddrp = (char *) &haddr;  // convert to char pointer
00158           ACE_OS::memcpy(haddrp,(char *) hp->h_addr,hp->h_length);
00159           host_addr.sin_addr.s_addr = haddr;
00160         }
00161 #else /* ! _UNICOS */
00162         ACE_OS::memcpy ((char *) &host_addr.sin_addr.s_addr,
00163                         (char *) hp->h_addr,
00164                         hp->h_length);
00165 #endif /* ! _UNICOS */
00166     }
00167 
00168 
00169 #if !defined(AIX) && !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_VXWORKS) && !defined(__APPLE__)
00170   for (int n = ifc.ifc_len / sizeof (struct ifreq) ; n > 0;
00171        n--, ifr++)
00172 #else
00173   /*
00174      There are addresses longer than sizeof (struct sockaddr) eg. IPv6
00175      or QNX::links. In this case address does not fit into struct ifreq.
00176      The code below could be applied everywhere, but not every system
00177          provides sockaddr.sa_len field.
00178    */
00179   for (int nbytes = ifc.ifc_len; nbytes >= (int) sizeof (struct ifreq) &&
00180         ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ?
00181           (nbytes >= (int) sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len) : 1);
00182         ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ?
00183           (nbytes -= sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len,
00184             ifr = (struct ifreq *)
00185               ((caddr_t) &ifr->ifr_addr + ifr->ifr_addr.sa_len)) :
00186           (nbytes -= sizeof (struct ifreq), ifr++)))
00187 #endif /* !defined(AIX) && !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_VXWORKS) && !defined(__APPLE__) */
00188     {
00189 #if defined (__QNX__) || defined (ACE_VXWORKS)
00190       // Silently skip link interfaces
00191       if (ifr->ifr_addr.sa_family == AF_LINK)
00192         continue;
00193 #endif /* __QNX__ */
00194       // Compare host ip address with interface ip address.
00195       if (host_name)
00196         {
00197           struct sockaddr_in if_addr;
00198 
00199           ACE_OS::memcpy (&if_addr,
00200                           &ifr->ifr_addr,
00201                           sizeof if_addr);
00202 
00203           if (host_addr.sin_addr.s_addr != if_addr.sin_addr.s_addr)
00204             continue;
00205         }
00206 
00207       if (ifr->ifr_addr.sa_family != AF_INET)
00208         {
00209           // Note that some systems seem to generate 0 (AF_UNDEF) for
00210           // the sa_family, even when there are no errors!  Thus, we
00211           // only print an error if this is not the case, or if we're
00212           // in "debugging" mode.
00213           if (ifr->ifr_addr.sa_family != 0
00214               || ACE::debug () > 0)
00215           ACE_DEBUG ((LM_DEBUG,
00216                       "warning %p: sa_family: %d\n",
00217                       "ACE_SOCK_Dgram_Bcast::mk_broadcast: Not AF_INET",
00218                       ifr->ifr_addr.sa_family));
00219           continue;
00220         }
00221 
00222       struct ifreq flags = *ifr;
00223       struct ifreq if_req = *ifr;
00224 
00225       if (ACE_OS::ioctl (s,
00226                          SIOCGIFFLAGS,
00227                          (char *) &flags) == -1)
00228         {
00229           ACE_ERROR ((LM_ERROR, "%p [%s]\n",
00230                                                  "ACE_SOCK_Dgram_Bcast::mk_broadcast: ioctl (get interface flags)",
00231                                                  flags.ifr_name));
00232           continue;
00233         }
00234 
00235       if (ACE_BIT_ENABLED (flags.ifr_flags,
00236                            IFF_UP) == 0)
00237         {
00238           ACE_ERROR ((LM_ERROR, "%p [%s]\n",
00239                                                  "ACE_SOCK_Dgram_Bcast::mk_broadcast: Network interface is not up",
00240                                                  flags.ifr_name));
00241           continue;
00242         }
00243 
00244       if (ACE_BIT_ENABLED (flags.ifr_flags,
00245                            IFF_LOOPBACK))
00246         continue;
00247 
00248       if (ACE_BIT_ENABLED (flags.ifr_flags,
00249                            IFF_BROADCAST))
00250         {
00251           if (ACE_OS::ioctl (s,
00252                              SIOCGIFBRDADDR,
00253                              (char *) &if_req) == -1)
00254             ACE_ERROR ((LM_ERROR, "%p [%s]\n",
00255                                                    "ACE_SOCK_Dgram_Bcast::mk_broadcast: ioctl (get broadaddr)",
00256                                                    flags.ifr_name));
00257           else
00258             {
00259               ACE_INET_Addr addr (reinterpret_cast <sockaddr_in *>
00260                                                    (&if_req.ifr_broadaddr),
00261                                   sizeof if_req.ifr_broadaddr);
00262               ACE_NEW_RETURN (this->if_list_,
00263                               ACE_Bcast_Node (addr,
00264                                               this->if_list_),
00265                               -1);
00266             }
00267         }
00268       else
00269         {
00270           if (host_name != 0)
00271             ACE_ERROR ((LM_ERROR, "%p [%s]\n",
00272                         "ACE_SOCK_Dgram_Bcast::mk_broadcast: Broadcast is not enable for this interface.",
00273                         flags.ifr_name));
00274         }
00275     }
00276 #else
00277   ACE_UNUSED_ARG (host_name);
00278 
00279   ACE_INET_Addr addr (u_short (0),
00280                       ACE_UINT32 (INADDR_BROADCAST));
00281   ACE_NEW_RETURN (this->if_list_,
00282                   ACE_Bcast_Node (addr,
00283                                   this->if_list_),
00284                   -1);
00285 #endif /* !ACE_WIN32 && !__INTERIX */
00286   if (this->if_list_ == 0)
00287     {
00288       errno = ENXIO;
00289       return -1;
00290     }
00291   else
00292     return 0;
00293 }
00294 
00295 // Broadcast the datagram to every interface.  Returns the average
00296 // number of bytes sent.
00297 
00298 ssize_t
00299 ACE_SOCK_Dgram_Bcast::send (const void *buf,
00300                             size_t n,
00301                             u_short port_number,
00302                             int flags) const
00303 {
00304   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::send");
00305   ssize_t iterations = 0;
00306   ssize_t total_bytes = 0;
00307 
00308   if (this->if_list_ == 0)
00309     return -1;
00310 
00311   for (ACE_Bcast_Node *temp = this->if_list_;
00312        temp != 0;
00313        temp = temp->next_)
00314     {
00315       temp->bcast_addr_.set_port_number (port_number);
00316 
00317       ssize_t bytes_sent = ACE_SOCK_Dgram::send (buf,
00318                                                  n,
00319                                                  temp->bcast_addr_,
00320                                                  flags);
00321 
00322       if (bytes_sent == -1)
00323         return -1;
00324       else
00325         total_bytes += bytes_sent;
00326 
00327       iterations++;
00328     }
00329 
00330   return iterations == 0 ? 0 : total_bytes / iterations;
00331 }
00332 
00333 #if defined (ACE_HAS_MSG)
00334 // Broadcast datagram to every interfaces.
00335 
00336 ssize_t
00337 ACE_SOCK_Dgram_Bcast::send (const iovec iov[],
00338                             int n,
00339                             u_short port_number,
00340                             int flags) const
00341 {
00342   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::send");
00343 
00344   if (this->if_list_ == 0)
00345     return -1;
00346 
00347   // Send the message to every interface.
00348 
00349   for (ACE_Bcast_Node *temp = this->if_list_;
00350        temp != 0;
00351        temp = temp->next_)
00352     {
00353       temp->bcast_addr_.set_port_number (port_number);
00354 
00355       if (ACE_SOCK_Dgram::send (iov,
00356                                 n,
00357                                 temp->bcast_addr_,
00358                                 flags) == -1)
00359         return -1;
00360     }
00361 
00362   return 0;
00363 }
00364 
00365 // Broadcast an iovec of size N to ADDR as a datagram (note that addr
00366 // must be preassigned to the broadcast address of the subnet...).
00367 
00368 ssize_t
00369 ACE_SOCK_Dgram_Bcast::send (const iovec iov[],
00370                             int n,
00371                             const ACE_Addr &addr,
00372                             int flags) const
00373 {
00374   ACE_TRACE ("ACE_SOCK_Dgram_Bcast::send");
00375 
00376   return ACE_SOCK_Dgram::send (iov, n, addr, flags);
00377 }
00378 #endif /* ACE_HAS_MSG */
00379 
00380 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:42:04 2006 for ACE by doxygen 1.3.6