summaryrefslogtreecommitdiff
path: root/libcult/cult/os/net/ipv4/multicast-socket.hxx
blob: 70207a3135afa12ce1a13cee377e312df7d4cc07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// file      : cult/os/net/ipv4/multicast-socket.hxx
// author    : Boris Kolpackov <boris@kolpackov.Net>
// copyright : Copyright (c) 2005-2010 Boris Kolpackov
// license   : GNU GPL v2 + exceptions; see accompanying LICENSE file

#ifndef CULT_OS_NET_IPV4_MULTICAST_SOCKET_HXX
#define CULT_OS_NET_IPV4_MULTICAST_SOCKET_HXX

#include <cult/types.hxx>

#include <cult/os/net/address.hxx>
#include <cult/os/net/multicast-socket.hxx>
#include <cult/os/net/ipv4/address.hxx>
#include <cult/os/net/ipv4/datagram-socket.hxx>

#include <cstring>      // memcpy
#include <sys/socket.h> // bind, setsockopt
#include <arpa/inet.h>  // htonl

namespace Cult
{
  namespace OS
  {
    namespace Net
    {
      namespace IPv4
      {
        //@@ Add MulticastAddress (with proper checks)?
	//

        class MulticastSocket : public virtual Net::MulticastSocket,
                                public virtual DatagramSocket
        {
        public:
          virtual
          ~MulticastSocket ()
          {
          }

        public:
          MulticastSocket (Boolean loop = true, UnsignedShort ttl = 1)
          {
            unsigned char ttl_ (static_cast<unsigned char> (ttl));

            {
              Int flag (1);

              if (::setsockopt (sock_,
                                SOL_SOCKET,
                                SO_REUSEADDR,
                                &flag,
                                sizeof (flag)) == -1)
              {
                throw Exception ();
              }
            }

            if (ttl != 1)
            {
              if (::setsockopt (sock_,
                                IPPROTO_IP,
                                IP_MULTICAST_TTL,
                                &ttl_,
                                sizeof (ttl_)) == -1)
              {
                throw Exception ();
              }
            }

            if (!loop)
            {
              unsigned char flag (0);

              if (::setsockopt (sock_,
                                IPPROTO_IP,
                                IP_MULTICAST_LOOP,
                                &flag,
                                sizeof (flag)) == -1)
              {
                throw Exception ();
              }
            }

          }

        public:
          virtual Void
          join (Net::Address const& addr)
          {
            if (addr.familiy () != familiy ())
              throw InvalidAddress ();

            join (dynamic_cast<Address const&> (addr));
          }

          virtual Void
          join (Address const& addr)
          {
            ip_mreq mreq;

            std::memcpy (&mreq.imr_multiaddr,
                         &addr.addr ().sin_addr,
                         sizeof (in_addr));

            mreq.imr_interface.s_addr = htonl (INADDR_ANY);

            if (::setsockopt (sock_,
                              IPPROTO_IP,
                              IP_ADD_MEMBERSHIP,
                              &mreq,
                              sizeof (mreq)) == -1)
            {
              throw Exception ();
            }

            if (::bind (sock_, addr.raw_addr (), addr.raw_size ()) == -1)
              throw Exception ();
          }

          virtual Void
          leave ()
          {
            //@@ TODO
            abort ();
          }
        };
      }
    }
  }
}


#endif  // CULT_OS_NET_IPV4_MULTICAST_SOCKET_HXX