blob: 774d5786c628aedf6b8d884d4fd79f8104102256 [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)) {
66 msgb_free(msg);
67 return -EIO;
68 }
69 msgb_put(msg, ret);
70
71 /* then read the length as specified in header */
72 msg->l2h = msg->data + sizeof(*hh);
73 len = ntohs(hh->len);
74
75 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
76 msgb_free(msg);
77 return -EIO;
78 }
79
80 ret = recv(fd, msg->l2h, len, 0);
81 if (ret <= 0) {
82 msgb_free(msg);
83 return ret;
84 } else if (ret < len) {
85 msgb_free(msg);
86 return -EIO;
87 }
88 msgb_put(msg, ret);
89 *rmsg = msg;
90 return ret;
91}
92
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020093void ipa_client_conn_close(struct ipa_client_conn *link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020094
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020095static void ipa_client_retry(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020096{
Harald Weltecc2241b2011-07-19 16:06:06 +020097 LOGP(DLINP, LOGL_NOTICE, "connection closed\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020098 ipa_client_conn_close(link);
Harald Weltecc2241b2011-07-19 16:06:06 +020099 LOGP(DLINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200100 osmo_timer_schedule(&link->timer, 5, 0);
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200101 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200102}
103
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200104void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200105{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200106 osmo_fd_unregister(link->ofd);
107 close(link->ofd->fd);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200108}
109
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200110static void ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200111{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200112 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200113 struct msgb *msg;
114 int ret;
115
Harald Weltecc2241b2011-07-19 16:06:06 +0200116 LOGP(DLINP, LOGL_NOTICE, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200117
118 ret = ipa_msg_recv(ofd->fd, &msg);
119 if (ret < 0) {
120 if (errno == EPIPE || errno == ECONNRESET) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200121 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200122 } else {
Harald Weltecc2241b2011-07-19 16:06:06 +0200123 LOGP(DLINP, LOGL_ERROR, "unknown error\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200124 }
125 ipa_client_retry(link);
126 return;
127 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200128 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200129 ipa_client_retry(link);
130 return;
131 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200132 if (link->read_cb)
133 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200134}
135
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200136static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200137{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200138 if (link->write_cb)
139 link->write_cb(link);
140}
141
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200142static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200143{
144 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200145 struct msgb *msg;
146 struct llist_head *lh;
147 int ret;
148
Harald Weltecc2241b2011-07-19 16:06:06 +0200149 LOGP(DLINP, LOGL_NOTICE, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200150
151 if (llist_empty(&link->tx_queue)) {
152 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200153 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200154 }
155 lh = link->tx_queue.next;
156 llist_del(lh);
157 msg = llist_entry(lh, struct msgb, list);
158
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200159 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200160 if (ret < 0) {
161 if (errno == EPIPE || errno == ENOTCONN) {
162 ipa_client_retry(link);
163 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200164 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200165 }
166 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200167 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200168}
169
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200170static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200171{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200172 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200173 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200174 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200175
176 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200177 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200178 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
179 if (ret >= 0 && error > 0) {
180 ipa_client_retry(link);
181 return 0;
182 }
183 ofd->when &= ~BSC_FD_WRITE;
Harald Weltecc2241b2011-07-19 16:06:06 +0200184 LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200185 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200186 if (link->connect_cb)
187 link->connect_cb(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200188 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200189 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200190 if (what & BSC_FD_READ) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200191 LOGP(DLINP, LOGL_NOTICE, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200192 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200193 }
194 if (what & BSC_FD_WRITE) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200195 LOGP(DLINP, LOGL_NOTICE, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200196 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200197 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200198 break;
199 default:
200 break;
201 }
202 return 0;
203}
204
205static void ipa_link_timer_cb(void *data);
206
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200207struct ipa_client_conn *
208ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200209 int priv_nr, const char *addr, uint16_t port,
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200210 int (*connect_cb)(struct ipa_client_conn *link),
211 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200212 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200213 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200214 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200215{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200216 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200217
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200218 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200219 if (!ipa_link)
220 return NULL;
221
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200222 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200223 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200224 talloc_free(ipa_link);
225 return NULL;
226 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200227 ipa_link->ofd = &ts->driver.ipaccess.fd;
228 } else {
229 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
230 if (ipa_link->ofd == NULL) {
231 talloc_free(ipa_link);
232 return NULL;
233 }
234 }
235
236 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
237 ipa_link->ofd->priv_nr = priv_nr;
238 ipa_link->ofd->cb = ipa_client_fd_cb;
239 ipa_link->ofd->data = ipa_link;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200240 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200241 ipa_link->timer.cb = ipa_link_timer_cb;
242 ipa_link->timer.data = ipa_link;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200243 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200244 ipa_link->port = port;
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200245 ipa_link->connect_cb = connect_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200246 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200247 /* default to generic write callback if not set. */
248 if (write_cb == NULL)
249 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200250 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200251 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200252 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200253
254 return ipa_link;
255}
256
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200257void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200258{
259 talloc_free(link);
260}
261
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200262int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200263{
264 int ret;
265
266 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200267 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200268 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
269 if (ret < 0) {
270 if (errno != EINPROGRESS)
271 return ret;
272 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200273 link->ofd->fd = ret;
274 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200275 close(ret);
276 return -EIO;
277 }
278 return 0;
279}
280
281static void ipa_link_timer_cb(void *data)
282{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200283 struct ipa_client_conn *link = data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200284
Harald Weltecc2241b2011-07-19 16:06:06 +0200285 LOGP(DLINP, LOGL_NOTICE, "reconnecting.\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200286
287 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200288 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200289 ipa_client_conn_open(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200290 break;
291 default:
292 break;
293 }
294}
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200295
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200296void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200297{
298 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200299 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200300}
301
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200302static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200303{
304 int ret;
305 struct sockaddr_in sa;
306 socklen_t sa_len = sizeof(sa);
307 struct ipa_server_link *link = ofd->data;
308
309 ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
310 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200311 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200312 "peer, reason=`%s'\n", strerror(errno));
313 return ret;
314 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200315 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200316 inet_ntoa(sa.sin_addr), link->port);
317
318 if (link->accept_cb)
319 link->accept_cb(link, ret);
320
321 return 0;
322}
323
324struct ipa_server_link *
325ipa_server_link_create(void *ctx, struct e1inp_line *line,
326 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200327 int (*accept_cb)(struct ipa_server_link *link, int fd),
328 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200329{
330 struct ipa_server_link *ipa_link;
331
332 ipa_link = talloc_zero(ctx, struct ipa_server_link);
333 if (!ipa_link)
334 return NULL;
335
336 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
337 ipa_link->ofd.cb = ipa_server_fd_cb;
338 ipa_link->ofd.data = ipa_link;
339 ipa_link->addr = talloc_strdup(ipa_link, addr);
340 ipa_link->port = port;
341 ipa_link->accept_cb = accept_cb;
342 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200343 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200344
345 return ipa_link;
346
347}
348
349void ipa_server_link_destroy(struct ipa_server_link *link)
350{
351 talloc_free(link);
352}
353
354int ipa_server_link_open(struct ipa_server_link *link)
355{
356 int ret;
357
358 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
359 link->addr, link->port, OSMO_SOCK_F_BIND);
360 if (ret < 0)
361 return ret;
362
363 link->ofd.fd = ret;
364 if (osmo_fd_register(&link->ofd) < 0) {
365 close(ret);
366 return -EIO;
367 }
368 return 0;
369}
370
371void ipa_server_link_close(struct ipa_server_link *link)
372{
373 osmo_fd_unregister(&link->ofd);
374 close(link->ofd.fd);
375}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200376
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200377static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200378{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200379 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200380 struct msgb *msg;
381 int ret;
382
Harald Weltecc2241b2011-07-19 16:06:06 +0200383 LOGP(DLINP, LOGL_NOTICE, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200384
385 ret = ipa_msg_recv(ofd->fd, &msg);
386 if (ret < 0) {
387 if (errno == EPIPE || errno == ECONNRESET) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200388 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200389 } else {
Harald Weltecc2241b2011-07-19 16:06:06 +0200390 LOGP(DLINP, LOGL_ERROR, "unknown error\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200391 }
392 return;
393 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200394 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200395 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200396 return;
397 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200398 if (conn->cb)
399 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200400
401 return;
402}
403
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200404static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200405{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200406 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200407 struct msgb *msg;
408 struct llist_head *lh;
409 int ret;
410
Harald Weltecc2241b2011-07-19 16:06:06 +0200411 LOGP(DLINP, LOGL_NOTICE, "sending data\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200412
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200413 if (llist_empty(&conn->tx_queue)) {
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200414 ofd->when &= ~BSC_FD_WRITE;
415 return;
416 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200417 lh = conn->tx_queue.next;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200418 llist_del(lh);
419 msg = llist_entry(lh, struct msgb, list);
420
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200421 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200422 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200423 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200424 }
425 msgb_free(msg);
426}
427
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200428static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200429{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200430 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200431
Harald Weltecc2241b2011-07-19 16:06:06 +0200432 LOGP(DLINP, LOGL_NOTICE, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200433 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200434 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200435 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200436 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200437
438 return 0;
439}
440
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200441struct ipa_server_conn *
442ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
443 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200444 void *data)
445{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200446 struct ipa_server_conn *conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200447
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200448 conn = talloc_zero(ctx, struct ipa_server_conn);
449 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200450 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200451 "reason=`%s'\n", strerror(errno));
452 return NULL;
453 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200454 conn->server = link;
455 conn->ofd.fd = fd;
456 conn->ofd.data = conn;
457 conn->ofd.cb = ipa_server_conn_cb;
458 conn->ofd.when = BSC_FD_READ;
459 conn->cb = cb;
460 conn->data = data;
461 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200462
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200463 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200464 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200465 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200466 return NULL;
467 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200468 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200469}
470
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200471void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200472{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200473 close(conn->ofd.fd);
474 osmo_fd_unregister(&conn->ofd);
475 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200476}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200477
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200478void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200479{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200480 msgb_enqueue(&conn->tx_queue, msg);
481 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200482}