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-net.h"
42 #include "qnetd-client-send.h"
43 #include "qnetd-client-msg-received.h"
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)
49 qnetd_client_net_write_finished(struct qnetd_instance
*instance
, struct qnetd_client
*client
)
53 * Callback is currently unused
60 qnetd_client_net_socket_poll_loop_set_events_cb(PRFileDesc
*prfd
, short *events
,
61 void *user_data1
, void *user_data2
)
63 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
64 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
66 if (client
->schedule_disconnect
) {
67 qnetd_instance_client_disconnect(instance
, client
, 0);
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");
78 if (!send_buffer_list_empty(&client
->send_buffer_list
)) {
87 qnetd_client_net_socket_poll_loop_read_cb(PRFileDesc
*prfd
, void *user_data1
, void *user_data2
)
89 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
90 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
92 if (!client
->schedule_disconnect
) {
93 if (qnetd_client_net_read(instance
, client
) == -1) {
94 client
->schedule_disconnect
= 1;
102 qnetd_client_net_socket_poll_loop_write_cb(PRFileDesc
*prfd
, void *user_data1
, void *user_data2
)
104 struct qnetd_instance
*instance
= (struct qnetd_instance
*)user_data1
;
105 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
107 if (!client
->schedule_disconnect
) {
108 if (qnetd_client_net_write(instance
, client
) == -1) {
109 client
->schedule_disconnect
= 1;
117 qnetd_client_net_socket_poll_loop_err_cb(PRFileDesc
*prfd
, short revents
, void *user_data1
, void *user_data2
)
119 struct qnetd_client
*client
= (struct qnetd_client
*)user_data2
;
121 if (!client
->schedule_disconnect
) {
122 log(LOG_DEBUG
, "POLL_ERR (%u) on client socket. "
123 "Disconnecting.", revents
);
125 client
->schedule_disconnect
= 1;
132 qnetd_client_net_write(struct qnetd_instance
*instance
, struct qnetd_client
*client
)
135 struct send_buffer_list_entry
*send_buffer
;
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");
144 res
= msgio_write(client
->socket
, &send_buffer
->buffer
,
145 &send_buffer
->msg_already_sent_bytes
);
148 send_buffer_list_delete(&client
->send_buffer_list
, send_buffer
);
150 if (qnetd_client_net_write_finished(instance
, client
) == -1) {
156 log_nss(LOG_CRIT
, "PR_Send returned 0");
162 log_nss(LOG_ERR
, "Unhandled error when sending message to client");
172 * -1 means end of connection (EOF) or some other unhandled error. 0 = success
175 qnetd_client_net_read(struct qnetd_instance
*instance
, struct qnetd_client
*client
)
179 int orig_skipping_msg
;
181 orig_skipping_msg
= client
->skipping_msg
;
183 res
= msgio_read(client
->socket
, &client
->receive_buffer
,
184 &client
->msg_already_received_bytes
, &client
->skipping_msg
);
186 if (!orig_skipping_msg
&& client
->skipping_msg
) {
187 log(LOG_DEBUG
, "msgio_read set skipping_msg");
199 log(LOG_DEBUG
, "Client closed connection");
203 log_nss(LOG_ERR
, "Unhandled error when reading from client. "
204 "Disconnecting client");
208 log(LOG_ERR
, "Can't store message header from client. Disconnecting client");
212 log(LOG_ERR
, "Can't store message from client. Skipping message");
213 client
->skipping_msg_reason
= TLV_REPLY_ERROR_CODE_ERROR_DECODING_MSG
;
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
;
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
;
228 * Full message received / skipped
230 if (!client
->skipping_msg
) {
231 if (qnetd_client_msg_received(instance
, client
) == -1) {
235 if (qnetd_client_send_err(client
, 0, 0, client
->skipping_msg_reason
) != 0) {
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
);
246 log(LOG_ERR
, "Unhandled msgio_read error %d\n", res
);
255 qnetd_client_net_accept(struct qnetd_instance
*instance
)
257 PRNetAddr client_addr
;
258 PRFileDesc
*client_socket
;
259 struct qnetd_client
*client
;
260 char *client_addr_str
;
263 client_addr_str
= NULL
;
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");
273 if (nss_sock_set_non_blocking(client_socket
) != 0) {
274 log_nss(LOG_ERR
, "Can't set client socket to non blocking mode");
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");
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");
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");
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");
302 client
= qnetd_client_list_add(&instance
->clients
, client_socket
, &client_addr
,
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");
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");
328 free(client_addr_str
);
329 PR_Close(client_socket
);