| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /*
- * 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 "qdevice-cmap.h"
- #include "qdevice-net-poll.h"
- #include "qdevice-log.h"
- #include "qdevice-net-send.h"
- #include "qdevice-net-socket.h"
- #include "qdevice-votequorum.h"
- enum qdevice_net_poll_pfd {
- QDEVICE_NET_POLL_VOTEQUORUM,
- QDEVICE_NET_POLL_CMAP,
- QDEVICE_NET_POLL_SOCKET,
- QDEVICE_NET_POLL_MAX_PFDS
- };
- static void
- qdevice_net_poll_read_socket(struct qdevice_net_instance *instance)
- {
- if (qdevice_net_socket_read(instance) == -1) {
- instance->schedule_disconnect = 1;
- }
- }
- static void
- qdevice_net_poll_read_votequorum(struct qdevice_net_instance *instance)
- {
- if (qdevice_votequorum_dispatch(instance->qdevice_instance_ptr) == -1) {
- instance->schedule_disconnect = 1;
- instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_COROSYNC_CONNECTION_CLOSED;
- }
- }
- static void
- qdevice_net_poll_read_cmap(struct qdevice_net_instance *instance)
- {
- if (qdevice_cmap_dispatch(instance->qdevice_instance_ptr) == -1) {
- instance->schedule_disconnect = 1;
- instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_COROSYNC_CONNECTION_CLOSED;
- }
- }
- static void
- qdevice_net_poll_write_socket(struct qdevice_net_instance *instance, const PRPollDesc *pfd)
- {
- int res;
- if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
- res = nss_sock_non_blocking_client_succeeded(pfd);
- if (res == -1) {
- /*
- * Connect failed -> try next
- */
- res = nss_sock_non_blocking_client_try_next(&instance->non_blocking_client);
- if (res == -1) {
- qdevice_log_nss(LOG_ERR, "Can't connect to qnetd host.");
- nss_sock_non_blocking_client_destroy(&instance->non_blocking_client);
- }
- } else if (res == 0) {
- /*
- * Poll again
- */
- } else if (res == 1) {
- /*
- * Connect success
- */
- instance->socket = instance->non_blocking_client.socket;
- nss_sock_non_blocking_client_destroy(&instance->non_blocking_client);
- instance->non_blocking_client.socket = NULL;
- qdevice_log(LOG_DEBUG, "Sending preinit msg to qnetd");
- if (qdevice_net_send_preinit(instance) != 0) {
- instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
- instance->schedule_disconnect = 1;
- }
- } else {
- qdevice_log(LOG_CRIT, "Unhandled nss_sock_non_blocking_client_succeeded");
- exit(1);
- }
- } else {
- if (qdevice_net_socket_write(instance) == -1) {
- instance->schedule_disconnect = 1;
- }
- }
- }
- static void
- qdevice_net_poll_err_socket(struct qdevice_net_instance *instance, const PRPollDesc *pfd)
- {
- if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
- /*
- * Workaround for RHEL<7. Pollout is never set for nonblocking connect (doesn't work
- * only with poll, select works as expected!???).
- * So test if client is still valid and if pollout was not already called (ensured
- * by default because of order in PR_Poll).
- * If both applies it's possible to emulate pollout set by calling poll_write.
- */
- if (!instance->non_blocking_client.destroyed) {
- qdevice_net_poll_write_socket(instance, pfd);
- }
- } else {
- qdevice_log(LOG_ERR, "POLL_ERR (%u) on main socket", pfd->out_flags);
- instance->schedule_disconnect = 1;
- instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_CLOSED_CONNECTION;
- }
- }
- int
- qdevice_net_poll(struct qdevice_net_instance *instance)
- {
- PRPollDesc pfds[QDEVICE_NET_POLL_MAX_PFDS];
- PRInt32 poll_res;
- PRIntn no_pfds;
- int i;
- no_pfds = 0;
- pfds[QDEVICE_NET_POLL_VOTEQUORUM].fd = instance->votequorum_poll_fd;
- pfds[QDEVICE_NET_POLL_VOTEQUORUM].in_flags = PR_POLL_READ;
- no_pfds++;
- pfds[QDEVICE_NET_POLL_CMAP].fd = instance->cmap_poll_fd;
- pfds[QDEVICE_NET_POLL_CMAP].in_flags = PR_POLL_READ;
- no_pfds++;
- if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT &&
- !instance->non_blocking_client.destroyed) {
- pfds[QDEVICE_NET_POLL_SOCKET].fd = instance->non_blocking_client.socket;
- pfds[QDEVICE_NET_POLL_SOCKET].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
- no_pfds++;
- } else {
- pfds[QDEVICE_NET_POLL_SOCKET].fd = instance->socket;
- pfds[QDEVICE_NET_POLL_SOCKET].in_flags = PR_POLL_READ;
- if (!send_buffer_list_empty(&instance->send_buffer_list)) {
- pfds[QDEVICE_NET_POLL_SOCKET].in_flags |= PR_POLL_WRITE;
- }
- no_pfds++;
- }
- instance->schedule_disconnect = 0;
- if ((poll_res = PR_Poll(pfds, no_pfds,
- timer_list_time_to_expire(&instance->main_timer_list))) > 0) {
- for (i = 0; i < no_pfds; i++) {
- if (pfds[i].out_flags & PR_POLL_READ) {
- switch (i) {
- case QDEVICE_NET_POLL_SOCKET:
- qdevice_net_poll_read_socket(instance);
- break;
- case QDEVICE_NET_POLL_VOTEQUORUM:
- qdevice_net_poll_read_votequorum(instance);
- break;
- case QDEVICE_NET_POLL_CMAP:
- qdevice_net_poll_read_cmap(instance);
- break;
- default:
- qdevice_log(LOG_CRIT, "Unhandled read on poll descriptor %u", i);
- exit(1);
- break;
- }
- }
- if (!instance->schedule_disconnect && pfds[i].out_flags & PR_POLL_WRITE) {
- switch (i) {
- case QDEVICE_NET_POLL_SOCKET:
- qdevice_net_poll_write_socket(instance, &pfds[i]);
- break;
- default:
- qdevice_log(LOG_CRIT, "Unhandled write on poll descriptor %u", i);
- exit(1);
- break;
- }
- }
- if (!instance->schedule_disconnect &&
- (pfds[i].out_flags & (PR_POLL_ERR|PR_POLL_NVAL|PR_POLL_HUP|PR_POLL_EXCEPT)) &&
- !(pfds[i].out_flags & (PR_POLL_READ|PR_POLL_WRITE))) {
- switch (i) {
- case QDEVICE_NET_POLL_SOCKET:
- qdevice_net_poll_err_socket(instance, &pfds[i]);
- break;
- default:
- qdevice_log(LOG_CRIT, "Unhandled error on poll descriptor %u", i);
- exit(1);
- break;
- }
- }
- }
- }
- if (!instance->schedule_disconnect) {
- timer_list_expire(&instance->main_timer_list);
- }
- if (instance->schedule_disconnect) {
- /*
- * Schedule disconnect can be set by this function, by some timer_list callback
- * or cmap/votequorum callbacks
- */
- return (-1);
- }
- return (0);
- }
|