blob: c65a0ecd82ea94d9251925d84e10e2c1f518e379 [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>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020022
23#include <osmocom/abis/ipa.h>
24
25#define IPA_ALLOC_SIZE 1200
26
27static struct msgb *ipa_msg_alloc(void)
28{
29 return msgb_alloc(IPA_ALLOC_SIZE, "Abis/IP");
30}
31
32int ipa_msg_recv(int fd, struct msgb **rmsg)
33{
34 struct msgb *msg;
35 struct ipaccess_head *hh;
36 int len, ret;
37
38 msg = ipa_msg_alloc();
39 if (msg == NULL)
40 return -ENOMEM;
41
42 /* first read our 3-byte header */
43 hh = (struct ipaccess_head *) msg->data;
44 ret = recv(fd, msg->data, sizeof(*hh), 0);
45 if (ret <= 0) {
46 msgb_free(msg);
47 return ret;
48 } else if (ret != sizeof(*hh)) {
49 msgb_free(msg);
50 return -EIO;
51 }
52 msgb_put(msg, ret);
53
54 /* then read the length as specified in header */
55 msg->l2h = msg->data + sizeof(*hh);
56 len = ntohs(hh->len);
57
58 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
59 msgb_free(msg);
60 return -EIO;
61 }
62
63 ret = recv(fd, msg->l2h, len, 0);
64 if (ret <= 0) {
65 msgb_free(msg);
66 return ret;
67 } else if (ret < len) {
68 msgb_free(msg);
69 return -EIO;
70 }
71 msgb_put(msg, ret);
72 *rmsg = msg;
73 return ret;
74}
75
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020076void ipa_client_link_close(struct ipa_client_link *link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020077
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020078static void ipa_client_retry(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020079{
80 LOGP(DINP, LOGL_NOTICE, "connection closed\n");
81 ipa_client_link_close(link);
82 LOGP(DINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
83 osmo_timer_schedule(&link->timer, 5, 0);
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020084 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020085}
86
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020087void ipa_client_link_close(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020088{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020089 osmo_fd_unregister(link->ofd);
90 close(link->ofd->fd);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020091}
92
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +020093static void ipa_client_read(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020094{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020095 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020096 struct msgb *msg;
97 int ret;
98
99 LOGP(DINP, LOGL_NOTICE, "message received\n");
100
101 ret = ipa_msg_recv(ofd->fd, &msg);
102 if (ret < 0) {
103 if (errno == EPIPE || errno == ECONNRESET) {
104 LOGP(DINP, LOGL_ERROR, "lost connection with server\n");
105 } else {
106 LOGP(DINP, LOGL_ERROR, "unknown error\n");
107 }
108 ipa_client_retry(link);
109 return;
110 } else if (ret == 0) {
111 LOGP(DINP, LOGL_ERROR, "connection closed with server\n");
112 ipa_client_retry(link);
113 return;
114 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200115 if (link->read_cb)
116 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200117}
118
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200119static void ipa_client_write(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200120{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200121 if (link->write_cb)
122 link->write_cb(link);
123}
124
125int ipa_client_write_default_cb(struct ipa_client_link *link)
126{
127 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200128 struct msgb *msg;
129 struct llist_head *lh;
130 int ret;
131
132 LOGP(DINP, LOGL_NOTICE, "sending data\n");
133
134 if (llist_empty(&link->tx_queue)) {
135 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200136 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200137 }
138 lh = link->tx_queue.next;
139 llist_del(lh);
140 msg = llist_entry(lh, struct msgb, list);
141
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200142 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200143 if (ret < 0) {
144 if (errno == EPIPE || errno == ENOTCONN) {
145 ipa_client_retry(link);
146 }
147 LOGP(DINP, LOGL_ERROR, "error to send\n");
148 }
149 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200150 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200151}
152
153int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
154{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200155 struct ipa_client_link *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200156 int error, ret;
157 size_t len = sizeof(error);
158
159 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200160 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200161 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
162 if (ret >= 0 && error > 0) {
163 ipa_client_retry(link);
164 return 0;
165 }
166 ofd->when &= ~BSC_FD_WRITE;
167 LOGP(DINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200168 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200169 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200170 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200171 if (what & BSC_FD_READ) {
172 LOGP(DINP, LOGL_NOTICE, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200173 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200174 }
175 if (what & BSC_FD_WRITE) {
176 LOGP(DINP, LOGL_NOTICE, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200177 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200178 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200179 break;
180 default:
181 break;
182 }
183 return 0;
184}
185
186static void ipa_link_timer_cb(void *data);
187
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200188struct ipa_client_link *
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200189ipa_client_link_create(void *ctx, struct e1inp_ts *ts, const char *driver_name,
190 int priv_nr, const char *addr, uint16_t port,
191 int (*read_cb)(struct ipa_client_link *link,
192 struct msgb *msgb),
193 int (*write_cb)(struct ipa_client_link *link),
194 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200195{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200196 struct ipa_client_link *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200197
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200198 ipa_link = talloc_zero(ctx, struct ipa_client_link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200199 if (!ipa_link)
200 return NULL;
201
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200202 if (ts) {
203 struct e1inp_driver *driver;
204
205 driver = e1inp_driver_find(driver_name);
206 if (driver == NULL) {
207 talloc_free(ipa_link);
208 return NULL;
209 }
210 ts->line->driver = driver;
211 ipa_link->ofd = &ts->driver.ipaccess.fd;
212 } else {
213 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
214 if (ipa_link->ofd == NULL) {
215 talloc_free(ipa_link);
216 return NULL;
217 }
218 }
219
220 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
221 ipa_link->ofd->priv_nr = priv_nr;
222 ipa_link->ofd->cb = ipa_client_fd_cb;
223 ipa_link->ofd->data = ipa_link;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200224 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200225 ipa_link->timer.cb = ipa_link_timer_cb;
226 ipa_link->timer.data = ipa_link;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200227 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200228 ipa_link->port = port;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200229 ipa_link->read_cb = read_cb;
230 ipa_link->write_cb = write_cb;
231 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200232 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200233 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200234
235 return ipa_link;
236}
237
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200238void ipa_client_link_destroy(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200239{
240 talloc_free(link);
241}
242
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200243int ipa_client_link_open(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200244{
245 int ret;
246
247 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200248 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200249 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
250 if (ret < 0) {
251 if (errno != EINPROGRESS)
252 return ret;
253 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200254 link->ofd->fd = ret;
255 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200256 close(ret);
257 return -EIO;
258 }
259 return 0;
260}
261
262static void ipa_link_timer_cb(void *data)
263{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200264 struct ipa_client_link *link = data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200265
266 LOGP(DINP, LOGL_NOTICE, "reconnecting.\n");
267
268 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200269 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200270 ipa_client_link_open(link);
271 break;
272 default:
273 break;
274 }
275}
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200276
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200277void ipa_client_link_send(struct ipa_client_link *link, struct msgb *msg)
278{
279 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200280 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200281}
282
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200283int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
284{
285 int ret;
286 struct sockaddr_in sa;
287 socklen_t sa_len = sizeof(sa);
288 struct ipa_server_link *link = ofd->data;
289
290 ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
291 if (ret < 0) {
292 LOGP(DINP, LOGL_ERROR, "failed to accept from origin "
293 "peer, reason=`%s'\n", strerror(errno));
294 return ret;
295 }
296 LOGP(DINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
297 inet_ntoa(sa.sin_addr), link->port);
298
299 if (link->accept_cb)
300 link->accept_cb(link, ret);
301
302 return 0;
303}
304
305struct ipa_server_link *
306ipa_server_link_create(void *ctx, struct e1inp_line *line,
307 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200308 int (*accept_cb)(struct ipa_server_link *link, int fd),
309 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200310{
311 struct ipa_server_link *ipa_link;
312
313 ipa_link = talloc_zero(ctx, struct ipa_server_link);
314 if (!ipa_link)
315 return NULL;
316
317 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
318 ipa_link->ofd.cb = ipa_server_fd_cb;
319 ipa_link->ofd.data = ipa_link;
320 ipa_link->addr = talloc_strdup(ipa_link, addr);
321 ipa_link->port = port;
322 ipa_link->accept_cb = accept_cb;
323 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200324 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200325
326 return ipa_link;
327
328}
329
330void ipa_server_link_destroy(struct ipa_server_link *link)
331{
332 talloc_free(link);
333}
334
335int ipa_server_link_open(struct ipa_server_link *link)
336{
337 int ret;
338
339 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
340 link->addr, link->port, OSMO_SOCK_F_BIND);
341 if (ret < 0)
342 return ret;
343
344 link->ofd.fd = ret;
345 if (osmo_fd_register(&link->ofd) < 0) {
346 close(ret);
347 return -EIO;
348 }
349 return 0;
350}
351
352void ipa_server_link_close(struct ipa_server_link *link)
353{
354 osmo_fd_unregister(&link->ofd);
355 close(link->ofd.fd);
356}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200357
358static void ipa_server_peer_read(struct ipa_server_peer *peer)
359{
360 struct osmo_fd *ofd = &peer->ofd;
361 struct msgb *msg;
362 int ret;
363
364 LOGP(DINP, LOGL_NOTICE, "message received\n");
365
366 ret = ipa_msg_recv(ofd->fd, &msg);
367 if (ret < 0) {
368 if (errno == EPIPE || errno == ECONNRESET) {
369 LOGP(DINP, LOGL_ERROR, "lost connection with server\n");
370 } else {
371 LOGP(DINP, LOGL_ERROR, "unknown error\n");
372 }
373 return;
374 } else if (ret == 0) {
375 LOGP(DINP, LOGL_ERROR, "connection closed with server\n");
376 ipa_server_peer_destroy(peer);
377 return;
378 }
379 if (peer->cb)
380 peer->cb(peer, msg);
381
382 return;
383}
384
385static void ipa_server_peer_write(struct ipa_server_peer *peer)
386{
387 struct osmo_fd *ofd = &peer->ofd;
388 struct msgb *msg;
389 struct llist_head *lh;
390 int ret;
391
392 LOGP(DINP, LOGL_NOTICE, "sending data\n");
393
394 if (llist_empty(&peer->tx_queue)) {
395 ofd->when &= ~BSC_FD_WRITE;
396 return;
397 }
398 lh = peer->tx_queue.next;
399 llist_del(lh);
400 msg = llist_entry(lh, struct msgb, list);
401
402 ret = send(peer->ofd.fd, msg->data, msg->len, 0);
403 if (ret < 0) {
404 LOGP(DINP, LOGL_ERROR, "error to send\n");
405 }
406 msgb_free(msg);
407}
408
409static int ipa_server_peer_cb(struct osmo_fd *ofd, unsigned int what)
410{
411 struct ipa_server_peer *peer = ofd->data;
412
413 LOGP(DINP, LOGL_NOTICE, "connected read/write\n");
414 if (what & BSC_FD_READ)
415 ipa_server_peer_read(peer);
416 if (what & BSC_FD_WRITE)
417 ipa_server_peer_write(peer);
418
419 return 0;
420}
421
422struct ipa_server_peer *
423ipa_server_peer_create(void *ctx, struct ipa_server_link *link, int fd,
424 int (*cb)(struct ipa_server_peer *peer, struct msgb *msg),
425 void *data)
426{
427 struct ipa_server_peer *peer;
428
429 peer = talloc_zero(ctx, struct ipa_server_peer);
430 if (peer == NULL) {
431 LOGP(DINP, LOGL_ERROR, "cannot allocate new peer in server, "
432 "reason=`%s'\n", strerror(errno));
433 return NULL;
434 }
435 peer->server = link;
436 peer->ofd.fd = fd;
437 peer->ofd.data = peer;
438 peer->ofd.cb = ipa_server_peer_cb;
439 peer->ofd.when = BSC_FD_READ;
440 peer->cb = cb;
441 peer->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200442 INIT_LLIST_HEAD(&peer->tx_queue);
443
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200444 if (osmo_fd_register(&peer->ofd) < 0) {
445 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
446 talloc_free(peer);
447 return NULL;
448 }
449 return peer;
450}
451
452void ipa_server_peer_destroy(struct ipa_server_peer *peer)
453{
454 close(peer->ofd.fd);
455 osmo_fd_unregister(&peer->ofd);
456 talloc_free(peer);
457}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200458
459void ipa_server_peer_send(struct ipa_server_peer *peer, struct msgb *msg)
460{
461 msgb_enqueue(&peer->tx_queue, msg);
462 peer->ofd.when |= BSC_FD_WRITE;
463}