mirror_corosync/qdevices/qnetd-client-net.c
Jan Friesse 6f6c80f582 Qdevice: Send ring id in more messages
To prevent receiving vote from old membership ring id is sent to server
during init and replied back to client in every node list,
ask for vote reply and vote info messages.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
2016-06-28 13:58:43 +02:00

249 lines
7.0 KiB
C

/*
* Copyright (c) 2015-2016 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Jan Friesse (jfriesse@redhat.com)
*
* This software licensed under BSD license, the text of which follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Red Hat, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include "msgio.h"
#include "msg.h"
#include "nss-sock.h"
#include "qnetd-log.h"
#include "qnetd-client-net.h"
#include "qnetd-client-send.h"
#include "qnetd-client-msg-received.h"
#define CLIENT_ADDR_STR_LEN_COLON_PORT (1 + 5 + 1)
#define CLIENT_ADDR_STR_LEN (INET6_ADDRSTRLEN + CLIENT_ADDR_STR_LEN_COLON_PORT)
static int
qnetd_client_net_write_finished(struct qnetd_instance *instance, struct qnetd_client *client)
{
/*
* Callback is currently unused
*/
return (0);
}
int
qnetd_client_net_write(struct qnetd_instance *instance, struct qnetd_client *client)
{
int res;
struct send_buffer_list_entry *send_buffer;
send_buffer = send_buffer_list_get_active(&client->send_buffer_list);
if (send_buffer == NULL) {
qnetd_log_nss(LOG_CRIT, "send_buffer_list_get_active returned NULL");
return (-1);
}
res = msgio_write(client->socket, &send_buffer->buffer,
&send_buffer->msg_already_sent_bytes);
if (res == 1) {
send_buffer_list_delete(&client->send_buffer_list, send_buffer);
if (qnetd_client_net_write_finished(instance, client) == -1) {
return (-1);
}
}
if (res == -1) {
qnetd_log_nss(LOG_CRIT, "PR_Send returned 0");
return (-1);
}
if (res == -2) {
qnetd_log_nss(LOG_ERR, "Unhandled error when sending message to client");
return (-1);
}
return (0);
}
/*
* -1 means end of connection (EOF) or some other unhandled error. 0 = success
*/
int
qnetd_client_net_read(struct qnetd_instance *instance, struct qnetd_client *client)
{
int res;
int ret_val;
int orig_skipping_msg;
orig_skipping_msg = client->skipping_msg;
res = msgio_read(client->socket, &client->receive_buffer,
&client->msg_already_received_bytes, &client->skipping_msg);
if (!orig_skipping_msg && client->skipping_msg) {
qnetd_log(LOG_DEBUG, "msgio_read set skipping_msg");
}
ret_val = 0;
switch (res) {
case 0:
/*
* Partial read
*/
break;
case -1:
qnetd_log(LOG_DEBUG, "Client closed connection");
ret_val = -1;
break;
case -2:
qnetd_log_nss(LOG_ERR, "Unhandled error when reading from client. "
"Disconnecting client");
ret_val = -1;
break;
case -3:
qnetd_log(LOG_ERR, "Can't store message header from client. Disconnecting client");
ret_val = -1;
break;
case -4:
qnetd_log(LOG_ERR, "Can't store message from client. Skipping message");
client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_ERROR_DECODING_MSG;
break;
case -5:
qnetd_log(LOG_WARNING, "Client sent unsupported msg type %u. Skipping message",
msg_get_type(&client->receive_buffer));
client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_UNSUPPORTED_MESSAGE;
break;
case -6:
qnetd_log(LOG_WARNING,
"Client wants to send too long message %u bytes. Skipping message",
msg_get_len(&client->receive_buffer));
client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_MESSAGE_TOO_LONG;
break;
case 1:
/*
* Full message received / skipped
*/
if (!client->skipping_msg) {
if (qnetd_client_msg_received(instance, client) == -1) {
ret_val = -1;
}
} else {
if (qnetd_client_send_err(client, 0, 0, client->skipping_msg_reason) != 0) {
ret_val = -1;
}
}
client->skipping_msg = 0;
client->skipping_msg_reason = TLV_REPLY_ERROR_CODE_NO_ERROR;
client->msg_already_received_bytes = 0;
dynar_clean(&client->receive_buffer);
break;
default:
qnetd_log(LOG_ERR, "Unhandled msgio_read error %d\n", res);
exit(1);
break;
}
return (ret_val);
}
int
qnetd_client_net_accept(struct qnetd_instance *instance)
{
PRNetAddr client_addr;
PRFileDesc *client_socket;
struct qnetd_client *client;
char *client_addr_str;
int res_err;
client_addr_str = NULL;
res_err = -1;
if ((client_socket = PR_Accept(instance->server.socket, &client_addr,
PR_INTERVAL_NO_TIMEOUT)) == NULL) {
qnetd_log_nss(LOG_ERR, "Can't accept connection");
return (-1);
}
if (nss_sock_set_non_blocking(client_socket) != 0) {
qnetd_log_nss(LOG_ERR, "Can't set client socket to non blocking mode");
goto exit_close;
}
if (instance->max_clients != 0 &&
qnetd_client_list_no_clients(&instance->clients) >= instance->max_clients) {
qnetd_log(LOG_ERR, "Maximum clients reached. Not accepting connection");
goto exit_close;
}
client_addr_str = malloc(CLIENT_ADDR_STR_LEN);
if (client_addr_str == NULL) {
qnetd_log(LOG_ERR, "Can't alloc client addr str memory. Not accepting connection");
goto exit_close;
}
if (PR_NetAddrToString(&client_addr, client_addr_str, CLIENT_ADDR_STR_LEN) != PR_SUCCESS) {
qnetd_log_nss(LOG_ERR, "Can't convert client address to string. Not accepting connection");
goto exit_close;
}
if (snprintf(client_addr_str + strlen(client_addr_str),
CLIENT_ADDR_STR_LEN_COLON_PORT, ":%"PRIu16,
ntohs(client_addr.ipv6.port)) >= CLIENT_ADDR_STR_LEN_COLON_PORT) {
qnetd_log(LOG_ERR, "Can't store port to client addr str. Not accepting connection");
goto exit_close;
}
client = qnetd_client_list_add(&instance->clients, client_socket, &client_addr,
client_addr_str,
instance->advanced_settings->max_client_receive_size,
instance->advanced_settings->max_client_send_buffers,
instance->advanced_settings->max_client_send_size, &instance->main_timer_list);
if (client == NULL) {
qnetd_log(LOG_ERR, "Can't add client to list");
res_err = -2;
goto exit_close;
}
return (0);
exit_close:
free(client_addr_str);
PR_Close(client_socket);
return (res_err);
}