Line data Source code
1 : // Copyright (c) 2012-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program; if not, write to the Free Software
18 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Event dispatch class.
22 : *
23 : * Class used to handle events.
24 : */
25 :
26 :
27 : // self
28 : //
29 : #include "eventdispatcher/local_dgram_base.h"
30 :
31 : #include "eventdispatcher/exception.h"
32 :
33 :
34 : // libaddr lib
35 : //
36 : //#include <libaddr/iface.h>
37 :
38 :
39 : // C lib
40 : //
41 : //#include <net/if.h>
42 : //#include <netinet/ip.h>
43 : //#include <netinet/udp.h>
44 : //#include <sys/ioctl.h>
45 :
46 :
47 : // last include
48 : //
49 : #include <snapdev/poison.h>
50 :
51 :
52 :
53 :
54 : namespace ed
55 : {
56 :
57 :
58 :
59 : /** \brief Initialize a UDP base object.
60 : *
61 : * This function initializes the UDP base object using the address and the
62 : * port as specified.
63 : *
64 : * The port is expected to be a host side port number (i.e. 59200).
65 : *
66 : * The \p addr parameter is a textual address. It may be an IPv4 or IPv6
67 : * address and it can represent a host name or an address defined with
68 : * just numbers. If the address cannot be resolved then an error occurs
69 : * and the constructor throws.
70 : *
71 : * \note
72 : * The socket is open in this process. If you fork() and exec() then the
73 : * socket gets closed by the operating system (i.e. close on exec()).
74 : *
75 : * \warning
76 : * We only make use of the first address found by getaddrinfo(). All
77 : * the other addresses are ignored.
78 : *
79 : * \todo
80 : * Add a constructor that supports a libaddr::addr object instead of
81 : * just a string address.
82 : *
83 : * \exception event_dispatcher_invalid_parameter
84 : * The \p addr parameter is empty or the port is out of the supported range.
85 : *
86 : * \exception event_dispatcher_runtime_error
87 : * The server could not be initialized properly. Either the address cannot be
88 : * resolved, the port is incompatible or not available, or the socket could
89 : * not be created.
90 : *
91 : * \param[in] address The address to connect/listen to.
92 : * \param[in] sequential Whether the packets have to be 100% sequential.
93 : * \param[in] close_on_exec Whether the socket has to be closed on execve().
94 : */
95 5 : local_dgram_base::local_dgram_base(
96 : addr::unix const & address
97 : , bool sequential
98 5 : , bool close_on_exec)
99 5 : : f_address(address)
100 : {
101 5 : int type(sequential ? SOCK_SEQPACKET : SOCK_DGRAM);
102 5 : if(close_on_exec)
103 : {
104 5 : type |= SOCK_CLOEXEC;
105 : }
106 :
107 5 : f_socket.reset(socket(AF_UNIX, type, 0));
108 5 : if(f_socket == nullptr)
109 : {
110 : throw event_dispatcher_runtime_error(
111 : "could not create socket for: \""
112 0 : + f_address.to_uri()
113 0 : + "\".");
114 : }
115 :
116 : // get the "MTU" maximum size right away for
117 : // (1) it is really fast; and
118 : // (2) it is going to work right before a first write() but may not
119 : // be if a write() was not yet fully processed
120 : //
121 5 : socklen_t optlen;
122 5 : optlen = sizeof(f_mtu_size);
123 5 : int const r(getsockopt(
124 10 : f_socket.get()
125 : , SOL_SOCKET
126 : , SO_SNDBUF
127 5 : , &f_mtu_size
128 10 : , &optlen));
129 5 : if(r != 0)
130 : {
131 : throw event_dispatcher_runtime_error(
132 : "could not retrieve \"MTU\" size for: \""
133 0 : + f_address.to_uri()
134 0 : + "\".");
135 : }
136 5 : }
137 :
138 :
139 : /** \brief The local datagram destructor.
140 : *
141 : * To avoid potential errors with virtual destruction, we have a virtual
142 : * destructor in this base class.
143 : */
144 5 : local_dgram_base::~local_dgram_base()
145 : {
146 5 : }
147 :
148 :
149 : /** \brief Retrieve a copy of the socket identifier.
150 : *
151 : * This function return the socket identifier as returned by the socket()
152 : * function. This can be used to change some flags.
153 : *
154 : * \return The socket used by this UDP client.
155 : */
156 18 : int local_dgram_base::get_socket() const
157 : {
158 18 : return f_socket.get();
159 : }
160 :
161 :
162 : /** \brief Set whether this UDP socket is to be used to broadcast messages.
163 : *
164 : * This function sets the BROADCAST flagon the socket. This is important
165 : * because by default it is expected that the socket is not used in
166 : * broadcast mode. This makes sure that was your intention.
167 : *
168 : * \note
169 : * We do not try to automatically set the flag for (1) the OS implementation
170 : * expects the end user application to systematically set the flag if
171 : * required and (2) it's complicated to know whether the address represents
172 : * the broadcast address (i.e. you need to get the info on the corresponding
173 : * interface to get the network mask, see whether the interface supports
174 : * broadcasting, etc.) We'll eventually implement that test in our
175 : * libaddr library one day. However, that would be a test we use in the
176 : * send() function to catch errors early (i.e. determine whether the
177 : * socket can be sent to in the current state).
178 : *
179 : * \param[in] state Whether to set (true) or remove (false) the broadcast
180 : * flag on this Unix datagram socket.
181 : */
182 0 : void local_dgram_base::set_broadcast(bool state)
183 : {
184 0 : int const value(state ? 1 : 0);
185 0 : setsockopt(f_socket.get(), SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
186 0 : }
187 :
188 :
189 : /** \brief Retrieve the size of the MTU on that connection.
190 : *
191 : * The "MTU" of the AF_UNIX message is defined by the largest allocatable
192 : * page of memory. This is defined in this file:
193 : *
194 : * /proc/sys/net/core/wmem_max
195 : *
196 : * Note that to get the maximum size of your message, you want to use
197 : * the get_mss_size() instead. The MTU size is the entire packet including
198 : * headers.
199 : *
200 : * \return -1 if the MTU could not be retrieved, the MTU's size otherwise.
201 : */
202 0 : int local_dgram_base::get_mtu_size() const
203 : {
204 0 : return f_mtu_size;
205 : }
206 :
207 :
208 : /** \brief Determine the size of the data buffer we can use.
209 : *
210 : * This function gets the MTU and then subtract the possible header data
211 : * of the packet to
212 : *
213 : * \return The size of the MMU, which is the MTU minus the headers.
214 : */
215 0 : int local_dgram_base::get_mss_size() const
216 : {
217 0 : int const mss(get_mtu_size());
218 0 : return mss < 32 ? -1 : mss - 32; // it looks like the header uses 32 bytes
219 : }
220 :
221 :
222 : /** \brief Retrieve a copy of the address.
223 : *
224 : * This function returns a copy of the address as it was specified in the
225 : * constructor. This does not return a canonicalized version of the address.
226 : *
227 : * The address cannot be modified. If you need to send data on a different
228 : * address, create a new UDP client.
229 : *
230 : * \return A string with a copy of the constructor input address.
231 : */
232 0 : addr::unix local_dgram_base::get_address() const
233 : {
234 0 : return f_address;
235 : }
236 :
237 :
238 :
239 6 : } // namespace ed
240 : // vim: ts=4 sw=4 et
|