blob: 2400f3a992a8cce0bdd3817d3a9c51195e01ece4 [file] [log] [blame]
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +02001/*
2 * osmo-pcap-client code
3 *
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +02004 * (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +02005 * (C) 2011 by On-Waves
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <osmo-pcap/osmo_pcap_client.h>
24#include <osmo-pcap/common.h>
25#include <osmo-pcap/wireformat.h>
26
27#include <osmocom/core/msgb.h>
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +020028#include <osmocom/core/rate_ctr.h>
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +020029#include <osmocom/core/select.h>
30#include <osmocom/core/socket.h>
31
32#include <arpa/inet.h>
Holger Hans Peter Freytherddc698f2016-04-24 11:09:13 +020033#include <netinet/in.h>
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +020034
35#include <sys/types.h>
36#include <sys/socket.h>
37
38#include <limits.h>
39#include <string.h>
40#include <unistd.h>
41
42static void _osmo_client_connect(void *_data)
43{
44 osmo_client_connect((struct osmo_pcap_client *) _data);
45}
46
47static void lost_connection(struct osmo_pcap_client *client)
48{
49 if (client->wqueue.bfd.fd >= 0) {
50 osmo_fd_unregister(&client->wqueue.bfd);
51 close(client->wqueue.bfd.fd);
52 client->wqueue.bfd.fd = -1;
53 }
54
55
56 client->timer.cb = _osmo_client_connect;
57 client->timer.data = client;
58 osmo_timer_schedule(&client->timer, 2, 0);
59}
60
61static void write_data(struct osmo_pcap_client *client, struct msgb *msg)
62{
63 if (osmo_wqueue_enqueue(&client->wqueue, msg) != 0) {
64 LOGP(DCLIENT, LOGL_ERROR, "Failed to enqueue.\n");
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +020065 rate_ctr_inc(&client->ctrg->ctr[CLIENT_CTR_QERR]);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +020066 msgb_free(msg);
67 return;
68 }
69}
70
71static int read_cb(struct osmo_fd *fd)
72{
73 char buf[4096];
74 int rc;
75
76 rc = read(fd->fd, buf, sizeof(buf));
77 if (rc <= 0) {
78 struct osmo_pcap_client *client = fd->data;
79 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on read.\n");
80 lost_connection(client);
81 return -1;
82 }
83
84 return 0;
85}
86
87static int write_cb(struct osmo_fd *fd, struct msgb *msg)
88{
89 int rc;
90
91 rc = write(fd->fd, msg->data, msg->len);
92 if (rc < 0) {
93 struct osmo_pcap_client *client = fd->data;
94 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on write.\n");
Holger Hans Peter Freytherc3455dc2016-08-19 17:31:01 +020095 rate_ctr_inc(&client->ctrg->ctr[CLIENT_CTR_WERR]);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +020096 lost_connection(client);
97 return -1;
98 }
99
100 return 0;
101}
102
103void osmo_client_send_data(struct osmo_pcap_client *client,
104 struct pcap_pkthdr *in_hdr, const uint8_t *data)
105{
106 struct osmo_pcap_data *om_hdr;
Holger Hans Peter Freyther66b80cc2015-12-03 22:13:38 +0100107 struct osmo_pcap_pkthdr *hdr;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200108 struct msgb *msg;
109
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100110 if (in_hdr->caplen > 9000) {
111 LOGP(DCLIENT, LOGL_ERROR,
112 "Capture len too big %zu\n", in_hdr->caplen);
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +0200113 rate_ctr_inc(&client->ctrg->ctr[CLIENT_CTR_2BIG]);
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100114 return;
115 }
116
117 msg = msgb_alloc(9000 + sizeof(*om_hdr) + sizeof(*hdr), "data-data");
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200118 if (!msg) {
119 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate.\n");
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +0200120 rate_ctr_inc(&client->ctrg->ctr[CLIENT_CTR_NOMEM]);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200121 return;
122 }
123
124 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
125 om_hdr->type = PKT_LINK_DATA;
126
127 msg->l2h = msgb_put(msg, sizeof(*hdr));
Holger Hans Peter Freyther66b80cc2015-12-03 22:13:38 +0100128 hdr = (struct osmo_pcap_pkthdr *) msg->l2h;
129 hdr->ts_sec = in_hdr->ts.tv_sec;
130 hdr->ts_usec = in_hdr->ts.tv_usec;
131 hdr->caplen = in_hdr->caplen;
132 hdr->len = in_hdr->len;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200133
134 msg->l3h = msgb_put(msg, in_hdr->caplen);
135 memcpy(msg->l3h, data, in_hdr->caplen);
136
Holger Hans Peter Freyther9df7dc52011-06-01 17:29:15 +0200137 om_hdr->len = htons(msgb_l2len(msg));
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +0200138 rate_ctr_add(&client->ctrg->ctr[CLIENT_CTR_BYTES], hdr->caplen);
139 rate_ctr_inc(&client->ctrg->ctr[CLIENT_CTR_PKTS]);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200140
141 write_data(client, msg);
142}
143
144void osmo_client_send_link(struct osmo_pcap_client *client)
145{
146 struct pcap_file_header *hdr;
147 struct osmo_pcap_data *om_hdr;
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100148 struct msgb *msg;
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200149
Holger Hans Peter Freyther42421c42015-12-03 20:16:37 +0100150 msg = msgb_alloc(9000 + sizeof(*om_hdr) + sizeof(*hdr), "link-data");
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200151 if (!msg) {
152 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
153 return;
154 }
155
156
157 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
158 om_hdr->type = PKT_LINK_HDR;
Holger Hans Peter Freyther9df7dc52011-06-01 17:29:15 +0200159 om_hdr->len = htons(sizeof(*hdr));
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200160
161 hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
162 hdr->magic = 0xa1b2c3d4;
163 hdr->version_major = 2;
164 hdr->version_minor = 4;
165 hdr->thiszone = 0;
166 hdr->sigfigs = 0;
167 hdr->snaplen = UINT_MAX;
168 hdr->linktype = pcap_datalink(client->handle);
169
170 write_data(client, msg);
171}
172
173void osmo_client_connect(struct osmo_pcap_client *client)
174{
175 int fd;
176
177 client->wqueue.read_cb = read_cb;
178 client->wqueue.write_cb = write_cb;
179 client->wqueue.bfd.when = BSC_FD_READ;
180 client->wqueue.bfd.data = client;
181 osmo_wqueue_clear(&client->wqueue);
182
183 fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Daniel Willmannb0003682011-07-17 17:48:19 +0200184 client->srv_ip, client->srv_port, OSMO_SOCK_F_CONNECT);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200185 if (fd < 0) {
186 LOGP(DCLIENT, LOGL_ERROR,
187 "Failed to connect to %s:%d\n",
188 client->srv_ip, client->srv_port);
189 lost_connection(client);
190 return;
191 }
192
193 client->wqueue.bfd.fd = fd;
194 if (osmo_fd_register(&client->wqueue.bfd) != 0) {
195 LOGP(DCLIENT, LOGL_ERROR,
196 "Failed to register to BFD.\n");
197 lost_connection(client);
198 return;
199 }
200
Holger Hans Peter Freytherf4164632016-08-18 18:39:53 +0200201 rate_ctr_inc(&client->ctrg->ctr[CLIENT_CTR_CONNECT]);
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +0200202 osmo_client_send_link(client);
203}