blob: 3abd2b89695d303d220aff9b8fab36692d73bb76 [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 Ayuso96e81282011-06-09 15:06:11 +020022
23#include <osmocom/abis/ipa.h>
24
25#define IPA_ALLOC_SIZE 1200
26
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020027struct msgb *ipa_msg_alloc(int headroom)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020028{
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020029 struct msgb *nmsg;
30
31 headroom += sizeof(struct ipaccess_head);
32
33 nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "Abis/IP");
34 if (!nmsg)
35 return NULL;
36 return nmsg;
37}
38
39void ipa_msg_push_header(struct msgb *msg, uint8_t proto)
40{
41 struct ipaccess_head *hh;
42
43 msg->l2h = msg->data;
44 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
45 hh->proto = proto;
46 hh->len = htons(msgb_l2len(msg));
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020047}
48
49int ipa_msg_recv(int fd, struct msgb **rmsg)
50{
51 struct msgb *msg;
52 struct ipaccess_head *hh;
53 int len, ret;
54
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020055 msg = ipa_msg_alloc(0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020056 if (msg == NULL)
57 return -ENOMEM;
58
59 /* first read our 3-byte header */
60 hh = (struct ipaccess_head *) msg->data;
61 ret = recv(fd, msg->data, sizeof(*hh), 0);
62 if (ret <= 0) {
63 msgb_free(msg);
64 return ret;
65 } else if (ret != sizeof(*hh)) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +020066 LOGP(DLINP, LOGL_ERROR, "too small message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020067 msgb_free(msg);
68 return -EIO;
69 }
70 msgb_put(msg, ret);
71
72 /* then read the length as specified in header */
73 msg->l2h = msg->data + sizeof(*hh);
74 len = ntohs(hh->len);
75
76 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +020077 LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
78 "received %d bytes\n", len, ret);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020079 msgb_free(msg);
80 return -EIO;
81 }
82
83 ret = recv(fd, msg->l2h, len, 0);
84 if (ret <= 0) {
85 msgb_free(msg);
86 return ret;
87 } else if (ret < len) {
Pablo Neira Ayuso32c883a2011-09-09 01:01:36 +020088 LOGP(DLINP, LOGL_ERROR, "trunked message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020089 msgb_free(msg);
90 return -EIO;
91 }
92 msgb_put(msg, ret);
93 *rmsg = msg;
94 return ret;
95}
96
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020097void ipa_client_conn_close(struct ipa_client_conn *link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020098
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020099static void ipa_client_retry(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200100{
Harald Weltecc2241b2011-07-19 16:06:06 +0200101 LOGP(DLINP, LOGL_NOTICE, "connection closed\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200102 ipa_client_conn_close(link);
Harald Weltecc2241b2011-07-19 16:06:06 +0200103 LOGP(DLINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200104 osmo_timer_schedule(&link->timer, 5, 0);
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200105 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200106}
107
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200108void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200109{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200110 osmo_fd_unregister(link->ofd);
111 close(link->ofd->fd);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200112}
113
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200114static void ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200115{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200116 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200117 struct msgb *msg;
118 int ret;
119
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200120 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200121
122 ret = ipa_msg_recv(ofd->fd, &msg);
123 if (ret < 0) {
124 if (errno == EPIPE || errno == ECONNRESET) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200125 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200126 }
127 ipa_client_retry(link);
128 return;
129 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200130 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200131 ipa_client_retry(link);
132 return;
133 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200134 if (link->read_cb)
135 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200136}
137
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200138static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200139{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200140 if (link->write_cb)
141 link->write_cb(link);
142}
143
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200144static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200145{
146 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200147 struct msgb *msg;
148 struct llist_head *lh;
149 int ret;
150
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200151 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200152
153 if (llist_empty(&link->tx_queue)) {
154 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200155 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200156 }
157 lh = link->tx_queue.next;
158 llist_del(lh);
159 msg = llist_entry(lh, struct msgb, list);
160
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200161 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200162 if (ret < 0) {
163 if (errno == EPIPE || errno == ENOTCONN) {
164 ipa_client_retry(link);
165 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200166 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200167 }
168 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200169 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200170}
171
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200172static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200173{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200174 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200175 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200176 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200177
178 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200179 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200180 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
181 if (ret >= 0 && error > 0) {
182 ipa_client_retry(link);
183 return 0;
184 }
185 ofd->when &= ~BSC_FD_WRITE;
Harald Weltecc2241b2011-07-19 16:06:06 +0200186 LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200187 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200188 if (link->connect_cb)
189 link->connect_cb(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200190 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200191 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200192 if (what & BSC_FD_READ) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200193 LOGP(DLINP, LOGL_DEBUG, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200194 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200195 }
196 if (what & BSC_FD_WRITE) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200197 LOGP(DLINP, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200198 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200199 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200200 break;
201 default:
202 break;
203 }
204 return 0;
205}
206
207static void ipa_link_timer_cb(void *data);
208
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200209struct ipa_client_conn *
210ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200211 int priv_nr, const char *addr, uint16_t port,
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200212 int (*connect_cb)(struct ipa_client_conn *link),
213 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200214 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200215 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200216 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200217{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200218 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200219
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200220 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200221 if (!ipa_link)
222 return NULL;
223
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200224 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200225 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200226 talloc_free(ipa_link);
227 return NULL;
228 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200229 ipa_link->ofd = &ts->driver.ipaccess.fd;
230 } else {
231 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
232 if (ipa_link->ofd == NULL) {
233 talloc_free(ipa_link);
234 return NULL;
235 }
236 }
237
238 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
239 ipa_link->ofd->priv_nr = priv_nr;
240 ipa_link->ofd->cb = ipa_client_fd_cb;
241 ipa_link->ofd->data = ipa_link;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200242 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200243 ipa_link->timer.cb = ipa_link_timer_cb;
244 ipa_link->timer.data = ipa_link;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200245 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200246 ipa_link->port = port;
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200247 ipa_link->connect_cb = connect_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200248 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200249 /* default to generic write callback if not set. */
250 if (write_cb == NULL)
251 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200252 else
253 ipa_link->write_cb = write_cb;
254
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200255 if (ts)
256 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200257 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200258 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200259
260 return ipa_link;
261}
262
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200263void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200264{
265 talloc_free(link);
266}
267
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200268int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200269{
270 int ret;
271
272 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200273 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200274 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
275 if (ret < 0) {
276 if (errno != EINPROGRESS)
277 return ret;
278 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200279 link->ofd->fd = ret;
280 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200281 close(ret);
282 return -EIO;
283 }
284 return 0;
285}
286
287static void ipa_link_timer_cb(void *data)
288{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200289 struct ipa_client_conn *link = data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200290
Harald Weltecc2241b2011-07-19 16:06:06 +0200291 LOGP(DLINP, LOGL_NOTICE, "reconnecting.\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200292
293 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200294 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200295 ipa_client_conn_open(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200296 break;
297 default:
298 break;
299 }
300}
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200301
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200302void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200303{
304 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200305 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200306}
307
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200308static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200309{
310 int ret;
311 struct sockaddr_in sa;
312 socklen_t sa_len = sizeof(sa);
313 struct ipa_server_link *link = ofd->data;
314
315 ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
316 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200317 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200318 "peer, reason=`%s'\n", strerror(errno));
319 return ret;
320 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200321 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200322 inet_ntoa(sa.sin_addr), link->port);
323
324 if (link->accept_cb)
325 link->accept_cb(link, ret);
Pablo Neira Ayusoa8c48712013-07-05 14:47:41 +0200326 else
327 close(ret);
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200328
329 return 0;
330}
331
332struct ipa_server_link *
333ipa_server_link_create(void *ctx, struct e1inp_line *line,
334 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200335 int (*accept_cb)(struct ipa_server_link *link, int fd),
336 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200337{
338 struct ipa_server_link *ipa_link;
339
340 ipa_link = talloc_zero(ctx, struct ipa_server_link);
341 if (!ipa_link)
342 return NULL;
343
344 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
345 ipa_link->ofd.cb = ipa_server_fd_cb;
346 ipa_link->ofd.data = ipa_link;
347 ipa_link->addr = talloc_strdup(ipa_link, addr);
348 ipa_link->port = port;
349 ipa_link->accept_cb = accept_cb;
350 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200351 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200352
353 return ipa_link;
354
355}
356
357void ipa_server_link_destroy(struct ipa_server_link *link)
358{
359 talloc_free(link);
360}
361
362int ipa_server_link_open(struct ipa_server_link *link)
363{
364 int ret;
365
366 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
367 link->addr, link->port, OSMO_SOCK_F_BIND);
368 if (ret < 0)
369 return ret;
370
371 link->ofd.fd = ret;
372 if (osmo_fd_register(&link->ofd) < 0) {
373 close(ret);
374 return -EIO;
375 }
376 return 0;
377}
378
379void ipa_server_link_close(struct ipa_server_link *link)
380{
381 osmo_fd_unregister(&link->ofd);
382 close(link->ofd.fd);
383}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200384
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200385static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200386{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200387 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200388 struct msgb *msg;
389 int ret;
390
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200391 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200392
393 ret = ipa_msg_recv(ofd->fd, &msg);
394 if (ret < 0) {
395 if (errno == EPIPE || errno == ECONNRESET) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200396 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200397 }
Daniel Willmanndc4479f2011-09-15 12:56:57 +0200398 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200399 return;
400 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200401 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200402 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200403 return;
404 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200405 if (conn->cb)
406 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200407
408 return;
409}
410
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200411static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200412{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200413 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200414 struct msgb *msg;
415 struct llist_head *lh;
416 int ret;
417
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200418 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200419
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200420 if (llist_empty(&conn->tx_queue)) {
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200421 ofd->when &= ~BSC_FD_WRITE;
422 return;
423 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200424 lh = conn->tx_queue.next;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200425 llist_del(lh);
426 msg = llist_entry(lh, struct msgb, list);
427
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200428 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200429 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200430 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200431 }
432 msgb_free(msg);
433}
434
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200435static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200436{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200437 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200438
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200439 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200440 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200441 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200442 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200443 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200444
445 return 0;
446}
447
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200448struct ipa_server_conn *
449ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
450 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200451 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200452{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200453 struct ipa_server_conn *conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200454
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200455 conn = talloc_zero(ctx, struct ipa_server_conn);
456 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200457 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200458 "reason=`%s'\n", strerror(errno));
459 return NULL;
460 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200461 conn->server = link;
462 conn->ofd.fd = fd;
463 conn->ofd.data = conn;
464 conn->ofd.cb = ipa_server_conn_cb;
465 conn->ofd.when = BSC_FD_READ;
466 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200467 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200468 conn->data = data;
469 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200470
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200471 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200472 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200473 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200474 return NULL;
475 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200476 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200477}
478
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200479void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200480{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200481 close(conn->ofd.fd);
482 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200483 if (conn->closed_cb)
484 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200485 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200486}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200487
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200488void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200489{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200490 msgb_enqueue(&conn->tx_queue, msg);
491 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200492}