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>