blob: eff01ce086706d5c5ecf4d6ac1b6e578f8fae1c4 [file] [log] [blame]
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +02001#include "internal.h"
2
3#include <stdio.h>
4#include <unistd.h>
5#include <stdlib.h>
6#include <errno.h>
7#include <string.h>
8#include <time.h>
9#include <sys/fcntl.h>
10#include <sys/socket.h>
11#include <sys/ioctl.h>
12#include <arpa/inet.h>
13
14#include <osmocom/core/select.h>
15#include <osmocom/gsm/tlv.h>
16#include <osmocom/core/msgb.h>
17#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020018#include <osmocom/core/talloc.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020019#include <osmocom/abis/e1_input.h>
20#include <osmocom/abis/ipaccess.h>
21#include <osmocom/core/socket.h>
Pablo Neira Ayusoef132692013-07-08 01:17:27 +020022#include <osmocom/core/backtrace.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020023
24#include <osmocom/abis/ipa.h>
25
26#define IPA_ALLOC_SIZE 1200
27
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020028struct msgb *ipa_msg_alloc(int headroom)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020029{
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020030 struct msgb *nmsg;
31
32 headroom += sizeof(struct ipaccess_head);
33
34 nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "Abis/IP");
35 if (!nmsg)
36 return NULL;
37 return nmsg;
38}
39
40void ipa_msg_push_header(struct msgb *msg, uint8_t proto)
41{
42 struct ipaccess_head *hh;
43
44 msg->l2h = msg->data;
45 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
46 hh->proto = proto;
47 hh->len = htons(msgb_l2len(msg));
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020048}
49
50int ipa_msg_recv(int fd, struct msgb **rmsg)
51{
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020052 int rc = ipa_msg_recv_buffered(fd, rmsg, NULL);
53 if (rc < 0) {
54 errno = -rc;
55 rc = -1;
56 }
57 return rc;
58}
59
60int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg)
61{
62 struct msgb *msg = tmp_msg ? *tmp_msg : NULL;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020063 struct ipaccess_head *hh;
64 int len, ret;
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020065 int needed;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020066
Harald Weltef0d4a222014-08-17 18:42:13 +020067 if (msg == NULL) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020068 msg = ipa_msg_alloc(0);
Harald Weltef0d4a222014-08-17 18:42:13 +020069 msg->l1h = msg->tail;
70 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020071
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020072 if (msg == NULL) {
73 ret = -ENOMEM;
74 goto discard_msg;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020075 }
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020076
77 if (msg->l2h == NULL) {
78 /* first read our 3-byte header */
79 needed = sizeof(*hh) - msg->len;
80 ret = recv(fd, msg->tail, needed, 0);
81 if (ret == 0)
82 goto discard_msg;
83
84 if (ret < 0) {
85 if (errno == EAGAIN || errno == EINTR)
86 ret = 0;
87 else {
88 ret = -errno;
89 goto discard_msg;
90 }
91 }
92
93 msgb_put(msg, ret);
94
95 if (ret < needed) {
96 if (msg->len == 0) {
97 ret = -EAGAIN;
98 goto discard_msg;
99 }
100
101 LOGP(DLINP, LOGL_INFO,
102 "Received part of IPA message header (%d/%d)\n",
103 msg->len, sizeof(*hh));
104 if (!tmp_msg) {
105 ret = -EIO;
106 goto discard_msg;
107 }
108 *tmp_msg = msg;
109 return -EAGAIN;
110 }
111
112 msg->l2h = msg->tail;
113 }
114
115 hh = (struct ipaccess_head *) msg->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200116
117 /* then read the length as specified in header */
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200118 len = ntohs(hh->len);
119
120 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +0200121 LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200122 "received %d bytes\n", len, msg->len);
123 ret = -EIO;
124 goto discard_msg;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200125 }
126
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200127 needed = len - msgb_l2len(msg);
128
129 if (needed > 0) {
130 ret = recv(fd, msg->tail, needed, 0);
131
132 if (ret == 0)
133 goto discard_msg;
134
135 if (ret < 0) {
136 if (errno == EAGAIN || errno == EINTR)
137 ret = 0;
138 else {
139 ret = -errno;
140 goto discard_msg;
141 }
142 }
143
144 msgb_put(msg, ret);
145
146 if (ret < needed) {
147 LOGP(DLINP, LOGL_INFO,
148 "Received part of IPA message L2 data (%d/%d)\n",
149 msgb_l2len(msg), len);
150 if (!tmp_msg) {
151 ret = -EIO;
152 goto discard_msg;
153 }
154 *tmp_msg = msg;
155 return -EAGAIN;
156 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200157 }
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200158
159 ret = msgb_l2len(msg);
160
161 if (ret == 0) {
162 LOGP(DLINP, LOGL_INFO,
163 "Discarding IPA message without payload\n");
164 ret = -EAGAIN;
165 goto discard_msg;
166 }
167
168 if (tmp_msg)
169 *tmp_msg = NULL;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200170 *rmsg = msg;
171 return ret;
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200172
173discard_msg:
174 if (tmp_msg)
175 *tmp_msg = NULL;
176 msgb_free(msg);
177 return ret;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200178}
179
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200180void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200181{
Harald Weltee68055b2013-06-30 14:21:54 +0200182 /* be safe against multiple calls */
183 if (link->ofd->fd != -1) {
184 osmo_fd_unregister(link->ofd);
185 close(link->ofd->fd);
186 link->ofd->fd = -1;
187 }
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200188 msgb_free(link->pending_msg);
189 link->pending_msg = NULL;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200190}
191
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200192static void ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200193{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200194 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200195 struct msgb *msg;
196 int ret;
197
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200198 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200199
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200200 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &link->pending_msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200201 if (ret < 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200202 if (ret == -EAGAIN)
203 return;
204 if (ret == -EPIPE || ret == -ECONNRESET)
Harald Weltecc2241b2011-07-19 16:06:06 +0200205 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +0200206 ipa_client_conn_close(link);
207 if (link->updown_cb)
208 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200209 return;
210 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200211 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +0200212 ipa_client_conn_close(link);
213 if (link->updown_cb)
214 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200215 return;
216 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200217 if (link->read_cb)
218 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200219}
220
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200221static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200222{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200223 if (link->write_cb)
224 link->write_cb(link);
225}
226
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200227static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200228{
229 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200230 struct msgb *msg;
231 struct llist_head *lh;
232 int ret;
233
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200234 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200235
236 if (llist_empty(&link->tx_queue)) {
237 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200238 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200239 }
240 lh = link->tx_queue.next;
241 llist_del(lh);
242 msg = llist_entry(lh, struct msgb, list);
243
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200244 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200245 if (ret < 0) {
246 if (errno == EPIPE || errno == ENOTCONN) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200247 ipa_client_conn_close(link);
248 if (link->updown_cb)
249 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200250 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200251 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200252 }
253 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200254 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200255}
256
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200257static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200258{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200259 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200260 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200261 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200262
263 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200264 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200265 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
266 if (ret >= 0 && error > 0) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200267 ipa_client_conn_close(link);
268 if (link->updown_cb)
269 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200270 return 0;
271 }
272 ofd->when &= ~BSC_FD_WRITE;
Harald Weltecc2241b2011-07-19 16:06:06 +0200273 LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200274 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Harald Welte51de9ca2013-06-30 20:13:16 +0200275 if (link->updown_cb)
276 link->updown_cb(link, 1);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200277 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200278 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200279 if (what & BSC_FD_READ) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200280 LOGP(DLINP, LOGL_DEBUG, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200281 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200282 }
283 if (what & BSC_FD_WRITE) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200284 LOGP(DLINP, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200285 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200286 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200287 break;
288 default:
289 break;
290 }
291 return 0;
292}
293
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200294struct ipa_client_conn *
295ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200296 int priv_nr, const char *addr, uint16_t port,
Harald Welte51de9ca2013-06-30 20:13:16 +0200297 void (*updown_cb)(struct ipa_client_conn *link, int up),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200298 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200299 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200300 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200301 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200302{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200303 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200304
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200305 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200306 if (!ipa_link)
307 return NULL;
308
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200309 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200310 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200311 talloc_free(ipa_link);
312 return NULL;
313 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200314 ipa_link->ofd = &ts->driver.ipaccess.fd;
315 } else {
316 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
317 if (ipa_link->ofd == NULL) {
318 talloc_free(ipa_link);
319 return NULL;
320 }
321 }
322
323 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
324 ipa_link->ofd->priv_nr = priv_nr;
325 ipa_link->ofd->cb = ipa_client_fd_cb;
326 ipa_link->ofd->data = ipa_link;
Harald Welte51de9ca2013-06-30 20:13:16 +0200327 ipa_link->ofd->fd = -1;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200328 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200329 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200330 ipa_link->port = port;
Harald Welte51de9ca2013-06-30 20:13:16 +0200331 ipa_link->updown_cb = updown_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200332 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200333 /* default to generic write callback if not set. */
334 if (write_cb == NULL)
335 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200336 else
337 ipa_link->write_cb = write_cb;
338
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200339 if (ts)
340 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200341 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200342 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200343
344 return ipa_link;
345}
346
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200347void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200348{
349 talloc_free(link);
350}
351
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200352int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200353{
354 int ret;
355
Harald Weltee7e1b752014-08-17 21:41:34 +0200356 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200357 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200358 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200359 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
360 if (ret < 0) {
361 if (errno != EINPROGRESS)
362 return ret;
363 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200364 link->ofd->fd = ret;
365 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200366 close(ret);
Harald Welte51de9ca2013-06-30 20:13:16 +0200367 link->ofd->fd = -1;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200368 return -EIO;
369 }
Harald Welte51de9ca2013-06-30 20:13:16 +0200370
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200371 return 0;
372}
373
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200374void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200375{
376 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200377 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200378}
379
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200380static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200381{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200382 int fd, ret;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200383 struct sockaddr_in sa;
384 socklen_t sa_len = sizeof(sa);
385 struct ipa_server_link *link = ofd->data;
386
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200387 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
388 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200389 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200390 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200391 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200392 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200393 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200394 inet_ntoa(sa.sin_addr), link->port);
395
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200396 ret = link->accept_cb(link, fd);
397 if (ret < 0) {
398 LOGP(DLINP, LOGL_ERROR,
399 "failed to processs accept()ed new link, "
400 "reason=`%s'\n", strerror(-ret));
401 close(fd);
402 return ret;
403 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200404
405 return 0;
406}
407
408struct ipa_server_link *
409ipa_server_link_create(void *ctx, struct e1inp_line *line,
410 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200411 int (*accept_cb)(struct ipa_server_link *link, int fd),
412 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200413{
414 struct ipa_server_link *ipa_link;
415
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200416 OSMO_ASSERT(accept_cb != NULL);
417
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200418 ipa_link = talloc_zero(ctx, struct ipa_server_link);
419 if (!ipa_link)
420 return NULL;
421
422 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
423 ipa_link->ofd.cb = ipa_server_fd_cb;
424 ipa_link->ofd.data = ipa_link;
425 ipa_link->addr = talloc_strdup(ipa_link, addr);
426 ipa_link->port = port;
427 ipa_link->accept_cb = accept_cb;
428 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200429 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200430
431 return ipa_link;
432
433}
434
435void ipa_server_link_destroy(struct ipa_server_link *link)
436{
437 talloc_free(link);
438}
439
440int ipa_server_link_open(struct ipa_server_link *link)
441{
442 int ret;
443
444 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
445 link->addr, link->port, OSMO_SOCK_F_BIND);
446 if (ret < 0)
447 return ret;
448
449 link->ofd.fd = ret;
450 if (osmo_fd_register(&link->ofd) < 0) {
451 close(ret);
452 return -EIO;
453 }
454 return 0;
455}
456
457void ipa_server_link_close(struct ipa_server_link *link)
458{
459 osmo_fd_unregister(&link->ofd);
460 close(link->ofd.fd);
461}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200462
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200463static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200464{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200465 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200466 struct msgb *msg;
467 int ret;
468
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200469 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200470
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200471 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &conn->pending_msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200472 if (ret < 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200473 if (ret == -EAGAIN)
474 return;
475 if (ret == -EPIPE || ret == -ECONNRESET)
Harald Weltecc2241b2011-07-19 16:06:06 +0200476 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Daniel Willmanndc4479f2011-09-15 12:56:57 +0200477 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200478 return;
479 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200480 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200481 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200482 return;
483 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200484 if (conn->cb)
485 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200486
487 return;
488}
489
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200490static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200491{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200492 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200493 struct msgb *msg;
494 struct llist_head *lh;
495 int ret;
496
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200497 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200498
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200499 if (llist_empty(&conn->tx_queue)) {
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200500 ofd->when &= ~BSC_FD_WRITE;
501 return;
502 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200503 lh = conn->tx_queue.next;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200504 llist_del(lh);
505 msg = llist_entry(lh, struct msgb, list);
506
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200507 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200508 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200509 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200510 }
511 msgb_free(msg);
512}
513
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200514static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200515{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200516 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200517
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200518 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200519 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200520 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200521 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200522 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200523
524 return 0;
525}
526
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200527struct ipa_server_conn *
528ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
529 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200530 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200531{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200532 struct ipa_server_conn *conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200533
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200534 conn = talloc_zero(ctx, struct ipa_server_conn);
535 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200536 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200537 "reason=`%s'\n", strerror(errno));
538 return NULL;
539 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200540 conn->server = link;
541 conn->ofd.fd = fd;
542 conn->ofd.data = conn;
543 conn->ofd.cb = ipa_server_conn_cb;
544 conn->ofd.when = BSC_FD_READ;
545 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200546 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200547 conn->data = data;
548 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200549
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200550 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200551 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200552 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200553 return NULL;
554 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200555 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200556}
557
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200558void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200559{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200560 close(conn->ofd.fd);
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200561 msgb_free(conn->pending_msg);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200562 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200563 if (conn->closed_cb)
564 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200565 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200566}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200567
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200568void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200569{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200570 msgb_enqueue(&conn->tx_queue, msg);
571 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200572}