2 * Copyright (c) 2015-2020 Red Hat, Inc.
6 * Author: Jan Friesse (jfriesse@redhat.com)
8 * This software licensed under BSD license, the text of which follows:
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
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.
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.
35 #include <sys/types.h>
41 #include "qnetd-client-dpd-timer.h"
42 #include "qnetd-client-net.h"
43 #include "qnetd-client-send.h"
44 #include "qnetd-client-msg-received.h"
46 #define CLIENT_ADDR_STR_LEN_COLON_PORT (1 + 5 + 1)
47 #define CLIENT_ADDR_STR_LEN (INET6_ADDRSTRLEN + CLIENT_ADDR_STR_LEN_COLON_PORT)
50 qnetd_client_net_write_finished(struct qnetd_instance
*instance
, struct qnetd_client
*client
)
54 * Callback is currently unused
61 qnetd_client_net_socket_poll_loop_set_events_cb(PRFileDesc
*prfd
, short *events
,
62 void *user_data1
, void *user_data2
)
64 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
65 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
67 if (client
->schedule_disconnect
) {
68 qnetd_instance_client_disconnect(instance
, client
, 0);
70 if (pr_poll_loop_del_prfd(&instance
->main_poll_loop
, prfd
) == -1) {
71 log(LOG_ERR
, "pr_poll_loop_del_prfd for client socket failed");
79 if (!send_buffer_list_empty(&client
->send_buffer_list
)) {
88 qnetd_client_net_socket_poll_loop_read_cb(PRFileDesc
*prfd
, const PRPollDesc
*pd
,
89 void *user_data1
, void *user_data2
)
91 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
92 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
94 if (!client
->schedule_disconnect
) {
95 if (qnetd_client_net_read(instance
, client
) == -1) {
96 client
->schedule_disconnect
= 1;
104 qnetd_client_net_socket_poll_loop_write_cb(PRFileDesc
*prfd
, const PRPollDesc
*pd
,
105 void *user_data1
, void *user_data2
)
107 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
108 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
110 if (!client
->schedule_disconnect
) {
111 if (qnetd_client_net_write(instance
, client
) == -1) {
112 client
->schedule_disconnect
= 1;
120 qnetd_client_net_socket_poll_loop_err_cb(PRFileDesc
*prfd
, short revents
,
121 const PRPollDesc
*pd
, void *user_data1
, void *user_data2
)
123 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
125 if (!client
->schedule_disconnect
) {
126 log(LOG_DEBUG
, "POLL_ERR (%u) on client socket. "
127 "Disconnecting.", revents
);
129 client
->schedule_disconnect
= 1;
136 qnetd_client_net_write(struct qnetd_instance
*instance
, struct qnetd_client
*client
)
139 struct send_buffer_list_entry
*send_buffer
;
141 send_buffer
= send_buffer_list_get_active(&client
->send_buffer_list
);
142 if (send_buffer
== NULL
) {
143 log_nss(LOG_CRIT
, "send_buffer_list_get_active returned NULL");
148 res
= msgio_write(client
->socket
, &send_buffer
->buffer
,
149 &send_buffer
->msg_already_sent_bytes
);
152 send_buffer_list_delete(&client
->send_buffer_list
, send_buffer
);
154 if (qnetd_client_net_write_finished(instance
, client
) == -1) {
160 log_nss(LOG_CRIT
, "PR_Send returned 0");
166 log_nss(LOG_ERR
, "Unhandled error when sending message to client");
176 * -1 means end of connection (EOF) or some other unhandled error. 0 = success
179 qnetd_client_net_read(struct qnetd_instance
*instance
, struct qnetd_client
*client
)
183 int orig_skipping_msg
;
185 orig_skipping_msg
= client
->skipping_msg
;
187 res
= msgio_read(client
->socket
, &client
->receive_buffer
,
188 &client
->msg_already_received_bytes
, &client
->skipping_msg
);
190 if (!orig_skipping_msg
&& client
->skipping_msg
) {
191 log(LOG_DEBUG
, "msgio_read set skipping_msg");
203 log(LOG_DEBUG
, "Client closed connection");
207 log_nss(LOG_ERR
, "Unhandled error when reading from client. "
208 "Disconnecting client");
212 log(LOG_ERR
, "Can't store message header from client. Disconnecting client");
216 log(LOG_ERR
, "Can't store message from client. Skipping message");
217 client
->skipping_msg_reason
= TLV_REPLY_ERROR_CODE_ERROR_DECODING_MSG
;
220 log(LOG_WARNING
, "Client sent unsupported msg type %u. Skipping message",
221 msg_get_type(&client
->receive_buffer
));
222 client
->skipping_msg_reason
= TLV_REPLY_ERROR_CODE_UNSUPPORTED_MESSAGE
;
226 "Client wants to send too long message %u bytes. Skipping message",
227 msg_get_len(&client
->receive_buffer
));
228 client
->skipping_msg_reason
= TLV_REPLY_ERROR_CODE_MESSAGE_TOO_LONG
;
232 * Full message received / skipped
234 if (!client
->skipping_msg
) {
235 if (qnetd_client_msg_received(instance
, client
) == -1) {
239 if (qnetd_client_send_err(client
, 0, 0, client
->skipping_msg_reason
) != 0) {
244 client
->skipping_msg
= 0;
245 client
->skipping_msg_reason
= TLV_REPLY_ERROR_CODE_NO_ERROR
;
246 client
->msg_already_received_bytes
= 0;
247 dynar_clean(&client
->receive_buffer
);
250 log(LOG_ERR
, "Unhandled msgio_read error %d\n", res
);
259 qnetd_client_net_accept(struct qnetd_instance
*instance
)
261 PRNetAddr client_addr
;
262 PRFileDesc
*client_socket
;
263 struct qnetd_client
*client
;
264 char *client_addr_str
;
267 client_addr_str
= NULL
;
271 if ((client_socket
= PR_Accept(instance
->server
.socket
, &client_addr
,
272 PR_INTERVAL_NO_TIMEOUT
)) == NULL
) {
273 log_nss(LOG_ERR
, "Can't accept connection");
277 if (nss_sock_set_non_blocking(client_socket
) != 0) {
278 log_nss(LOG_ERR
, "Can't set client socket to non blocking mode");
282 if (instance
->max_clients
!= 0 &&
283 qnetd_client_list_no_clients(&instance
->clients
) >= instance
->max_clients
) {
284 log(LOG_ERR
, "Maximum clients reached. Not accepting connection");
288 client_addr_str
= malloc(CLIENT_ADDR_STR_LEN
);
289 if (client_addr_str
== NULL
) {
290 log(LOG_ERR
, "Can't alloc client addr str memory. Not accepting connection");
294 if (PR_NetAddrToString(&client_addr
, client_addr_str
, CLIENT_ADDR_STR_LEN
) != PR_SUCCESS
) {
295 log_nss(LOG_ERR
, "Can't convert client address to string. Not accepting connection");
299 if (snprintf(client_addr_str
+ strlen(client_addr_str
),
300 CLIENT_ADDR_STR_LEN_COLON_PORT
, ":%"PRIu16
,
301 ntohs(client_addr
.ipv6
.port
)) >= CLIENT_ADDR_STR_LEN_COLON_PORT
) {
302 log(LOG_ERR
, "Can't store port to client addr str. Not accepting connection");
306 client
= qnetd_client_list_add(&instance
->clients
, client_socket
, &client_addr
,
308 instance
->advanced_settings
->max_client_receive_size
,
309 instance
->advanced_settings
->max_client_send_buffers
,
310 instance
->advanced_settings
->max_client_send_size
,
311 pr_poll_loop_get_timer_list(&instance
->main_poll_loop
));
312 if (client
== NULL
) {
313 log(LOG_ERR
, "Can't add client to list");
318 if (pr_poll_loop_add_prfd(&instance
->main_poll_loop
, client_socket
, POLLIN
,
319 qnetd_client_net_socket_poll_loop_set_events_cb
,
320 qnetd_client_net_socket_poll_loop_read_cb
,
321 qnetd_client_net_socket_poll_loop_write_cb
,
322 qnetd_client_net_socket_poll_loop_err_cb
,
323 instance
, client
) == -1) {
324 log(LOG_ERR
, "Can't add client to main poll loop");
326 goto exit_client_list_del_close
;
329 if (qnetd_client_dpd_timer_init(instance
, client
) == -1) {
331 goto exit_client_nspr_list_del_close
;
336 exit_client_nspr_list_del_close
:
337 if (pr_poll_loop_del_prfd(&instance
->main_poll_loop
, client_socket
) == -1) {
338 log(LOG_ERR
, "pr_poll_loop_del_prfd for client socket failed");
341 exit_client_list_del_close
:
342 qnetd_client_list_del(&instance
->clients
, client
);
344 * client_addr_str is passed to qnetd_client_list_add and becomes part of client struct.
345 * qnetd_client_list_del calls qnetd_client_destroy which frees this memory
347 client_addr_str
= NULL
;
350 free(client_addr_str
);
351 PR_Close(client_socket
);