Line data Source code
1 : // Copyright (c) 2012-2022 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/udp_client.h"
30 :
31 :
32 : // last include
33 : //
34 : #include <snapdev/poison.h>
35 :
36 :
37 :
38 : namespace ed
39 : {
40 :
41 :
42 :
43 : /** \brief Initialize a UDP client object.
44 : *
45 : * This function initializes the UDP client object using the address and the
46 : * port as specified.
47 : *
48 : * The port is expected to be a host side port number (i.e. 59200).
49 : *
50 : * The \p addr parameter is a textual address. It may be an IPv4 or IPv6
51 : * address and it can represent a host name or an address defined with
52 : * just numbers. If the address cannot be resolved then an error occurs
53 : * and the constructor throws.
54 : *
55 : * \note
56 : * The socket is open in this process. If you fork() or exec() then the
57 : * socket will be closed by the operating system.
58 : *
59 : * \warning
60 : * We only make use of the first address found by getaddrinfo(). All
61 : * the other addresses are ignored.
62 : *
63 : * \exception udp_client_server_runtime_error
64 : * The server could not be initialized properly. Either the address cannot be
65 : * resolved, the port is incompatible or not available, or the socket could
66 : * not be created.
67 : *
68 : * \param[in] address The address and port.
69 : */
70 0 : udp_client::udp_client(addr::addr const & address)
71 0 : : udp_base(address)
72 : {
73 0 : }
74 :
75 :
76 : /** \brief Clean up the UDP client object.
77 : *
78 : * This function frees the address information structure and close the socket
79 : * before returning.
80 : */
81 0 : udp_client::~udp_client()
82 : {
83 0 : }
84 :
85 :
86 : /** \brief Send a message through this UDP client.
87 : *
88 : * This function sends \p msg through the UDP client socket. The function
89 : * cannot be used to change the destination as it was defined when creating
90 : * the udp_client object.
91 : *
92 : * The size must be small enough for the message to fit. In most cases, we
93 : * use these in Snap! to send very small signals (i.e. 4 bytes commands.)
94 : * Any data we would want to share remains in the Cassandra database so
95 : * that way we can avoid losing it because of a UDP message.
96 : *
97 : * \note
98 : * The send may fail with EAGAIN, EWOULDBLOCK, or ENOBUFS which all mean
99 : * that the attempt can be tried again. The ENOBUFS means that a new buffer
100 : * could not be allocated, not that the UDP queue is full or that packets
101 : * are being lost because too many are being sent in a row. Also, you want
102 : * to control the size of your buffer with get_mss_size(). UDP buffers that
103 : * are larger will be broken up in multiple packets and that increases the
104 : * chance that the packet never arrives. Also over a certain size (probably
105 : * around 64K in IPv4) the ENOBUFS automatically happens. Note that IPv6
106 : * allows for much buffer packets. This is not automatically a good idea
107 : * unless the number of packets is quite small because when it fails, you
108 : * have to resend a very large packet...
109 : *
110 : * \note
111 : * To avoid drop of UDP messages, you need to time your calls to the send()
112 : * function taking in account the amount of data being sent and the network
113 : * speed. On the lo network, the throughput is very high and packets can be
114 : * really large (nearly 64Kb). On a local network, check the size with the
115 : * get_mss_size() function and (TBD how?) check the speed. You certainly
116 : * can use up to about 95% of the speed without much problems assuming that
117 : * the pipe is only used by these UDP packets. Too much and the dropping is
118 : * going to increase steadily.
119 : *
120 : * \todo
121 : * See whether we could always use the IPv6 to avoid the duplication of the
122 : * client.
123 : *
124 : * \param[in] msg The message to send.
125 : * \param[in] size The number of bytes representing this message.
126 : *
127 : * \return -1 if an error occurs, otherwise the number of bytes sent. errno
128 : * is set accordingly on error.
129 : */
130 0 : int udp_client::send(char const * msg, size_t size)
131 : {
132 0 : if(f_address.is_ipv4())
133 : {
134 0 : sockaddr_in a;
135 0 : f_address.get_ipv4(a);
136 0 : return static_cast<int>(sendto(
137 0 : f_socket.get()
138 : , msg
139 : , size
140 : , 0
141 : , reinterpret_cast<sockaddr const *>(&a)
142 0 : , sizeof(a)));
143 : }
144 : else
145 : {
146 0 : sockaddr_in6 a;
147 0 : f_address.get_ipv6(a);
148 0 : return static_cast<int>(sendto(
149 0 : f_socket.get()
150 : , msg
151 : , size
152 : , 0
153 : , reinterpret_cast<sockaddr const *>(&a)
154 0 : , sizeof(a)));
155 : }
156 : }
157 :
158 :
159 :
160 6 : } // namespace ed
161 : // vim: ts=4 sw=4 et
|