blob: 2d499ee337130bc573b511f47baec184fadffe75 [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>
18#include <talloc.h>
19#include <osmocom/abis/e1_input.h>
20#include <osmocom/abis/ipaccess.h>
21#include <osmocom/core/socket.h>
22#include <osmocom/abis/logging.h>
23
24#include <osmocom/abis/ipa.h>
25
26#define IPA_ALLOC_SIZE 1200
27
28static struct msgb *ipa_msg_alloc(void)
29{
30 return msgb_alloc(IPA_ALLOC_SIZE, "Abis/IP");
31}
32
33int ipa_msg_recv(int fd, struct msgb **rmsg)
34{
35 struct msgb *msg;
36 struct ipaccess_head *hh;
37 int len, ret;
38
39 msg = ipa_msg_alloc();
40 if (msg == NULL)
41 return -ENOMEM;
42
43 /* first read our 3-byte header */
44 hh = (struct ipaccess_head *) msg->data;
45 ret = recv(fd, msg->data, sizeof(*hh), 0);
46 if (ret <= 0) {
47 msgb_free(msg);
48 return ret;
49 } else if (ret != sizeof(*hh)) {
50 msgb_free(msg);
51 return -EIO;
52 }
53 msgb_put(msg, ret);
54
55 /* then read the length as specified in header */
56 msg->l2h = msg->data + sizeof(*hh);
57 len = ntohs(hh->len);
58
59 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
60 msgb_free(msg);
61 return -EIO;
62 }
63
64 ret = recv(fd, msg->l2h, len, 0);
65 if (ret <= 0) {
66 msgb_free(msg);
67 return ret;
68 } else if (ret < len) {
69 msgb_free(msg);
70 return -EIO;
71 }
72 msgb_put(msg, ret);
73 *rmsg = msg;
74 return ret;
75}
76
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020077void ipa_client_link_close(struct ipa_client_link *link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020078
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020079static void ipa_client_retry(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020080{
81 LOGP(DINP, LOGL_NOTICE, "connection closed\n");
82 ipa_client_link_close(link);
83 LOGP(DINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
84 osmo_timer_schedule(&link->timer, 5, 0);
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020085 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020086}
87
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020088void ipa_client_link_close(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020089{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020090 osmo_fd_unregister(link->ofd);
91 close(link->ofd->fd);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020092}
93
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020094static void ipa_client_read(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020095{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020096 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020097 struct msgb *msg;
98 int ret;
99
100 LOGP(DINP, LOGL_NOTICE, "message received\n");
101
102 ret = ipa_msg_recv(ofd->fd, &msg);
103 if (ret < 0) {
104 if (errno == EPIPE || errno == ECONNRESET) {
105 LOGP(DINP, LOGL_ERROR, "lost connection with server\n");
106 } else {
107 LOGP(DINP, LOGL_ERROR, "unknown error\n");
108 }
109 ipa_client_retry(link);
110 return;
111 } else if (ret == 0) {
112 LOGP(DINP, LOGL_ERROR, "connection closed with server\n");
113 ipa_client_retry(link);
114 return;
115 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200116 if (link->read_cb)
117 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200118}
119
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200120static void ipa_client_write(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200121{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200122 if (link->write_cb)
123 link->write_cb(link);
124}
125
126int ipa_client_write_default_cb(struct ipa_client_link *link)
127{
128 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200129 struct msgb *msg;
130 struct llist_head *lh;
131 int ret;
132
133 LOGP(DINP, LOGL_NOTICE, "sending data\n");
134
135 if (llist_empty(&link->tx_queue)) {
136 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200137 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200138 }
139 lh = link->tx_queue.next;
140 llist_del(lh);
141 msg = llist_entry(lh, struct msgb, list);
142
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200143 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200144 if (ret < 0) {
145 if (errno == EPIPE || errno == ENOTCONN) {
146 ipa_client_retry(link);
147 }
148 LOGP(DINP, LOGL_ERROR, "error to send\n");
149 }
150 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200151 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200152}
153
154int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
155{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200156 struct ipa_client_link *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200157 int error, ret;
158 size_t len = sizeof(error);
159
160 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200161 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200162 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
163 if (ret >= 0 && error > 0) {
164 ipa_client_retry(link);
165 return 0;
166 }
167 ofd->when &= ~BSC_FD_WRITE;
168 LOGP(DINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200169 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200170 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200171 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200172 if (what & BSC_FD_READ) {
173 LOGP(DINP, LOGL_NOTICE, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200174 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200175 }
176 if (what & BSC_FD_WRITE) {
177 LOGP(DINP, LOGL_NOTICE, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200178 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200179 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200180 break;
181 default:
182 break;
183 }
184 return 0;
185}
186
187static void ipa_link_timer_cb(void *data);
188
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200189struct ipa_client_link *
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200190ipa_client_link_create(void *ctx, struct e1inp_ts *ts, const char *driver_name,
191 int priv_nr, const char *addr, uint16_t port,
192 int (*read_cb)(struct ipa_client_link *link,
193 struct msgb *msgb),
194 int (*write_cb)(struct ipa_client_link *link),
195 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200196{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200197 struct ipa_client_link *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200198
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200199 ipa_link = talloc_zero(ctx, struct ipa_client_link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200200 if (!ipa_link)
201 return NULL;
202
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200203 if (ts) {
204 struct e1inp_driver *driver;
205
206 driver = e1inp_driver_find(driver_name);
207 if (driver == NULL) {
208 talloc_free(ipa_link);
209 return NULL;
210 }
211 ts->line->driver = driver;
212 ipa_link->ofd = &ts->driver.ipaccess.fd;
213 } else {
214 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
215 if (ipa_link->ofd == NULL) {
216 talloc_free(ipa_link);
217 return NULL;
218 }
219 }
220
221 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
222 ipa_link->ofd->priv_nr = priv_nr;
223 ipa_link->ofd->cb = ipa_client_fd_cb;
224 ipa_link->ofd->data = ipa_link;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200225 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200226 ipa_link->timer.cb = ipa_link_timer_cb;
227 ipa_link->timer.data = ipa_link;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200228 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200229 ipa_link->port = port;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200230 ipa_link->read_cb = read_cb;
231 ipa_link->write_cb = write_cb;
232 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200233 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200234 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200235
236 return ipa_link;
237}
238
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200239void ipa_client_link_destroy(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200240{
241 talloc_free(link);
242}
243
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200244int ipa_client_link_open(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200245{
246 int ret;
247
248 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200249 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200250 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
251 if (ret < 0) {
252 if (errno != EINPROGRESS)
253 return ret;
254 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200255 link->ofd->fd = ret;
256 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200257 close(ret);
258 return -EIO;
259 }
260 return 0;
261}
262
263static void ipa_link_timer_cb(void *data)
264{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200265 struct ipa_client_link *link = data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200266
267 LOGP(DINP, LOGL_NOTICE, "reconnecting.\n");
268
269 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200270 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200271 ipa_client_link_open(link);
272 break;
273 default:
274 break;
275 }
276}
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200277
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200278void ipa_client_link_send(struct ipa_client_link *link, struct msgb *msg)
279{
280 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200281 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200282}
283
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200284int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
285{
286 int ret;
287 struct sockaddr_in sa;
288 socklen_t sa_len = sizeof(sa);
289 struct ipa_server_link *link = ofd->data;
290
291 ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
292 if (ret < 0) {
293 LOGP(DINP, LOGL_ERROR, "failed to accept from origin "
294 "peer, reason=`%s'\n", strerror(errno));
295 return ret;
296 }
297 LOGP(DINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
298 inet_ntoa(sa.sin_addr), link->port);
299
300 if (link->accept_cb)
301 link->accept_cb(link, ret);
302
303 return 0;
304}
305
306struct ipa_server_link *
307ipa_server_link_create(void *ctx, struct e1inp_line *line,
308 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200309 int (*accept_cb)(struct ipa_server_link *link, int fd),
310 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200311{
312 struct ipa_server_link *ipa_link;
313
314 ipa_link = talloc_zero(ctx, struct ipa_server_link);
315 if (!ipa_link)
316 return NULL;
317
318 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
319 ipa_link->ofd.cb = ipa_server_fd_cb;
320 ipa_link->ofd.data = ipa_link;
321 ipa_link->addr = talloc_strdup(ipa_link, addr);
322 ipa_link->port = port;
323 ipa_link->accept_cb = accept_cb;
324 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200325 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200326
327 return ipa_link;
328
329}
330
331void ipa_server_link_destroy(struct ipa_server_link *link)
332{
333 talloc_free(link);
334}
335
336int ipa_server_link_open(struct ipa_server_link *link)
337{
338 int ret;
339
340 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
341 link->addr, link->port, OSMO_SOCK_F_BIND);
342 if (ret < 0)
343 return ret;
344
345 link->ofd.fd = ret;
346 if (osmo_fd_register(&link->ofd) < 0) {
347 close(ret);
348 return -EIO;
349 }
350 return 0;
351}
352
353void ipa_server_link_close(struct ipa_server_link *link)
354{
355 osmo_fd_unregister(&link->ofd);
356 close(link->ofd.fd);
357}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200358
359static void ipa_server_peer_read(struct ipa_server_peer *peer)
360{
361 struct osmo_fd *ofd = &peer->ofd;
362 struct msgb *msg;
363 int ret;
364
365 LOGP(DINP, LOGL_NOTICE, "message received\n");
366
367 ret = ipa_msg_recv(ofd->fd, &msg);
368 if (ret < 0) {
369 if (errno == EPIPE || errno == ECONNRESET) {
370 LOGP(DINP, LOGL_ERROR, "lost connection with server\n");
371 } else {
372 LOGP(DINP, LOGL_ERROR, "unknown error\n");
373 }
374 return;
375 } else if (ret == 0) {
376 LOGP(DINP, LOGL_ERROR, "connection closed with server\n");
377 ipa_server_peer_destroy(peer);
378 return;
379 }
380 if (peer->cb)
381 peer->cb(peer, msg);
382
383 return;
384}
385
386static void ipa_server_peer_write(struct ipa_server_peer *peer)
387{
388 struct osmo_fd *ofd = &peer->ofd;
389 struct msgb *msg;
390 struct llist_head *lh;
391 int ret;
392
393 LOGP(DINP, LOGL_NOTICE, "sending data\n");
394
395 if (llist_empty(&peer->tx_queue)) {
396 ofd->when &= ~BSC_FD_WRITE;
397 return;
398 }
399 lh = peer->tx_queue.next;
400 llist_del(lh);
401 msg = llist_entry(lh, struct msgb, list);
402
403 ret = send(peer->ofd.fd, msg->data, msg->len, 0);
404 if (ret < 0) {
405 LOGP(DINP, LOGL_ERROR, "error to send\n");
406 }
407 msgb_free(msg);
408}
409
410static int ipa_server_peer_cb(struct osmo_fd *ofd, unsigned int what)
411{
412 struct ipa_server_peer *peer = ofd->data;
413
414 LOGP(DINP, LOGL_NOTICE, "connected read/write\n");
415 if (what & BSC_FD_READ)
416 ipa_server_peer_read(peer);
417 if (what & BSC_FD_WRITE)
418 ipa_server_peer_write(peer);
419
420 return 0;
421}
422
423struct ipa_server_peer *
424ipa_server_peer_create(void *ctx, struct ipa_server_link *link, int fd,
425 int (*cb)(struct ipa_server_peer *peer, struct msgb *msg),
426 void *data)
427{
428 struct ipa_server_peer *peer;
429
430 peer = talloc_zero(ctx, struct ipa_server_peer);
431 if (peer == NULL) {
432 LOGP(DINP, LOGL_ERROR, "cannot allocate new peer in server, "
433 "reason=`%s'\n", strerror(errno));
434 return NULL;
435 }
436 peer->server = link;
437 peer->ofd.fd = fd;
438 peer->ofd.data = peer;
439 peer->ofd.cb = ipa_server_peer_cb;
440 peer->ofd.when = BSC_FD_READ;
441 peer->cb = cb;
442 peer->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200443 INIT_LLIST_HEAD(&peer->tx_queue);
444
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200445 if (osmo_fd_register(&peer->ofd) < 0) {
446 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
447 talloc_free(peer);
448 return NULL;
449 }
450 return peer;
451}
452
453void ipa_server_peer_destroy(struct ipa_server_peer *peer)
454{
455 close(peer->ofd.fd);
456 osmo_fd_unregister(&peer->ofd);
457 talloc_free(peer);
458}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200459
460void ipa_server_peer_send(struct ipa_server_peer *peer, struct msgb *msg)
461{
462 msgb_enqueue(&peer->tx_queue, msg);
463 peer->ofd.when |= BSC_FD_WRITE;
464}