]> git.proxmox.com Git - mirror_corosync-qdevice.git/blob - qdevices/qnetd-client-net.c
qdevice: Use EXIT_SUCCESS and EXIT_FAILURE codes
[mirror_corosync-qdevice.git] / qdevices / qnetd-client-net.c
1 /*
2 * Copyright (c) 2015-2020 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/types.h>
36
37 #include "log.h"
38 #include "msgio.h"
39 #include "msg.h"
40 #include "nss-sock.h"
41 #include "qnetd-client-net.h"
42 #include "qnetd-client-send.h"
43 #include "qnetd-client-msg-received.h"
44
45 #define CLIENT_ADDR_STR_LEN_COLON_PORT (1 + 5 + 1)
46 #define CLIENT_ADDR_STR_LEN (INET6_ADDRSTRLEN + CLIENT_ADDR_STR_LEN_COLON_PORT)
47
48 static int
49 qnetd_client_net_write_finished(struct qnetd_instance *instance, struct qnetd_client *client)
50 {
51
52 /*
53 * Callback is currently unused
54 */
55
56 return (0);
57 }
58
59 static int
60 qnetd_client_net_socket_poll_loop_set_events_cb(PRFileDesc *prfd, short *events,
61 void *user_data1, void *user_data2)
62 {
63 struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
64 struct qnetd_client *client = (struct qnetd_client *)user_data2;
65
66 if (client->schedule_disconnect) {
67 qnetd_instance_client_disconnect(instance, client, 0);
68
69 if (pr_poll_loop_del_prfd(&instance->main_poll_loop, prfd) == -1) {
70 log(LOG_CRIT, "pr_poll_loop_del_prfd for client socket failed");
71
72 return (-2);
73 }
74
75 return (-1);
76 }
77
78 if (!send_buffer_list_empty(&client->send_buffer_list)) {
79 *events |= POLLOUT;
80 }
81
82 return (0);
83 }
84
85
86 static int
87 qnetd_client_net_socket_poll_loop_read_cb(PRFileDesc *prfd, void *user_data1, void *user_data2)
88 {
89 struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
90 struct qnetd_client *client = (struct qnetd_client *)user_data2;
91
92 if (!client->schedule_disconnect) {
93 if (qnetd_client_net_read(instance, client) == -1) {
94 client->schedule_disconnect = 1;
95 }
96 }
97
98 return (0);
99 }
100
101 static int
102 qnetd_client_net_socket_poll_loop_write_cb(PRFileDesc *prfd, void *user_data1, void *user_data2)
103 {
104 struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
105 struct qnetd_client *client = (struct qnetd_client *)user_data2;
106
107 if (!client->schedule_disconnect) {
108 if (qnetd_client_net_write(instance, client) == -1) {
109 client->schedule_disconnect = 1;
110 }
111 }
112
113 return (0);
114 }
115
116 static int
117 qnetd_client_net_socket_poll_loop_err_cb(PRFileDesc *prfd, short revents, void *user_data1, void *user_data2)
118 {
119 struct qnetd_client *client = (struct qnetd_client *)user_data2;
120
121 if (!client->schedule_disconnect) {
122 log(LOG_DEBUG, "POLL_ERR (%u) on client socket. "
123 "Disconnecting.", revents);
124
125 client->schedule_disconnect = 1;
126 }
127
128 return (0);
129 }
130
131 int
132 qnetd_client_net_write(struct qnetd_instance *instance, struct qnetd_client *client)
133 {
134 int res;
135 struct send_buffer_list_entry *send_buffer;
136
137 send_buffer = send_buffer_list_get_active(&client->send_buffer_list);
138 if (send_buffer == NULL) {
139 log_nss(LOG_CRIT, "send_buffer_list_get_active returned NULL");
140
141 return (-1);
142 }
143
144 res = msgio_write(client->socket, &send_buffer->buffer,
145 &send_buffer->msg_already_sent_bytes);
146
147 if (res == 1) {
148 send_buffer_list_delete(&client->send_buffer_list, send_buffer);
149
150 if (qnetd_client_net_write_finished(instance, client) == -1) {
151 return (-1);
152 }
153 }
154
155 if (res == -1) {
156 log_nss(LOG_CRIT, "PR_Send returned 0");
157
158 return (-1);
159 }
160
161 if (res == -2) {
162 log_nss(LOG_ERR, "Unhandled error when sending message to client");
163
164 return (-1);
165 }
166
167 return (0);
168 }
169
170
171 /*
172 * -1 means end of connection (EOF) or some other unhandled error. 0 = success
173 */
174 int
175 qnetd_client_net_read(struct qnetd_instance *instance, struct qnetd_client *client)
176 {
177 int res;
178 int ret_val;
179 int orig_skipping_msg;
180
181 orig_skipping_msg = client->skipping_msg;
182
183 res = msgio_read(client->socket, &client->receive_buffer,
184 &client->msg_already_received_bytes, &client->skipping_msg);
185
186 if (!orig_skipping_msg && client->skipping_msg) {
187 log(LOG_DEBUG, "msgio_read set skipping_msg");
188 }
189
190 ret_val = 0;
191
192 switch (res) {
193 case 0:
194 /*
195 * Partial read
196 */
197 break;
198 case -1:
199 log(LOG_DEBUG, "Client closed connection");
200 ret_val = -1;
201 break;
202 case -2:
203 log_nss(LOG_ERR, "Unhandled error when reading from client. "
204 "Disconnecting client");
205 ret_val = -1;
206 break;
207 case -3:
208 log(LOG_ERR, "Can't store message header from client. Disconnecting client");
209 ret_val = -1;
210 break;
211 case -4:
212 log(LOG_ERR, "Can't store message from client. Skipping message");
213 client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_ERROR_DECODING_MSG;
214 break;
215 case -5:
216 log(LOG_WARNING, "Client sent unsupported msg type %u. Skipping message",
217 msg_get_type(&client->receive_buffer));
218 client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_UNSUPPORTED_MESSAGE;
219 break;
220 case -6:
221 log(LOG_WARNING,
222 "Client wants to send too long message %u bytes. Skipping message",
223 msg_get_len(&client->receive_buffer));
224 client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_MESSAGE_TOO_LONG;
225 break;
226 case 1:
227 /*
228 * Full message received / skipped
229 */
230 if (!client->skipping_msg) {
231 if (qnetd_client_msg_received(instance, client) == -1) {
232 ret_val = -1;
233 }
234 } else {
235 if (qnetd_client_send_err(client, 0, 0, client->skipping_msg_reason) != 0) {
236 ret_val = -1;
237 }
238 }
239
240 client->skipping_msg = 0;
241 client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_NO_ERROR;
242 client->msg_already_received_bytes = 0;
243 dynar_clean(&client->receive_buffer);
244 break;
245 default:
246 log(LOG_ERR, "Unhandled msgio_read error %d\n", res);
247 exit(EXIT_FAILURE);
248 break;
249 }
250
251 return (ret_val);
252 }
253
254 int
255 qnetd_client_net_accept(struct qnetd_instance *instance)
256 {
257 PRNetAddr client_addr;
258 PRFileDesc *client_socket;
259 struct qnetd_client *client;
260 char *client_addr_str;
261 int res_err;
262
263 client_addr_str = NULL;
264
265 res_err = -1;
266
267 if ((client_socket = PR_Accept(instance->server.socket, &client_addr,
268 PR_INTERVAL_NO_TIMEOUT)) == NULL) {
269 log_nss(LOG_ERR, "Can't accept connection");
270 return (-1);
271 }
272
273 if (nss_sock_set_non_blocking(client_socket) != 0) {
274 log_nss(LOG_ERR, "Can't set client socket to non blocking mode");
275 goto exit_close;
276 }
277
278 if (instance->max_clients != 0 &&
279 qnetd_client_list_no_clients(&instance->clients) >= instance->max_clients) {
280 log(LOG_ERR, "Maximum clients reached. Not accepting connection");
281 goto exit_close;
282 }
283
284 client_addr_str = malloc(CLIENT_ADDR_STR_LEN);
285 if (client_addr_str == NULL) {
286 log(LOG_ERR, "Can't alloc client addr str memory. Not accepting connection");
287 goto exit_close;
288 }
289
290 if (PR_NetAddrToString(&client_addr, client_addr_str, CLIENT_ADDR_STR_LEN) != PR_SUCCESS) {
291 log_nss(LOG_ERR, "Can't convert client address to string. Not accepting connection");
292 goto exit_close;
293 }
294
295 if (snprintf(client_addr_str + strlen(client_addr_str),
296 CLIENT_ADDR_STR_LEN_COLON_PORT, ":%"PRIu16,
297 ntohs(client_addr.ipv6.port)) >= CLIENT_ADDR_STR_LEN_COLON_PORT) {
298 log(LOG_ERR, "Can't store port to client addr str. Not accepting connection");
299 goto exit_close;
300 }
301
302 client = qnetd_client_list_add(&instance->clients, client_socket, &client_addr,
303 client_addr_str,
304 instance->advanced_settings->max_client_receive_size,
305 instance->advanced_settings->max_client_send_buffers,
306 instance->advanced_settings->max_client_send_size,
307 pr_poll_loop_get_timer_list(&instance->main_poll_loop));
308 if (client == NULL) {
309 log(LOG_ERR, "Can't add client to list");
310 res_err = -2;
311 goto exit_close;
312 }
313
314 if (pr_poll_loop_add_prfd(&instance->main_poll_loop, client_socket, POLLIN,
315 qnetd_client_net_socket_poll_loop_set_events_cb,
316 qnetd_client_net_socket_poll_loop_read_cb,
317 qnetd_client_net_socket_poll_loop_write_cb,
318 qnetd_client_net_socket_poll_loop_err_cb,
319 instance, client) == -1) {
320 log_err(LOG_CRIT, "Can't add client to main poll loop");
321 res_err = -2;
322 goto exit_close;
323 }
324
325 return (0);
326
327 exit_close:
328 free(client_addr_str);
329 PR_Close(client_socket);
330
331 return (res_err);
332 }