Line data Source code
1 : // Copyright (c) 2012-2019 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // This program is free software; you can redistribute it and/or modify
4 : // it under the terms of the GNU General Public License as published by
5 : // the Free Software Foundation; either version 2 of the License, or
6 : // (at your option) any later version.
7 : //
8 : // This program is distributed in the hope that it will be useful,
9 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 : // GNU General Public License for more details.
12 : //
13 : // You should have received a copy of the GNU General Public License
14 : // along with this program; if not, write to the Free Software
15 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 :
17 : /** \file
18 : * \brief Implementation of the Snap Communicator class.
19 : *
20 : * This class wraps the C poll() interface in a C++ object with many types
21 : * of objects:
22 : *
23 : * \li Server Connections; for software that want to offer a port to
24 : * which clients can connect to; the server will call accept()
25 : * once a new client connection is ready; this results in a
26 : * Server/Client connection object
27 : * \li Client Connections; for software that want to connect to
28 : * a server; these expect the IP address and port to connect to
29 : * \li Server/Client Connections; for the server when it accepts a new
30 : * connection; in this case the server gets a socket from accept()
31 : * and creates one of these objects to handle the connection
32 : *
33 : * Using the poll() function is the easiest and allows us to listen
34 : * on pretty much any number of sockets (on my server it is limited
35 : * at 16,768 and frankly over 1,000 we probably will start to have
36 : * real slowness issues on small VPN servers.)
37 : */
38 :
39 : // self
40 : //
41 : #include "eventdispatcher/pipe_connection.h"
42 :
43 : #include "eventdispatcher/exception.h"
44 :
45 :
46 : // C lib
47 : //
48 : #include <unistd.h>
49 : #include <sys/socket.h>
50 :
51 :
52 : // last include
53 : //
54 : #include <snapdev/poison.h>
55 :
56 :
57 :
58 :
59 : namespace ed
60 : {
61 :
62 :
63 :
64 : /** \brief Initializes the pipe connection.
65 : *
66 : * This function creates the pipes that are to be used to connect
67 : * two processes (these are actually Unix sockets). These are
68 : * used whenever you fork() so the parent process can very quickly
69 : * communicate with the child process using complex messages just
70 : * like you do between services and Snap Communicator.
71 : *
72 : * \warning
73 : * The sockets are opened in a non-blocking state. However, they are
74 : * not closed when you call fork() since they are to be used across
75 : * processes.
76 : *
77 : * \warning
78 : * You need to create a new snap_pipe_connection each time you want
79 : * to create a new child.
80 : *
81 : * \exception snap_communicator_initialization_error
82 : * This exception is raised if the pipes (socketpair) cannot be created.
83 : */
84 0 : pipe_connection::pipe_connection()
85 : {
86 0 : if(socketpair(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0, f_socket) != 0)
87 : {
88 : // pipe could not be created
89 0 : throw event_dispatcher_initialization_error("somehow the pipes used for a two way pipe connection could not be created.");
90 : }
91 :
92 0 : f_parent = getpid();
93 0 : }
94 :
95 :
96 : /** \brief Make sure to close the pipes.
97 : *
98 : * The destructor ensures that the pipes get closed.
99 : *
100 : * They may already have been closed if a broken pipe was detected.
101 : */
102 0 : pipe_connection::~pipe_connection()
103 : {
104 0 : close();
105 0 : }
106 :
107 :
108 : /** \brief Read data from this pipe connection.
109 : *
110 : * This function reads up to count bytes from this pipe connection.
111 : *
112 : * The function makes sure to use the correct socket for the calling
113 : * process (i.e. depending on whether this is the parent or child.)
114 : *
115 : * Just like the system read(2) function, errno is set to the error
116 : * that happened when the function returns -1.
117 : *
118 : * \param[in] buf A pointer to a buffer of data.
119 : * \param[in] count The number of bytes to read from the pipe connection.
120 : *
121 : * \return The number of bytes read from this pipe socket, or -1 on errors.
122 : */
123 0 : ssize_t pipe_connection::read(void * buf, size_t count)
124 : {
125 0 : int const s(get_socket());
126 0 : if(s == -1)
127 : {
128 0 : errno = EBADF;
129 0 : return -1;
130 : }
131 0 : return ::read(s, buf, count);
132 : }
133 :
134 :
135 : /** \brief Write data to this pipe connection.
136 : *
137 : * This function writes count bytes to this pipe connection.
138 : *
139 : * The function makes sure to use the correct socket for the calling
140 : * process (i.e. depending on whether this is the parent or child.)
141 : *
142 : * Just like the system write(2) function, errno is set to the error
143 : * that happened when the function returns -1.
144 : *
145 : * \param[in] buf A pointer to a buffer of data.
146 : * \param[in] count The number of bytes to write to the pipe connection.
147 : *
148 : * \return The number of bytes written to this pipe socket, or -1 on errors.
149 : */
150 0 : ssize_t pipe_connection::write(void const * buf, size_t count)
151 : {
152 0 : int const s(get_socket());
153 0 : if(s == -1)
154 : {
155 0 : errno = EBADF;
156 0 : return -1;
157 : }
158 0 : if(buf != nullptr && count > 0)
159 : {
160 0 : return ::write(s, buf, count);
161 : }
162 0 : return 0;
163 : }
164 :
165 :
166 : /** \brief Close the sockets.
167 : *
168 : * This function closes the pair of sockets managed by this
169 : * pipe connection object.
170 : *
171 : * After this call, the pipe connection is closed and cannot be
172 : * used anymore. The read and write functions will return immediately
173 : * if called.
174 : */
175 0 : void pipe_connection::close()
176 : {
177 0 : if(f_socket[0] != -1)
178 : {
179 0 : ::close(f_socket[0]);
180 0 : ::close(f_socket[1]);
181 0 : f_socket[0] = -1;
182 0 : f_socket[1] = -1;
183 : }
184 0 : }
185 :
186 :
187 : /** \brief Pipe connections accept reads.
188 : *
189 : * This function returns true meaning that the pipe connection can be
190 : * used to read data.
191 : *
192 : * \return true since a pipe connection is a reader.
193 : */
194 0 : bool pipe_connection::is_reader() const
195 : {
196 0 : return true;
197 : }
198 :
199 :
200 : /** \brief This function returns the pipe we want to listen on.
201 : *
202 : * This function returns the file descriptor of one of the two
203 : * sockets. The parent process returns the descriptor of socket
204 : * number 0. The child process returns the descriptor of socket
205 : * number 1.
206 : *
207 : * \note
208 : * If the close() function was called, this function returns -1.
209 : *
210 : * \return A pipe descriptor to listen on with poll().
211 : */
212 0 : int pipe_connection::get_socket() const
213 : {
214 0 : if(f_parent == getpid())
215 : {
216 0 : return f_socket[0];
217 : }
218 :
219 0 : return f_socket[1];
220 : }
221 :
222 :
223 :
224 :
225 :
226 :
227 :
228 : } // namespace ed
229 : // vim: ts=4 sw=4 et
|