blob: 8c6f60353db2fb39e463ce18fc6ef1c0c8e80f29 [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{
52 struct msgb *msg;
53 struct ipaccess_head *hh;
54 int len, ret;
55
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020056 msg = ipa_msg_alloc(0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020057 if (msg == NULL)
58 return -ENOMEM;
59
60 /* first read our 3-byte header */
61 hh = (struct ipaccess_head *) msg->data;
62 ret = recv(fd, msg->data, sizeof(*hh), 0);
63 if (ret <= 0) {
64 msgb_free(msg);
65 return ret;
66 } else if (ret != sizeof(*hh)) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +020067 LOGP(DLINP, LOGL_ERROR, "too small message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020068 msgb_free(msg);
69 return -EIO;
70 }
71 msgb_put(msg, ret);
72
73 /* then read the length as specified in header */
74 msg->l2h = msg->data + sizeof(*hh);
75 len = ntohs(hh->len);
76
77 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +020078 LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
79 "received %d bytes\n", len, ret);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020080 msgb_free(msg);
81 return -EIO;
82 }
83
84 ret = recv(fd, msg->l2h, len, 0);
85 if (ret <= 0) {
86 msgb_free(msg);
87 return ret;
88 } else if (ret < len) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +020089 LOGP(DLINP, LOGL_ERROR, "trunked message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020090 msgb_free(msg);
91 return -EIO;
92 }
93 msgb_put(msg, ret);
94 *rmsg = msg;
95 return ret;
96}
97
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020098void ipa_client_conn_close(struct ipa_client_conn *link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020099
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200100static void ipa_client_retry(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200101{
Harald Weltecc2241b2011-07-19 16:06:06 +0200102 LOGP(DLINP, LOGL_NOTICE, "connection closed\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200103 ipa_client_conn_close(link);
Harald Weltecc2241b2011-07-19 16:06:06 +0200104 LOGP(DLINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200105 osmo_timer_schedule(&link->timer, 5, 0);
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200106 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200107}
108
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200109void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200110{
Harald Weltee68055b2013-06-30 14:21:54 +0200111 /* be safe against multiple calls */
112 if (link->ofd->fd != -1) {
113 osmo_fd_unregister(link->ofd);
114 close(link->ofd->fd);
115 link->ofd->fd = -1;
116 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200117}
118
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200119static void ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200120{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200121 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200122 struct msgb *msg;
123 int ret;
124
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200125 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200126
127 ret = ipa_msg_recv(ofd->fd, &msg);
128 if (ret < 0) {
129 if (errno == EPIPE || errno == ECONNRESET) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200130 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200131 }
132 ipa_client_retry(link);
133 return;
134 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200135 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200136 ipa_client_retry(link);
137 return;
138 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200139 if (link->read_cb)
140 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200141}
142
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200143static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200144{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200145 if (link->write_cb)
146 link->write_cb(link);
147}
148
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200149static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200150{
151 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200152 struct msgb *msg;
153 struct llist_head *lh;
154 int ret;
155
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200156 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200157
158 if (llist_empty(&link->tx_queue)) {
159 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200160 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200161 }
162 lh = link->tx_queue.next;
163 llist_del(lh);
164 msg = llist_entry(lh, struct msgb, list);
165
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200166 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200167 if (ret < 0) {
168 if (errno == EPIPE || errno == ENOTCONN) {
169 ipa_client_retry(link);
170 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200171 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200172 }
173 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200174 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200175}
176
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200177static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200178{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200179 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200180 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200181 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200182
183 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200184 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200185 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
186 if (ret >= 0 && error > 0) {
187 ipa_client_retry(link);
188 return 0;
189 }
190 ofd->when &= ~BSC_FD_WRITE;
Harald Weltecc2241b2011-07-19 16:06:06 +0200191 LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200192 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200193 if (link->connect_cb)
194 link->connect_cb(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200195 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200196 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200197 if (what & BSC_FD_READ) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200198 LOGP(DLINP, LOGL_DEBUG, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200199 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200200 }
201 if (what & BSC_FD_WRITE) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200202 LOGP(DLINP, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200203 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200204 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200205 break;
206 default:
207 break;
208 }
209 return 0;
210}
211
212static void ipa_link_timer_cb(void *data);
213
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200214struct ipa_client_conn *
215ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200216 int priv_nr, const char *addr, uint16_t port,
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200217 int (*connect_cb)(struct ipa_client_conn *link),
218 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200219 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200220 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200221 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200222{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200223 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200224
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200225 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200226 if (!ipa_link)
227 return NULL;
228
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200229 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200230 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200231 talloc_free(ipa_link);
232 return NULL;
233 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200234 ipa_link->ofd = &ts->driver.ipaccess.fd;
235 } else {
236 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
237 if (ipa_link->ofd == NULL) {
238 talloc_free(ipa_link);
239 return NULL;
240 }
241 }
242
243 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
244 ipa_link->ofd->priv_nr = priv_nr;
245 ipa_link->ofd->cb = ipa_client_fd_cb;
246 ipa_link->ofd->data = ipa_link;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200247 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200248 ipa_link->timer.cb = ipa_link_timer_cb;
249 ipa_link->timer.data = ipa_link;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200250 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200251 ipa_link->port = port;
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200252 ipa_link->connect_cb = connect_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200253 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200254 /* default to generic write callback if not set. */
255 if (write_cb == NULL)
256 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200257 else
258 ipa_link->write_cb = write_cb;
259
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200260 if (ts)
261 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200262 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200263 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200264
265 return ipa_link;
266}
267
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200268void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200269{
270 talloc_free(link);
271}
272
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200273int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200274{
275 int ret;
276
277 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200278 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200279 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
280 if (ret < 0) {
281 if (errno != EINPROGRESS)
282 return ret;
283 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200284 link->ofd->fd = ret;
285 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200286 close(ret);
287 return -EIO;
288 }
289 return 0;
290}
291
292static void ipa_link_timer_cb(void *data)
293{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200294 struct ipa_client_conn *link = data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200295
Harald Weltecc2241b2011-07-19 16:06:06 +0200296 LOGP(DLINP, LOGL_NOTICE, "reconnecting.\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200297
298 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200299 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200300 ipa_client_conn_open(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200301 break;
302 default:
303 break;
304 }
305}
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200306
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200307void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200308{
309 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200310 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200311}
312
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200313static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200314{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200315 int fd, ret;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200316 struct sockaddr_in sa;
317 socklen_t sa_len = sizeof(sa);
318 struct ipa_server_link *link = ofd->data;
319
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200320 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
321 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200322 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200323 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200324 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200325 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200326 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200327 inet_ntoa(sa.sin_addr), link->port);
328
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200329 ret = link->accept_cb(link, fd);
330 if (ret < 0) {
331 LOGP(DLINP, LOGL_ERROR,
332 "failed to processs accept()ed new link, "
333 "reason=`%s'\n", strerror(-ret));
334 close(fd);
335 return ret;
336 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200337
338 return 0;
339}
340
341struct ipa_server_link *
342ipa_server_link_create(void *ctx, struct e1inp_line *line,
343 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200344 int (*accept_cb)(struct ipa_server_link *link, int fd),
345 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200346{
347 struct ipa_server_link *ipa_link;
348
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200349 OSMO_ASSERT(accept_cb != NULL);
350
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200351 ipa_link = talloc_zero(ctx, struct ipa_server_link);
352 if (!ipa_link)
353 return NULL;
354
355 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
356 ipa_link->ofd.cb = ipa_server_fd_cb;
357 ipa_link->ofd.data = ipa_link;
358 ipa_link->addr = talloc_strdup(ipa_link, addr);
359 ipa_link->port = port;
360 ipa_link->accept_cb = accept_cb;
361 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200362 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200363
364 return ipa_link;
365
366}
367
368void ipa_server_link_destroy(struct ipa_server_link *link)
369{
370 talloc_free(link);
371}
372
373int ipa_server_link_open(struct ipa_server_link *link)
374{
375 int ret;
376
377 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
378 link->addr, link->port, OSMO_SOCK_F_BIND);
379 if (ret < 0)
380 return ret;
381
382 link->ofd.fd = ret;
383 if (osmo_fd_register(&link->ofd) < 0) {
384 close(ret);
385 return -EIO;
386 }
387 return 0;
388}
389
390void ipa_server_link_close(struct ipa_server_link *link)
391{
392 osmo_fd_unregister(&link->ofd);
393 close(link->ofd.fd);
394}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200395
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200396static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200397{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200398 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200399 struct msgb *msg;
400 int ret;
401
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200402 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200403
404 ret = ipa_msg_recv(ofd->fd, &msg);
405 if (ret < 0) {
406 if (errno == EPIPE || errno == ECONNRESET) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200407 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200408 }
Daniel Willmanndc4479f2011-09-15 12:56:57 +0200409 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200410 return;
411 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200412 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200413 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200414 return;
415 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200416 if (conn->cb)
417 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200418
419 return;
420}
421
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200422static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200423{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200424 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200425 struct msgb *msg;
426 struct llist_head *lh;
427 int ret;
428
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200429 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200430
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200431 if (llist_empty(&conn->tx_queue)) {
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200432 ofd->when &= ~BSC_FD_WRITE;
433 return;
434 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200435 lh = conn->tx_queue.next;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200436 llist_del(lh);
437 msg = llist_entry(lh, struct msgb, list);
438
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200439 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200440 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200441 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200442 }
443 msgb_free(msg);
444}
445
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200446static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200447{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200448 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200449
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200450 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200451 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200452 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200453 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200454 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200455
456 return 0;
457}
458
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200459struct ipa_server_conn *
460ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
461 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200462 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200463{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200464 struct ipa_server_conn *conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200465
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200466 conn = talloc_zero(ctx, struct ipa_server_conn);
467 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200468 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200469 "reason=`%s'\n", strerror(errno));
470 return NULL;
471 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200472 conn->server = link;
473 conn->ofd.fd = fd;
474 conn->ofd.data = conn;
475 conn->ofd.cb = ipa_server_conn_cb;
476 conn->ofd.when = BSC_FD_READ;
477 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200478 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200479 conn->data = data;
480 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200481
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200482 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200483 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200484 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200485 return NULL;
486 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200487 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200488}
489
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200490void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200491{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200492 close(conn->ofd.fd);
493 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200494 if (conn->closed_cb)
495 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200496 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200497}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200498
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200499void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200500{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200501 msgb_enqueue(&conn->tx_queue, msg);
502 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200503}