Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_socket.c, revision 1.1.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>