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 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] address The Unix address of the server to connect to.
83 : * \param[in] blocking Whether the socket has to be opened in blocking mode.
84 : * \param[in] close_on_exec Whether to close this socket on an execve() call.
85 : */
86 1 : local_stream_client_connection::local_stream_client_connection(
87 : addr::unix const & address
88 : , bool const blocking
89 1 : , bool const close_on_exec)
90 1 : : f_address(address)
91 : {
92 1 : sockaddr_un un;
93 1 : f_address.get_un(un);
94 3 : f_socket.reset(socket(
95 1 : un.sun_family
96 : , SOCK_STREAM
97 1 : | (blocking ? 0 : SOCK_NONBLOCK)
98 1 : | (close_on_exec ? SOCK_CLOEXEC : 0)
99 : , 0));
100 1 : if(f_socket == nullptr)
101 : {
102 0 : int const e(errno);
103 0 : SNAP_LOG_FATAL
104 0 : << "socket() failed to create a Unix socket descriptor (errno: "
105 : << e
106 : << " -- "
107 0 : << strerror(e)
108 : << ")"
109 : << SNAP_LOG_SEND;
110 0 : throw event_dispatcher_runtime_error("could not create socket for client");
111 : }
112 :
113 1 : if(f_address.is_unnamed())
114 : {
115 : // for an unnamed socket, we do not bind at all the user is
116 : // responsible for knowing where to read and where to write
117 : //
118 0 : return;
119 : }
120 :
121 1 : int r(-1);
122 1 : if(f_address.is_abstract())
123 : {
124 : // to create a correct abstract socket, we need to adjust the
125 : // size to the exact length of the address (i.e. we do not want
126 : // to send the '\0' after the name)
127 : //
128 0 : std::size_t const size(strlen(un.sun_path + 1));
129 0 : r = connect(
130 0 : f_socket.get()
131 : , reinterpret_cast<sockaddr const *>(&un)
132 : , size);
133 : }
134 : else
135 : {
136 : // in this case we can send the entire address
137 : //
138 2 : r = connect(
139 2 : f_socket.get()
140 : , reinterpret_cast<sockaddr const *>(&un)
141 : , sizeof(un));
142 : }
143 :
144 1 : if(r < 0)
145 : {
146 0 : int const e(errno);
147 0 : SNAP_LOG_FATAL
148 : << "connect() failed to connect a socket with address \""
149 0 : << f_address.to_uri()
150 0 : << "\" (errno: "
151 : << e
152 : << " -- "
153 0 : << strerror(e)
154 : << ")"
155 : << SNAP_LOG_SEND;
156 : throw event_dispatcher_runtime_error(
157 : "could not connect client socket to \""
158 0 : + f_address.to_uri()
159 0 : + "\"");
160 : }
161 :
162 1 : if(!blocking)
163 : {
164 1 : non_blocking();
165 : }
166 : }
167 :
168 :
169 : /** \brief Clean up the TCP client object.
170 : *
171 : * This function cleans up the TCP client object by closing the attached socket.
172 : *
173 : * \note
174 : * DO NOT use the shutdown() call since we may end up forking and using
175 : * that connection in the child.
176 : */
177 1 : local_stream_client_connection::~local_stream_client_connection()
178 : {
179 1 : }
180 :
181 :
182 : /** \brief Close this connection.
183 : *
184 : * A connction automatically gets closed when it gets destroyed. There are
185 : * times, though, when it is useful to close the connection early
186 : * (specifically, when you receive an error).
187 : *
188 : * This function can be used to close the connection at any time. Many
189 : * of the other functions will stop working once the connection is
190 : * officially closed.
191 : */
192 0 : void local_stream_client_connection::close()
193 : {
194 0 : f_socket.reset();
195 0 : }
196 :
197 :
198 : /** \brief Get the Unix server address.
199 : *
200 : * This function returns the address used when creating the Unix server.
201 : *
202 : * \return The Unix address.
203 : */
204 0 : addr::unix local_stream_client_connection::get_address() const
205 : {
206 0 : return f_address;
207 : }
208 :
209 :
210 : /** \brief Check whether this connection is a reader.
211 : *
212 : * We change the default to true since Unix sockets are generally
213 : * always readers. You can still override this function and
214 : * return false if necessary.
215 : *
216 : * However, we do not override the is_writer() because that is
217 : * much more dynamic (i.e. you do not want to advertise as
218 : * being a writer unless you have data to write to the
219 : * socket.)
220 : *
221 : * \return Always true since this is a reader connection.
222 : */
223 5 : bool local_stream_client_connection::is_reader() const
224 : {
225 5 : return true;
226 : }
227 :
228 :
229 : /** \brief Get the socket descriptor.
230 : *
231 : * This function returns the TCP client socket descriptor. This can be
232 : * used to change the descriptor behavior (i.e. make it non-blocking for
233 : * example.)
234 : *
235 : * \return The socket descriptor.
236 : */
237 25 : int local_stream_client_connection::get_socket() const
238 : {
239 25 : return f_socket.get();
240 : }
241 :
242 :
243 : /** \brief Read data from the socket.
244 : *
245 : * A TCP socket is a stream type of socket and one can read data from it
246 : * as if it were a regular file. This function reads \p size bytes and
247 : * returns. The function returns early if the server closes the connection.
248 : *
249 : * If your socket is blocking, \p size should be exactly what you are
250 : * expecting or this function will block forever or until the server
251 : * closes the connection.
252 : *
253 : * The function returns -1 if an error occurs. The error is available in
254 : * errno as expected in the POSIX interface.
255 : *
256 : * \param[in,out] buf The buffer where the data is read.
257 : * \param[in] size The size of the buffer.
258 : *
259 : * \return The number of bytes read from the socket, or -1 on errors.
260 : */
261 2 : ssize_t local_stream_client_connection::read(char * buf, size_t size)
262 : {
263 2 : return ::read(f_socket.get(), buf, size);
264 : }
265 :
266 :
267 : /** \brief Write data to the socket.
268 : *
269 : * A TCP socket is a stream type of socket and one can write data to it
270 : * as if it were a regular file. This function writes \p size bytes to
271 : * the socket and then returns. This function returns early if the server
272 : * closes the connection.
273 : *
274 : * If your socket is not blocking, less than \p size bytes may be written
275 : * to the socket. In that case you are responsible for calling the function
276 : * again to write the remainder of the buffer until the function returns
277 : * a number of bytes written equal to \p size.
278 : *
279 : * The function returns -1 if an error occurs. The error is available in
280 : * errno as expected in the POSIX interface.
281 : *
282 : * \param[in] buf The buffer with the data to send over the socket.
283 : * \param[in] size The number of bytes in buffer to send over the socket.
284 : *
285 : * \return The number of bytes that were actually accepted by the socket
286 : * or -1 if an error occurs.
287 : */
288 2 : ssize_t local_stream_client_connection::write(void const * buf, size_t size)
289 : {
290 2 : return ::write(f_socket.get(), buf, size);
291 : }
292 :
293 :
294 :
295 :
296 6 : } // namespace ed
297 : // vim: ts=4 sw=4 et
|