blob: 60f3216cdad7be2a45779f38721249e84eec957f [file] [log] [blame]
Holger Hans Peter Freyther77288202011-05-31 21:19:22 +02001/*
2 * osmo-pcap-client code
3 *
4 * (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (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>
28#include <osmocom/core/select.h>
29#include <osmocom/core/socket.h>
30
31#include <arpa/inet.h>
32
33#include <sys/types.h>
34#include <sys/socket.h>
35
36#include <limits.h>
37#include <string.h>
38#include <unistd.h>
39
40static void _osmo_client_connect(void *_data)
41{
42 osmo_client_connect((struct osmo_pcap_client *) _data);
43}
44
45static void lost_connection(struct osmo_pcap_client *client)
46{
47 if (client->wqueue.bfd.fd >= 0) {
48 osmo_fd_unregister(&client->wqueue.bfd);
49 close(client->wqueue.bfd.fd);
50 client->wqueue.bfd.fd = -1;
51 }
52
53
54 client->timer.cb = _osmo_client_connect;
55 client->timer.data = client;
56 osmo_timer_schedule(&client->timer, 2, 0);
57}
58
59static void write_data(struct osmo_pcap_client *client, struct msgb *msg)
60{
61 if (osmo_wqueue_enqueue(&client->wqueue, msg) != 0) {
62 LOGP(DCLIENT, LOGL_ERROR, "Failed to enqueue.\n");
63 msgb_free(msg);
64 return;
65 }
66}
67
68static int read_cb(struct osmo_fd *fd)
69{
70 char buf[4096];
71 int rc;
72
73 rc = read(fd->fd, buf, sizeof(buf));
74 if (rc <= 0) {
75 struct osmo_pcap_client *client = fd->data;
76 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on read.\n");
77 lost_connection(client);
78 return -1;
79 }
80
81 return 0;
82}
83
84static int write_cb(struct osmo_fd *fd, struct msgb *msg)
85{
86 int rc;
87
88 rc = write(fd->fd, msg->data, msg->len);
89 if (rc < 0) {
90 struct osmo_pcap_client *client = fd->data;
91 LOGP(DCLIENT, LOGL_ERROR, "Lost connection on write.\n");
92 lost_connection(client);
93 return -1;
94 }
95
96 return 0;
97}
98
99void osmo_client_send_data(struct osmo_pcap_client *client,
100 struct pcap_pkthdr *in_hdr, const uint8_t *data)
101{
102 struct osmo_pcap_data *om_hdr;
103 struct pcap_pkthdr *hdr;
104 struct msgb *msg;
105
106 msg = msgb_alloc(4096, "data-data");
107 if (!msg) {
108 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate.\n");
109 return;
110 }
111
112 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
113 om_hdr->type = PKT_LINK_DATA;
114
115 msg->l2h = msgb_put(msg, sizeof(*hdr));
116 hdr = (struct pcap_pkthdr *) msg->l2h;
117 *hdr = *in_hdr;
118
119 msg->l3h = msgb_put(msg, in_hdr->caplen);
120 memcpy(msg->l3h, data, in_hdr->caplen);
121
122 om_hdr->len = msgb_l2len(msg);
123
124 write_data(client, msg);
125}
126
127void osmo_client_send_link(struct osmo_pcap_client *client)
128{
129 struct pcap_file_header *hdr;
130 struct osmo_pcap_data *om_hdr;
131
132 struct msgb *msg = msgb_alloc(4096, "link-data");
133 if (!msg) {
134 LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
135 return;
136 }
137
138
139 om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
140 om_hdr->type = PKT_LINK_HDR;
141 om_hdr->len = sizeof(*hdr);
142
143 hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
144 hdr->magic = 0xa1b2c3d4;
145 hdr->version_major = 2;
146 hdr->version_minor = 4;
147 hdr->thiszone = 0;
148 hdr->sigfigs = 0;
149 hdr->snaplen = UINT_MAX;
150 hdr->linktype = pcap_datalink(client->handle);
151
152 write_data(client, msg);
153}
154
155void osmo_client_connect(struct osmo_pcap_client *client)
156{
157 int fd;
158
159 client->wqueue.read_cb = read_cb;
160 client->wqueue.write_cb = write_cb;
161 client->wqueue.bfd.when = BSC_FD_READ;
162 client->wqueue.bfd.data = client;
163 osmo_wqueue_clear(&client->wqueue);
164
165 fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
166 client->srv_ip, client->srv_port, 0);
167 if (fd < 0) {
168 LOGP(DCLIENT, LOGL_ERROR,
169 "Failed to connect to %s:%d\n",
170 client->srv_ip, client->srv_port);
171 lost_connection(client);
172 return;
173 }
174
175 client->wqueue.bfd.fd = fd;
176 if (osmo_fd_register(&client->wqueue.bfd) != 0) {
177 LOGP(DCLIENT, LOGL_ERROR,
178 "Failed to register to BFD.\n");
179 lost_connection(client);
180 return;
181 }
182
183 osmo_client_send_link(client);
184}