blob: 0cd254097763a40bb1c886f5396c45d953dc9cdb [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{
90 osmo_fd_unregister(&link->ofd);
91 close(link->ofd.fd);
92}
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{
96 struct osmo_fd *ofd = &link->ofd;
97 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 Ayuso591ddad2011-06-21 18:16:42 +0200116 if (link->cb)
117 link->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{
122 struct osmo_fd *ofd = &link->ofd;
123 struct msgb *msg;
124 struct llist_head *lh;
125 int ret;
126
127 LOGP(DINP, LOGL_NOTICE, "sending data\n");
128
129 if (llist_empty(&link->tx_queue)) {
130 ofd->when &= ~BSC_FD_WRITE;
131 return;
132 }
133 lh = link->tx_queue.next;
134 llist_del(lh);
135 msg = llist_entry(lh, struct msgb, list);
136
137 ret = send(link->ofd.fd, msg->data, msg->len, 0);
138 if (ret < 0) {
139 if (errno == EPIPE || errno == ENOTCONN) {
140 ipa_client_retry(link);
141 }
142 LOGP(DINP, LOGL_ERROR, "error to send\n");
143 }
144 msgb_free(msg);
145}
146
147int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
148{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200149 struct ipa_client_link *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200150 int error, ret;
151 size_t len = sizeof(error);
152
153 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200154 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200155 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
156 if (ret >= 0 && error > 0) {
157 ipa_client_retry(link);
158 return 0;
159 }
160 ofd->when &= ~BSC_FD_WRITE;
161 LOGP(DINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200162 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200163 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200164 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200165 LOGP(DINP, LOGL_NOTICE, "connected read/write\n");
166 if (what & BSC_FD_READ)
167 ipa_client_read(link);
168 if (what & BSC_FD_WRITE)
169 ipa_client_write(link);
170 break;
171 default:
172 break;
173 }
174 return 0;
175}
176
177static void ipa_link_timer_cb(void *data);
178
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200179struct ipa_client_link *
Pablo Neira Ayuso591ddad2011-06-21 18:16:42 +0200180ipa_client_link_create(void *ctx, struct e1inp_line *line,
181 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200182 int (*cb)(struct ipa_client_link *link,
183 struct msgb *msgb), void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200184{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200185 struct ipa_client_link *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200186
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200187 ipa_link = talloc_zero(ctx, struct ipa_client_link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200188 if (!ipa_link)
189 return NULL;
190
191 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
192 ipa_link->ofd.cb = ipa_client_fd_cb;
193 ipa_link->ofd.data = ipa_link;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200194 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200195 ipa_link->timer.cb = ipa_link_timer_cb;
196 ipa_link->timer.data = ipa_link;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200197 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200198 ipa_link->port = port;
Pablo Neira Ayuso591ddad2011-06-21 18:16:42 +0200199 ipa_link->cb = cb;
200 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200201 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200202 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200203
204 return ipa_link;
205}
206
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200207void ipa_client_link_destroy(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200208{
209 talloc_free(link);
210}
211
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200212int ipa_client_link_open(struct ipa_client_link *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200213{
214 int ret;
215
216 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200217 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200218 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
219 if (ret < 0) {
220 if (errno != EINPROGRESS)
221 return ret;
222 }
223 link->ofd.fd = ret;
224 if (osmo_fd_register(&link->ofd) < 0) {
225 close(ret);
226 return -EIO;
227 }
228 return 0;
229}
230
231static void ipa_link_timer_cb(void *data)
232{
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200233 struct ipa_client_link *link = data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200234
235 LOGP(DINP, LOGL_NOTICE, "reconnecting.\n");
236
237 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200238 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200239 ipa_client_link_open(link);
240 break;
241 default:
242 break;
243 }
244}
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200245
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200246void ipa_client_link_send(struct ipa_client_link *link, struct msgb *msg)
247{
248 msgb_enqueue(&link->tx_queue, msg);
249 link->ofd.when |= BSC_FD_WRITE;
250}
251
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200252int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
253{
254 int ret;
255 struct sockaddr_in sa;
256 socklen_t sa_len = sizeof(sa);
257 struct ipa_server_link *link = ofd->data;
258
259 ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
260 if (ret < 0) {
261 LOGP(DINP, LOGL_ERROR, "failed to accept from origin "
262 "peer, reason=`%s'\n", strerror(errno));
263 return ret;
264 }
265 LOGP(DINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
266 inet_ntoa(sa.sin_addr), link->port);
267
268 if (link->accept_cb)
269 link->accept_cb(link, ret);
270
271 return 0;
272}
273
274struct ipa_server_link *
275ipa_server_link_create(void *ctx, struct e1inp_line *line,
276 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200277 int (*accept_cb)(struct ipa_server_link *link, int fd),
278 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200279{
280 struct ipa_server_link *ipa_link;
281
282 ipa_link = talloc_zero(ctx, struct ipa_server_link);
283 if (!ipa_link)
284 return NULL;
285
286 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
287 ipa_link->ofd.cb = ipa_server_fd_cb;
288 ipa_link->ofd.data = ipa_link;
289 ipa_link->addr = talloc_strdup(ipa_link, addr);
290 ipa_link->port = port;
291 ipa_link->accept_cb = accept_cb;
292 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200293 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200294
295 return ipa_link;
296
297}
298
299void ipa_server_link_destroy(struct ipa_server_link *link)
300{
301 talloc_free(link);
302}
303
304int ipa_server_link_open(struct ipa_server_link *link)
305{
306 int ret;
307
308 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
309 link->addr, link->port, OSMO_SOCK_F_BIND);
310 if (ret < 0)
311 return ret;
312
313 link->ofd.fd = ret;
314 if (osmo_fd_register(&link->ofd) < 0) {
315 close(ret);
316 return -EIO;
317 }
318 return 0;
319}
320
321void ipa_server_link_close(struct ipa_server_link *link)
322{
323 osmo_fd_unregister(&link->ofd);
324 close(link->ofd.fd);
325}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200326
327static void ipa_server_peer_read(struct ipa_server_peer *peer)
328{
329 struct osmo_fd *ofd = &peer->ofd;
330 struct msgb *msg;
331 int ret;
332
333 LOGP(DINP, LOGL_NOTICE, "message received\n");
334
335 ret = ipa_msg_recv(ofd->fd, &msg);
336 if (ret < 0) {
337 if (errno == EPIPE || errno == ECONNRESET) {
338 LOGP(DINP, LOGL_ERROR, "lost connection with server\n");
339 } else {
340 LOGP(DINP, LOGL_ERROR, "unknown error\n");
341 }
342 return;
343 } else if (ret == 0) {
344 LOGP(DINP, LOGL_ERROR, "connection closed with server\n");
345 ipa_server_peer_destroy(peer);
346 return;
347 }
348 if (peer->cb)
349 peer->cb(peer, msg);
350
351 return;
352}
353
354static void ipa_server_peer_write(struct ipa_server_peer *peer)
355{
356 struct osmo_fd *ofd = &peer->ofd;
357 struct msgb *msg;
358 struct llist_head *lh;
359 int ret;
360
361 LOGP(DINP, LOGL_NOTICE, "sending data\n");
362
363 if (llist_empty(&peer->tx_queue)) {
364 ofd->when &= ~BSC_FD_WRITE;
365 return;
366 }
367 lh = peer->tx_queue.next;
368 llist_del(lh);
369 msg = llist_entry(lh, struct msgb, list);
370
371 ret = send(peer->ofd.fd, msg->data, msg->len, 0);
372 if (ret < 0) {
373 LOGP(DINP, LOGL_ERROR, "error to send\n");
374 }
375 msgb_free(msg);
376}
377
378static int ipa_server_peer_cb(struct osmo_fd *ofd, unsigned int what)
379{
380 struct ipa_server_peer *peer = ofd->data;
381
382 LOGP(DINP, LOGL_NOTICE, "connected read/write\n");
383 if (what & BSC_FD_READ)
384 ipa_server_peer_read(peer);
385 if (what & BSC_FD_WRITE)
386 ipa_server_peer_write(peer);
387
388 return 0;
389}
390
391struct ipa_server_peer *
392ipa_server_peer_create(void *ctx, struct ipa_server_link *link, int fd,
393 int (*cb)(struct ipa_server_peer *peer, struct msgb *msg),
394 void *data)
395{
396 struct ipa_server_peer *peer;
397
398 peer = talloc_zero(ctx, struct ipa_server_peer);
399 if (peer == NULL) {
400 LOGP(DINP, LOGL_ERROR, "cannot allocate new peer in server, "
401 "reason=`%s'\n", strerror(errno));
402 return NULL;
403 }
404 peer->server = link;
405 peer->ofd.fd = fd;
406 peer->ofd.data = peer;
407 peer->ofd.cb = ipa_server_peer_cb;
408 peer->ofd.when = BSC_FD_READ;
409 peer->cb = cb;
410 peer->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200411 INIT_LLIST_HEAD(&peer->tx_queue);
412
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200413 if (osmo_fd_register(&peer->ofd) < 0) {
414 LOGP(DINP, LOGL_ERROR, "could not register FD\n");
415 talloc_free(peer);
416 return NULL;
417 }
418 return peer;
419}
420
421void ipa_server_peer_destroy(struct ipa_server_peer *peer)
422{
423 close(peer->ofd.fd);
424 osmo_fd_unregister(&peer->ofd);
425 talloc_free(peer);
426}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200427
428void ipa_server_peer_send(struct ipa_server_peer *peer, struct msgb *msg)
429{
430 msgb_enqueue(&peer->tx_queue, msg);
431 peer->ofd.when |= BSC_FD_WRITE;
432}