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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Handle an AF_UNIX socket.
22 : *
23 : * Class used to handle a Unix socket.
24 : */
25 :
26 :
27 : // self
28 : //
29 : #include "eventdispatcher/local_stream_client_connection.h"
30 :
31 : #include "eventdispatcher/exception.h"
32 : //#include "eventdispatcher/utils.h"
33 :
34 :
35 : // snaplogger lib
36 : //
37 : #include <snaplogger/message.h>
38 :
39 :
40 : // C lib
41 : //
42 : //#include <netdb.h>
43 : //#include <arpa/inet.h>
44 : //#include <string.h>
45 :
46 :
47 : // last include
48 : //
49 : #include <snapdev/poison.h>
50 :
51 :
52 :
53 : namespace ed
54 : {
55 :
56 :
57 :
58 : /** \class local_stream_client_connection
59 : * \brief Create a client socket and connect to a server.
60 : *
61 : * This class is a client socket implementation used to connect to a server.
62 : * The server is expected to be running at the time the client is created
63 : * otherwise it fails connecting.
64 : *
65 : * This class is not appropriate to connect to a server that may come and go
66 : * over time.
67 : */
68 :
69 :
70 :
71 :
72 : /** \brief Construct a local_stream_client_connection object.
73 : *
74 : * The local_stream_client_connection constructor initializes a streaming
75 : * Unix socket object by connecting to the specified server. The server
76 : * is defined with the \p u parameters.
77 : *
78 : * \exception event_dispatcher_runtime_error
79 : * This exception is raised if the client cannot create the socket or it
80 : * cannot connect to the server.
81 : *
82 : * \param[in] u The Unux address of the server to connect to.
83 : * \param[in] close_on_exec Whether to close this socket on an execve() call.
84 : */
85 1 : local_stream_client_connection::local_stream_client_connection(
86 : addr::unix const & address
87 : , bool const blocking
88 1 : , bool const close_on_exec)
89 1 : : f_address(address)
90 : {
91 1 : sockaddr_un un;
92 1 : f_address.get_un(un);
93 2 : f_socket.reset(socket(
94 1 : un.sun_family
95 : , SOCK_STREAM | SOCK_NONBLOCK | (close_on_exec ? SOCK_CLOEXEC : 0)
96 : , 0));
97 1 : if(f_socket == nullptr)
98 : {
99 0 : int const e(errno);
100 0 : SNAP_LOG_FATAL
101 0 : << "socket() failed to create a Unix socket descriptor (errno: "
102 : << e
103 : << " -- "
104 0 : << strerror(e)
105 : << ")"
106 : << SNAP_LOG_SEND;
107 0 : throw event_dispatcher_runtime_error("could not create socket for client");
108 : }
109 :
110 1 : if(f_address.is_unnamed())
111 : {
112 : // for an unnamed socket, we do not bind at all the user is
113 : // responsible for knowing where to read and where to write
114 : //
115 0 : return;
116 : }
117 :
118 1 : int r(-1);
119 1 : if(f_address.is_abstract())
120 : {
121 : // to create a correct abstract socket, we need to adjust the
122 : // size to the exact length of the address (i.e. we do not want
123 : // to send the '\0' after the name)
124 : //
125 0 : std::size_t const size(strlen(un.sun_path + 1));
126 0 : r = connect(
127 0 : f_socket.get()
128 : , reinterpret_cast<sockaddr const *>(&un)
129 : , size);
130 : }
131 : else
132 : {
133 : // in this case we can send the entire address
134 : //
135 2 : r = connect(
136 2 : f_socket.get()
137 : , reinterpret_cast<sockaddr const *>(&un)
138 : , sizeof(un));
139 : }
140 :
141 1 : if(r < 0)
142 : {
143 0 : int const e(errno);
144 0 : SNAP_LOG_FATAL
145 0 : << "connect() failed to connect a socket with address \""
146 0 : << f_address.to_uri()
147 0 : << "\" (errno: "
148 : << e
149 : << " -- "
150 0 : << strerror(e)
151 : << ")"
152 : << SNAP_LOG_SEND;
153 : throw event_dispatcher_runtime_error(
154 : "could not connect client socket to \""
155 0 : + f_address.to_uri()
156 0 : + "\"");
157 : }
158 :
159 1 : if(!blocking)
160 : {
161 1 : non_blocking();
162 : }
163 : }
164 :
165 :
166 : /** \brief Clean up the TCP client object.
167 : *
168 : * This function cleans up the TCP client object by closing the attached socket.
169 : *
170 : * \note
171 : * DO NOT use the shutdown() call since we may end up forking and using
172 : * that connection in the child.
173 : */
174 1 : local_stream_client_connection::~local_stream_client_connection()
175 : {
176 1 : }
177 :
178 :
179 : /** \brief Close this connection.
180 : *
181 : * A connction automatically gets closed when it gets destroyed. There are
182 : * times, though, when it is useful to close the connection early
183 : * (specifically, when you receive an error).
184 : *
185 : * This function can be used to close the connection at any time. Many
186 : * of the other functions will stop working once the connection is
187 : * officially closed.
188 : */
189 0 : void local_stream_client_connection::close()
190 : {
191 0 : f_socket.reset();
192 0 : }
193 :
194 :
195 : /** \brief Get the Unix server address.
196 : *
197 : * This function returns the address used when creating the Unix server.
198 : *
199 : * \return The Unix address.
200 : */
201 0 : addr::unix local_stream_client_connection::get_address() const
202 : {
203 0 : return f_address;
204 : }
205 :
206 :
207 : /** \brief Check whether this connection is a reader.
208 : *
209 : * We change the default to true since Unix sockets are generally
210 : * always readers. You can still override this function and
211 : * return false if necessary.
212 : *
213 : * However, we do not override the is_writer() because that is
214 : * much more dynamic (i.e. you do not want to advertise as
215 : * being a writer unless you have data to write to the
216 : * socket.)
217 : *
218 : * \return Always true since this is a reader connection.
219 : */
220 5 : bool local_stream_client_connection::is_reader() const
221 : {
222 5 : return true;
223 : }
224 :
225 :
226 : /** \brief Get the socket descriptor.
227 : *
228 : * This function returns the TCP client socket descriptor. This can be
229 : * used to change the descriptor behavior (i.e. make it non-blocking for
230 : * example.)
231 : *
232 : * \return The socket descriptor.
233 : */
234 25 : int local_stream_client_connection::get_socket() const
235 : {
236 25 : return f_socket.get();
237 : }
238 :
239 :
240 : /** \brief Read data from the socket.
241 : *
242 : * A TCP socket is a stream type of socket and one can read data from it
243 : * as if it were a regular file. This function reads \p size bytes and
244 : * returns. The function returns early if the server closes the connection.
245 : *
246 : * If your socket is blocking, \p size should be exactly what you are
247 : * expecting or this function will block forever or until the server
248 : * closes the connection.
249 : *
250 : * The function returns -1 if an error occurs. The error is available in
251 : * errno as expected in the POSIX interface.
252 : *
253 : * \param[in,out] buf The buffer where the data is read.
254 : * \param[in] size The size of the buffer.
255 : *
256 : * \return The number of bytes read from the socket, or -1 on errors.
257 : */
258 2 : ssize_t local_stream_client_connection::read(char * buf, size_t size)
259 : {
260 2 : return ::read(f_socket.get(), buf, size);
261 : }
262 :
263 :
264 : /** \brief Write data to the socket.
265 : *
266 : * A TCP socket is a stream type of socket and one can write data to it
267 : * as if it were a regular file. This function writes \p size bytes to
268 : * the socket and then returns. This function returns early if the server
269 : * closes the connection.
270 : *
271 : * If your socket is not blocking, less than \p size bytes may be written
272 : * to the socket. In that case you are responsible for calling the function
273 : * again to write the remainder of the buffer until the function returns
274 : * a number of bytes written equal to \p size.
275 : *
276 : * The function returns -1 if an error occurs. The error is available in
277 : * errno as expected in the POSIX interface.
278 : *
279 : * \param[in] buf The buffer with the data to send over the socket.
280 : * \param[in] size The number of bytes in buffer to send over the socket.
281 : *
282 : * \return The number of bytes that were actually accepted by the socket
283 : * or -1 if an error occurs.
284 : */
285 2 : ssize_t local_stream_client_connection::write(void const * buf, size_t size)
286 : {
287 2 : return ::write(f_socket.get(), buf, size);
288 : }
289 :
290 :
291 :
292 :
293 6 : } // namespace ed
294 : // vim: ts=4 sw=4 et
|