Line data Source code
1 : // Copyright (c) 2012-2024 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 3 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, see <https://www.gnu.org/licenses/>.
18 :
19 : /** \file
20 : * \brief Implementation of the Snap Communicator class.
21 : *
22 : * This class wraps the C poll() interface in a C++ object with many types
23 : * of objects:
24 : *
25 : * \li Server Connections; for software that want to offer a port to
26 : * which clients can connect to; the server will call accept()
27 : * once a new client connection is ready; this results in a
28 : * Server/Client connection object
29 : * \li Client Connections; for software that want to connect to
30 : * a server; these expect the IP address and port to connect to
31 : * \li Server/Client Connections; for the server when it accepts a new
32 : * connection; in this case the server gets a socket from accept()
33 : * and creates one of these objects to handle the connection
34 : *
35 : * Using the poll() function is the easiest and allows us to listen
36 : * on pretty much any number of sockets (on my server it is limited
37 : * at 16,768 and frankly over 1,000 we probably will start to have
38 : * real slowness issues on small VPN servers.)
39 : */
40 :
41 : // self
42 : //
43 : #include "eventdispatcher/tcp_server_client_connection.h"
44 :
45 : #include "eventdispatcher/exception.h"
46 :
47 :
48 : // snaplogger
49 : //
50 : #include <snaplogger/message.h>
51 :
52 :
53 : // C++
54 : //
55 : #include <cstring>
56 :
57 :
58 : // C
59 : //
60 : #include <arpa/inet.h>
61 : #include <netdb.h>
62 :
63 :
64 : // last include
65 : //
66 : #include <snapdev/poison.h>
67 :
68 :
69 :
70 : namespace ed
71 : {
72 :
73 :
74 :
75 : /** \brief Create a client connection created from an accept().
76 : *
77 : * This constructor initializes a client connection from a socket
78 : * that we received from an accept() call.
79 : *
80 : * The destructor will automatically close that socket on destruction.
81 : *
82 : * \param[in] client The client that accept() returned.
83 : */
84 62 : tcp_server_client_connection::tcp_server_client_connection(tcp_bio_client::pointer_t client)
85 62 : : f_client(client)
86 : {
87 62 : }
88 :
89 :
90 : /** \brief Make sure the socket gets released.
91 : *
92 : * This destructor makes sure that the socket gets closed.
93 : */
94 62 : tcp_server_client_connection::~tcp_server_client_connection()
95 : {
96 62 : close();
97 62 : }
98 :
99 :
100 : /** \brief Read data from the TCP server client socket.
101 : *
102 : * This function reads as much data up to the specified amount
103 : * in \p count. The read data is saved in \p buf.
104 : *
105 : * \param[in,out] buf The buffer where the data gets read.
106 : * \param[in] count The maximum number of bytes to read in buf.
107 : *
108 : * \return The number of bytes read or -1 if an error occurred.
109 : */
110 95 : ssize_t tcp_server_client_connection::read(void * buf, std::size_t count)
111 : {
112 95 : if(f_client == nullptr)
113 : {
114 0 : errno = EBADF;
115 0 : return -1;
116 : }
117 95 : return f_client->read(reinterpret_cast<char *>(buf), count);
118 : }
119 :
120 :
121 : /** \brief Write data to this connection's socket.
122 : *
123 : * This function writes up to \p count bytes of data from \p buf
124 : * to this connection's socket.
125 : *
126 : * \warning
127 : * This write function may not always write all the data you are
128 : * trying to send to the remote connection. If you want to make
129 : * sure that all your data is written to the other side,
130 : * you want to instead use the tcp_server_client_buffer_connection,
131 : * which overloads this write() function and saves the data to be
132 : * written to the socket in a buffer. The communicator run()-loop is
133 : * then responsible for sending all the data. However, that buffering
134 : * has no limit, so if you are sending large files, it is also not
135 : * a very good idea.
136 : *
137 : * \param[in] buf The buffer of data to be written to the socket.
138 : * \param[in] count The number of bytes the caller wants to write to the
139 : * connection.
140 : *
141 : * \return The number of bytes written to the socket or -1 if an error occurred.
142 : */
143 40 : ssize_t tcp_server_client_connection::write(void const * buf, std::size_t count)
144 : {
145 40 : if(f_client == nullptr)
146 : {
147 0 : errno = EBADF;
148 0 : return -1;
149 : }
150 40 : return f_client->write(reinterpret_cast<char const *>(buf), count);
151 : }
152 :
153 :
154 : /** \brief Close the socket of this connection.
155 : *
156 : * This function is automatically called whenever the object gets
157 : * destroyed (see destructor) or detects that the client closed
158 : * the network connection.
159 : *
160 : * Connections cannot be reopened.
161 : */
162 68 : void tcp_server_client_connection::close()
163 : {
164 68 : f_client.reset();
165 68 : }
166 :
167 :
168 : /** \brief Retrieve the socket of this connection.
169 : *
170 : * This function returns the socket defined in this connection.
171 : *
172 : * \return The socket file descriptor or -1 if the connection is closed.
173 : */
174 575 : int tcp_server_client_connection::get_socket() const
175 : {
176 575 : if(f_client == nullptr)
177 : {
178 : // client connection was closed
179 : //
180 10 : return -1;
181 : }
182 564 : return f_client->get_socket();
183 : }
184 :
185 :
186 : /** \brief Tell that we are always a reader.
187 : *
188 : * This function always returns true meaning that the connection is
189 : * always of a reader. In most cases this is safe because if nothing
190 : * is being written to you then poll() never returns so you do not
191 : * waste much time in have a TCP connection always marked as a
192 : * reader.
193 : *
194 : * \return The events to listen to for this connection.
195 : */
196 110 : bool tcp_server_client_connection::is_reader() const
197 : {
198 110 : return true;
199 : }
200 :
201 :
202 : /** \brief Retrieve a copy of the client's address.
203 : *
204 : * This function retrieves a copy of the client's address and returns it.
205 : *
206 : * \return A reference to the client's address.
207 : */
208 0 : addr::addr const & tcp_server_client_connection::get_client_address()
209 : {
210 0 : if(f_client_address.is_default())
211 : {
212 0 : int const s(get_socket());
213 0 : if(s >= 0)
214 : {
215 0 : f_client_address.set_from_socket(s, false);
216 : }
217 : }
218 :
219 0 : return f_client_address;
220 : }
221 :
222 :
223 : /** \brief Retrieve the remote address information.
224 : *
225 : * This function can be used to retrieve the remove address and port
226 : * information as was specified on the constructor. These can be used
227 : * to find this specific connection at a later time or create another
228 : * connection.
229 : *
230 : * For example, you may get 192.168.2.17:4040.
231 : *
232 : * The function works even after the socket gets closed as we save
233 : * the remote address and port in a string just after the connection
234 : * was established.
235 : *
236 : * \warning
237 : * This function returns BOTH: the address and the port.
238 : *
239 : * \note
240 : * These parameters are the same as what was passed to the constructor,
241 : * only both will have been converted to numbers. So for example when
242 : * you used "localhost", here you get "::1" or "127.0.0.1" for the
243 : * address.
244 : *
245 : * \return The remote host address and connection port.
246 : */
247 0 : addr::addr const & tcp_server_client_connection::get_remote_address()
248 : {
249 : // TODO: somehow the port seems wrong (i.e. all connections return the same port)
250 : // I changed this to do the getpeername() at the time you call the
251 : // get_remote_address() and I use the addr::addr get_from_socket()
252 : // so now it may work? I need to test it again
253 : //
254 0 : if(f_remote_address.is_default())
255 : {
256 0 : int const s(get_socket());
257 0 : if(s >= 0)
258 : {
259 0 : f_remote_address.set_from_socket(s, true);
260 : }
261 : }
262 :
263 0 : return f_remote_address;
264 : }
265 :
266 :
267 : } // namespace ed
268 : // vim: ts=4 sw=4 et
|