Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_socket.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2018 Tobias Brunner
! 3: * Copyright (C) 2008-2009 Martin Willi
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #include "ha_socket.h"
! 18: #include "ha_plugin.h"
! 19:
! 20: #include <sys/types.h>
! 21: #include <sys/socket.h>
! 22: #include <errno.h>
! 23: #include <unistd.h>
! 24:
! 25: #include <daemon.h>
! 26: #include <networking/host.h>
! 27: #include <threading/thread.h>
! 28: #include <processing/jobs/callback_job.h>
! 29:
! 30: typedef struct private_ha_socket_t private_ha_socket_t;
! 31:
! 32: /**
! 33: * Private data of an ha_socket_t object.
! 34: */
! 35: struct private_ha_socket_t {
! 36:
! 37: /**
! 38: * Public ha_socket_t interface.
! 39: */
! 40: ha_socket_t public;
! 41:
! 42: /**
! 43: * UDP communication socket fd
! 44: */
! 45: int fd;
! 46:
! 47: /**
! 48: * local host to receive/send from
! 49: */
! 50: host_t *local;
! 51:
! 52: /**
! 53: * remote host to receive/send to
! 54: */
! 55: host_t *remote;
! 56:
! 57: /**
! 58: * Receive buffer size
! 59: */
! 60: u_int buflen;
! 61: };
! 62:
! 63: /**
! 64: * Data to pass to the send_message() callback job
! 65: */
! 66: typedef struct {
! 67: chunk_t chunk;
! 68: int fd;
! 69: } job_data_t;
! 70:
! 71: /**
! 72: * Cleanup job data
! 73: */
! 74: static void job_data_destroy(job_data_t *this)
! 75: {
! 76: free(this->chunk.ptr);
! 77: free(this);
! 78: }
! 79:
! 80: /**
! 81: * Callback to asynchronously send messages
! 82: */
! 83: static job_requeue_t send_message(job_data_t *data)
! 84: {
! 85: if (send(data->fd, data->chunk.ptr, data->chunk.len, 0) < data->chunk.len)
! 86: {
! 87: DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
! 88: }
! 89: return JOB_REQUEUE_NONE;
! 90: }
! 91:
! 92: METHOD(ha_socket_t, push, void,
! 93: private_ha_socket_t *this, ha_message_t *message)
! 94: {
! 95: chunk_t chunk;
! 96:
! 97: /* Try to send synchronously, but non-blocking. */
! 98: chunk = message->get_encoding(message);
! 99: if (send(this->fd, chunk.ptr, chunk.len, MSG_DONTWAIT) < chunk.len)
! 100: {
! 101: if (errno == EAGAIN)
! 102: {
! 103: callback_job_t *job;
! 104: job_data_t *data;
! 105:
! 106: /* Fallback to asynchronous transmission. This is required, as sendto()
! 107: * is a blocking call if it acquires a policy. We could end up in a
! 108: * deadlock, as we own an IKE_SA. */
! 109: INIT(data,
! 110: .chunk = chunk_clone(chunk),
! 111: .fd = this->fd,
! 112: );
! 113:
! 114: job = callback_job_create_with_prio((callback_job_cb_t)send_message,
! 115: data, (void*)job_data_destroy, NULL, JOB_PRIO_HIGH);
! 116: lib->processor->queue_job(lib->processor, (job_t*)job);
! 117: return;
! 118: }
! 119: DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
! 120: }
! 121: }
! 122:
! 123: METHOD(ha_socket_t, pull, ha_message_t*,
! 124: private_ha_socket_t *this)
! 125: {
! 126: while (TRUE)
! 127: {
! 128: ha_message_t *message;
! 129: char buf[this->buflen];
! 130: struct iovec iov = {
! 131: .iov_base = buf,
! 132: .iov_len = this->buflen,
! 133: };
! 134: struct msghdr msg = {
! 135: .msg_iov = &iov,
! 136: .msg_iovlen = 1,
! 137: };
! 138: bool oldstate;
! 139: ssize_t len;
! 140:
! 141: oldstate = thread_cancelability(TRUE);
! 142: len = recvmsg(this->fd, &msg, 0);
! 143: thread_cancelability(oldstate);
! 144: if (msg.msg_flags & MSG_TRUNC)
! 145: {
! 146: DBG1(DBG_CFG, "HA message exceeds receive buffer");
! 147: continue;
! 148: }
! 149: if (len <= 0)
! 150: {
! 151: switch (errno)
! 152: {
! 153: case ECONNREFUSED:
! 154: case EINTR:
! 155: continue;
! 156: default:
! 157: DBG1(DBG_CFG, "pulling HA message failed: %s",
! 158: strerror(errno));
! 159: sleep(1);
! 160: continue;
! 161: }
! 162: }
! 163: message = ha_message_parse(chunk_create(buf, len));
! 164: if (message)
! 165: {
! 166: return message;
! 167: }
! 168: }
! 169: }
! 170:
! 171: /**
! 172: * Open and connect the HA socket
! 173: */
! 174: static bool open_socket(private_ha_socket_t *this)
! 175: {
! 176: this->fd = socket(this->local->get_family(this->local), SOCK_DGRAM, 0);
! 177: if (this->fd == -1)
! 178: {
! 179: DBG1(DBG_CFG, "opening HA socket failed: %s", strerror(errno));
! 180: return FALSE;
! 181: }
! 182:
! 183: if (bind(this->fd, this->local->get_sockaddr(this->local),
! 184: *this->local->get_sockaddr_len(this->local)) == -1)
! 185: {
! 186: DBG1(DBG_CFG, "binding HA socket failed: %s", strerror(errno));
! 187: close(this->fd);
! 188: this->fd = -1;
! 189: return FALSE;
! 190: }
! 191: if (connect(this->fd, this->remote->get_sockaddr(this->remote),
! 192: *this->remote->get_sockaddr_len(this->remote)) == -1)
! 193: {
! 194: DBG1(DBG_CFG, "connecting HA socket failed: %s", strerror(errno));
! 195: close(this->fd);
! 196: this->fd = -1;
! 197: return FALSE;
! 198: }
! 199:
! 200: return TRUE;
! 201: }
! 202:
! 203: METHOD(ha_socket_t, destroy, void,
! 204: private_ha_socket_t *this)
! 205: {
! 206: if (this->fd != -1)
! 207: {
! 208: close(this->fd);
! 209: }
! 210: DESTROY_IF(this->local);
! 211: DESTROY_IF(this->remote);
! 212: free(this);
! 213: }
! 214:
! 215: /**
! 216: * See header
! 217: */
! 218: ha_socket_t *ha_socket_create(char *local, char *remote)
! 219: {
! 220: private_ha_socket_t *this;
! 221:
! 222: INIT(this,
! 223: .public = {
! 224: .push = _push,
! 225: .pull = _pull,
! 226: .destroy = _destroy,
! 227: },
! 228: .local = host_create_from_dns(local, 0, HA_PORT),
! 229: .remote = host_create_from_dns(remote, 0, HA_PORT),
! 230: .buflen = lib->settings->get_int(lib->settings,
! 231: "%s.plugins.ha.buflen", 2048, lib->ns),
! 232: .fd = -1,
! 233: );
! 234:
! 235: if (!this->local || !this->remote)
! 236: {
! 237: DBG1(DBG_CFG, "invalid local/remote HA address");
! 238: destroy(this);
! 239: return NULL;
! 240: }
! 241: if (!open_socket(this))
! 242: {
! 243: destroy(this);
! 244: return NULL;
! 245: }
! 246: return &this->public;
! 247: }
! 248:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>