blob: 1b7addcb2277d83590e2cbd33269f63ffdc6ce76 [file] [log] [blame]
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +02001/*
2 * osmo-pcap-server code
3 *
Holger Hans Peter Freyther6413e762016-08-26 15:24:40 +02004 * (C) 2011-2016 by Holger Hans Peter Freyther <holger@moiji-mobile.com>
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +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_server.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020024#include <osmo-pcap/common.h>
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +020025#include <osmo-pcap/wireformat.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020026
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020027#include <osmocom/core/socket.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020028#include <osmocom/core/talloc.h>
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +020029#include <osmocom/core/rate_ctr.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020030
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020031#include <arpa/inet.h>
32#include <sys/socket.h>
33#include <sys/types.h>
34
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +020035#include <zmq.h>
36
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +020037#include <fcntl.h>
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020038#include <errno.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020039#include <string.h>
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020040#include <unistd.h>
41
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +020042static void pcap_zmq_send(void *publ, const void *data, size_t len, int flags)
43{
44 int rc;
45 zmq_msg_t msg;
46
47 rc = zmq_msg_init_size(&msg, len);
48 if (rc != 0) {
49 /* sigh.. we said SNDMORE but can't... */
50 LOGP(DSERVER, LOGL_ERROR, "Failed to init rc=%d errno=%d/%s\n",
51 rc, errno, strerror(errno));
52 return;
53 }
54 memcpy(zmq_msg_data(&msg), data, len);
55 rc = zmq_msg_send(&msg, publ, flags);
56 if (rc == -1) {
57 /* is the zmq_msg now owned? leak??? */
58 LOGP(DSERVER, LOGL_ERROR, "Failed to send data rc=%d errno=%d/%s\n",
59 rc, errno, strerror(errno));
60 return;
61 }
62}
63
64static void client_event(struct osmo_pcap_conn *conn,
65 const char *event, const char *data)
66{
67 char *event_name;
68
69 if (!conn->server->zmq_publ)
70 return;
71
72 /*
73 * This multi-part support is insane... so if we lose the first
74 * or the last part of the multipart message stuff is going out
75 * of sync. *great* As we can't do anything about it right now
76 * just close the eyese and send it.
77 */
78 event_name = talloc_asprintf(conn, "event.v1.%s.%s",
79 event, conn->name);
80 pcap_zmq_send(conn->server->zmq_publ,
81 event_name, strlen(event_name),
82 data ? ZMQ_SNDMORE : 0);
83 talloc_free(event_name);
84 if (data)
85 pcap_zmq_send(conn->server->zmq_publ, data, strlen(data), 0);
86}
87
88static void client_data(struct osmo_pcap_conn *conn,
89 struct osmo_pcap_data *data)
90{
91 char *event_name;
92
93 if (!conn->server->zmq_publ)
94 return;
95
96 /*
97 * This multi-part support is insane... so if we lose the first
98 * or the last part of the multipart message stuff is going out
99 * of sync. *great* As we can't do anything about it right now
100 * just close the eyese and send it.
101 */
102 event_name = talloc_asprintf(conn, "data.v1.%s", conn->name);
103 pcap_zmq_send(conn->server->zmq_publ, event_name, strlen(event_name), ZMQ_SNDMORE);
104 talloc_free(event_name);
105
106 pcap_zmq_send(conn->server->zmq_publ,
107 &conn->file_hdr, sizeof(conn->file_hdr),
108 ZMQ_SNDMORE);
109 pcap_zmq_send(conn->server->zmq_publ,
110 &data->data[0], data->len,
111 0);
112}
113
114void osmo_pcap_server_close_trace(struct osmo_pcap_conn *conn)
115{
116 if (conn->local_fd >= 0) {
117 close(conn->local_fd);
118 conn->local_fd = -1;
119 }
120
121 if (conn->curr_filename) {
122 client_event(conn, "closingtracefile", conn->curr_filename);
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200123 rate_ctr_inc(&conn->ctrg->ctr[PEER_CTR_PROTATE]);
124 rate_ctr_inc(&conn->server->ctrg->ctr[SERVER_CTR_PROTATE]);
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200125 talloc_free(conn->curr_filename);
126 conn->curr_filename = NULL;
127 }
128}
129
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200130static void close_connection(struct osmo_pcap_conn *conn)
131{
Holger Hans Peter Freyther098850d2016-08-26 19:31:16 +0200132 if (conn->rem_wq.bfd.fd >= 0) {
133 close(conn->rem_wq.bfd.fd);
134 conn->rem_wq.bfd.fd = -1;
Holger Hans Peter Freyther9ea4da42016-09-06 11:38:56 +0200135 osmo_tls_release(&conn->tls_session);
Holger Hans Peter Freyther098850d2016-08-26 19:31:16 +0200136 osmo_fd_unregister(&conn->rem_wq.bfd);
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200137 }
138
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200139 osmo_pcap_server_close_trace(conn);
140 client_event(conn, "disconnect", NULL);
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200141}
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200142
Holger Hans Peter Freyther1bec9d52016-09-06 11:01:50 +0200143void osmo_pcap_server_close_conn(struct osmo_pcap_conn *conn)
144{
145 return close_connection(conn);
146}
147
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200148static void restart_pcap(struct osmo_pcap_conn *conn)
149{
150 time_t now = time(NULL);
151 struct tm *tm = localtime(&now);
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200152 int rc;
153
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200154 osmo_pcap_server_close_trace(conn);
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200155
Holger Hans Peter Freyther28994282016-08-04 16:14:38 +0200156 /* omit any storing/creation of the file */
157 if (conn->no_store) {
158 conn->last_write = *tm;
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200159 talloc_free(conn->curr_filename);
160 conn->curr_filename = NULL;
Holger Hans Peter Freyther28994282016-08-04 16:14:38 +0200161 return;
162 }
163
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200164 conn->curr_filename = talloc_asprintf(conn, "%s/trace-%s-%d%.2d%.2d_%.2d%.2d%.2d.pcap",
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200165 conn->server->base_path, conn->name,
166 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
167 tm->tm_hour, tm->tm_min, tm->tm_sec);
Daniel Willmannde773862011-07-17 17:48:17 +0200168
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200169 if (!conn->curr_filename) {
Daniel Willmannde773862011-07-17 17:48:17 +0200170 LOGP(DSERVER, LOGL_ERROR, "Failed to assemble filename for %s.\n", conn->name);
171 return;
172 }
173
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200174 conn->local_fd = creat(conn->curr_filename, 0440);
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200175 if (conn->local_fd < 0) {
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200176 LOGP(DSERVER, LOGL_ERROR, "Failed to file: '%s'\n", conn->curr_filename);
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200177 return;
178 }
179
180 rc = write(conn->local_fd, &conn->file_hdr, sizeof(conn->file_hdr));
181 if (rc != sizeof(conn->file_hdr)) {
182 LOGP(DSERVER, LOGL_ERROR, "Failed to write the header: %d\n", errno);
183 close(conn->local_fd);
184 conn->local_fd = -1;
185 return;
186 }
187
188 conn->last_write = *tm;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200189}
190
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200191static int link_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200192{
193 struct pcap_file_header *hdr;
194
195 if (data->len != sizeof(*hdr)) {
196 LOGP(DSERVER, LOGL_ERROR, "The pcap_file_header does not fit.\n");
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200197 return -1;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200198 }
199
200 hdr = (struct pcap_file_header *) &data->data[0];
Holger Hans Peter Freyther28994282016-08-04 16:14:38 +0200201 if (!conn->no_store && conn->local_fd < 0) {
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200202 conn->file_hdr = *hdr;
203 restart_pcap(conn);
204 } else if (memcmp(&conn->file_hdr, hdr, sizeof(*hdr)) != 0) {
205 conn->file_hdr = *hdr;
206 restart_pcap(conn);
207 }
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200208
209 return 1;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200210}
211
212/*
213 * Check if we are past the limit or on a day change
214 */
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200215static int write_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200216{
217 time_t now = time(NULL);
218 struct tm *tm = localtime(&now);
219 int rc;
220
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200221 client_data(conn, data);
222
Holger Hans Peter Freyther28994282016-08-04 16:14:38 +0200223 if (conn->no_store) {
224 conn->last_write = *tm;
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200225 return 1;
Holger Hans Peter Freyther28994282016-08-04 16:14:38 +0200226 }
227
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200228 if (conn->local_fd < -1) {
229 LOGP(DSERVER, LOGL_ERROR, "No file is open. close connection.\n");
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200230 return -1;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200231 }
232
233 off_t cur = lseek(conn->local_fd, 0, SEEK_CUR);
234 if (cur > conn->server->max_size) {
235 LOGP(DSERVER, LOGL_NOTICE, "Rolling over file for %s\n", conn->name);
236 restart_pcap(conn);
237 } else if (conn->last_write.tm_mday != tm->tm_mday ||
238 conn->last_write.tm_mon != tm->tm_mon ||
239 conn->last_write.tm_year != tm->tm_year) {
240 LOGP(DSERVER, LOGL_NOTICE, "Rolling over file for %s\n", conn->name);
241 restart_pcap(conn);
242 }
243
244 conn->last_write = *tm;
245 rc = write(conn->local_fd, &data->data[0], data->len);
246 if (rc != data->len) {
247 LOGP(DSERVER, LOGL_ERROR, "Failed to write for %s\n", conn->name);
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200248 return -1;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200249 }
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200250 return 1;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200251}
252
253
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200254void osmo_pcap_server_delete(struct osmo_pcap_conn *conn)
255{
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200256 close_connection(conn);
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200257 llist_del(&conn->entry);
258 talloc_free(conn);
259}
260
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200261struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
262 const char *name)
263{
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200264 struct rate_ctr_group_desc *desc;
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200265 struct osmo_pcap_conn *conn;
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200266
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200267 llist_for_each_entry(conn, &server->conn, entry) {
268 if (strcmp(conn->name, name) == 0)
269 return conn;
270 }
271
272 conn = talloc_zero(server, struct osmo_pcap_conn);
273 if (!conn) {
274 LOGP(DSERVER, LOGL_ERROR,
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200275 "Failed to allocate the connection peer=%s.\n", name);
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200276 return NULL;
277 }
278
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200279 /* a bit nasty. we do not work with ids but names */
280 desc = talloc_zero(conn, struct rate_ctr_group_desc);
281 if (!desc) {
282 LOGP(DSERVER, LOGL_ERROR,
283 "Failed to allocate rate ctr desc peer=%s\n", name);
284 talloc_free(conn);
285 return NULL;
286 }
287 memcpy(desc, &pcap_peer_group_desc, sizeof(pcap_peer_group_desc));
288 desc->group_name_prefix = talloc_asprintf(desc, "pcap.peer.%s", name);
289 if (!desc->group_name_prefix) {
290 LOGP(DSERVER, LOGL_ERROR,
291 "Failed to allocate group name prefix peer=%s\n", name);
292 talloc_free(conn);
293 return NULL;
294 }
295 desc->group_description = talloc_asprintf(desc, "PCAP peer statistics %s", name);
296 if (!desc->group_description) {
297 LOGP(DSERVER, LOGL_ERROR,
298 "Failed to allocate group description peer=%s\n", name);
299 talloc_free(conn);
300 return NULL;
301 }
302
303 conn->ctrg = rate_ctr_group_alloc(desc, desc, 0);
304 if (!conn->ctrg) {
305 LOGP(DSERVER, LOGL_ERROR,
306 "Failed to allocate rate ctr peer=%s\n", name);
307 talloc_free(conn);
308 return NULL;
309 }
310
311
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200312 conn->name = talloc_strdup(conn, name);
Holger Hans Peter Freyther098850d2016-08-26 19:31:16 +0200313 /* we never write */
314 osmo_wqueue_init(&conn->rem_wq, 0);
315 conn->rem_wq.bfd.fd = -1;
Holger Hans Peter Freytherdc3d1dc2011-06-01 16:32:29 +0200316 conn->local_fd = -1;
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200317 conn->server = server;
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200318 conn->data = (struct osmo_pcap_data *) &conn->buf[0];
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +0200319 llist_add_tail(&conn->entry, &server->conn);
320 return conn;
321}
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +0200322
Holger Hans Peter Freyther9ea4da42016-09-06 11:38:56 +0200323static int do_read_tls(struct osmo_pcap_conn *conn, void *buf, size_t want_size)
324{
325 size_t size = want_size;
326 if (conn->tls_limit_read && size > conn->tls_limit_read)
327 size = conn->tls_limit_read;
328 return gnutls_record_recv(conn->tls_session.session, buf, size);
329}
330
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200331static int do_read(struct osmo_pcap_conn *conn, void *buf, size_t size)
332{
Holger Hans Peter Freyther9ea4da42016-09-06 11:38:56 +0200333 if (conn->direct_read)
334 return read(conn->rem_wq.bfd.fd, buf, size);
335 return do_read_tls(conn, buf, size);
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200336}
337
338static int read_cb_initial(struct osmo_pcap_conn *conn)
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200339{
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200340 int rc;
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200341
342 rc = do_read(conn, &conn->buf[sizeof(*conn->data) - conn->pend], conn->pend);
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200343 if (rc <= 0) {
344 LOGP(DSERVER, LOGL_ERROR,
345 "Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200346 return -1;
347 }
348
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200349 conn->pend -= rc;
350 if (conn->pend < 0) {
351 LOGP(DSERVER, LOGL_ERROR,
352 "Someone got the pending read wrong: %d\n", conn->pend);
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200353 return -1;
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200354 } else if (conn->pend == 0) {
355 conn->data->len = ntohs(conn->data->len);
356
Holger Hans Peter Freytherff1a5dc2015-12-03 19:32:04 +0100357 if (conn->data->len > SERVER_MAX_DATA_SIZE) {
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200358 LOGP(DSERVER, LOGL_ERROR,
Holger Hans Peter Freyther26327bd2015-12-03 19:29:38 +0100359 "Implausible data length: %u\n", conn->data->len);
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200360 return -1;
361 }
362
363 conn->state = STATE_DATA;
364 conn->pend = conn->data->len;
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200365 }
366
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200367 return 1;
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200368}
369
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200370static int read_cb_data(struct osmo_pcap_conn *conn)
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200371{
372 int rc;
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200373
374 rc = do_read(conn, &conn->data->data[conn->data->len - conn->pend], conn->pend);
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200375 if (rc <= 0) {
Holger Hans Peter Freyther59bfb582011-06-01 17:00:12 +0200376 LOGP(DSERVER, LOGL_ERROR,
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200377 "Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
Holger Hans Peter Freyther7309a902011-06-01 14:04:22 +0200378 return -1;
379 }
380
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200381 conn->pend -= rc;
382 if (conn->pend < 0) {
383 LOGP(DSERVER, LOGL_ERROR,
384 "Someone got the pending read wrong: %d\n", conn->pend);
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200385 return -1;
386 } else if (conn->pend == 0) {
387 conn->state = STATE_INITIAL;
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200388 conn->pend = sizeof(*conn->data);
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200389
390 /* count the full packet we got */
391 rate_ctr_inc(&conn->ctrg->ctr[PEER_CTR_PKTS]);
392 rate_ctr_inc(&conn->server->ctrg->ctr[SERVER_CTR_PKTS]);
393
394 /* count the bytes of it */
395 rate_ctr_add(&conn->ctrg->ctr[PEER_CTR_BYTES], conn->data->len);
396 rate_ctr_add(&conn->server->ctrg->ctr[SERVER_CTR_BYTES], conn->data->len);
397
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200398 switch (conn->data->type) {
399 case PKT_LINK_HDR:
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200400 return link_data(conn, conn->data);
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200401 break;
402 case PKT_LINK_DATA:
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200403 return write_data(conn, conn->data);
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200404 break;
405 }
406 }
407
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200408 return 1;
409}
410
411static int dispatch_read(struct osmo_pcap_conn *conn)
412{
413 if (conn->state == STATE_INITIAL) {
414 if (conn->reopen) {
415 LOGP(DSERVER, LOGL_INFO, "Reopening log for %s now.\n", conn->name);
416 restart_pcap(conn);
417 conn->reopen = 0;
418 }
419 return read_cb_initial(conn);
420 } else if (conn->state == STATE_DATA) {
421 return read_cb_data(conn);
422 }
423
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200424 return 0;
425}
426
Holger Hans Peter Freyther098850d2016-08-26 19:31:16 +0200427static int read_cb(struct osmo_fd *fd)
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200428{
429 struct osmo_pcap_conn *conn;
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200430 int rc;
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200431
432 conn = fd->data;
Holger Hans Peter Freyther064d2242016-09-06 11:08:19 +0200433 rc = dispatch_read(conn);
434 if (rc <= 0)
435 close_connection(conn);
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200436 return 0;
437}
438
Holger Hans Peter Freyther9ea4da42016-09-06 11:38:56 +0200439static void tls_error_cb(struct osmo_tls_session *session)
440{
441 struct osmo_pcap_conn *conn;
442 conn = container_of(session, struct osmo_pcap_conn, tls_session);
443 close_connection(conn);
444}
445
446static int tls_read_cb(struct osmo_tls_session *session)
447{
448 struct osmo_pcap_conn *conn;
449 size_t pend;
450 int rc;
451
452 conn = container_of(session, struct osmo_pcap_conn, tls_session);
453 conn->tls_limit_read = 0;
454 rc = dispatch_read(conn);
455 if (rc <= 0)
456 return rc;
457
458 /**
459 * This is a weakness of a single select approach and the
460 * buffered reading here. We need to read everything as
461 * otherwise we do not receive a ready-read. But at the
462 * same time don't read more than is buffered! So cap what
463 * can be read right now.
464 */
465 while ((pend = osmo_tls_pending(session)) > 0) {
466 conn->tls_limit_read = pend;
467 rc = dispatch_read(conn);
468 if (rc <= 0)
469 return rc;
470 }
471
472 return 1;
473}
474
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200475static void new_connection(struct osmo_pcap_server *server,
476 struct osmo_pcap_conn *client, int new_fd)
477{
478 close_connection(client);
479
480 memset(&client->file_hdr, 0, sizeof(client->file_hdr));
Holger Hans Peter Freyther098850d2016-08-26 19:31:16 +0200481 client->rem_wq.bfd.fd = new_fd;
482 if (osmo_fd_register(&client->rem_wq.bfd) != 0) {
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200483 LOGP(DSERVER, LOGL_ERROR, "Failed to register fd.\n");
Holger Hans Peter Freyther098850d2016-08-26 19:31:16 +0200484 client->rem_wq.bfd.fd = -1;
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200485 close(new_fd);
486 return;
487 }
488
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200489 rate_ctr_inc(&client->ctrg->ctr[PEER_CTR_CONNECT]);
490
Holger Hans Peter Freyther39d904f2011-06-01 18:49:07 +0200491 client->state = STATE_INITIAL;
Holger Hans Peter Freyther91eaae32011-06-02 17:58:46 +0200492 client->pend = sizeof(*client->data);
Holger Hans Peter Freyther9ea4da42016-09-06 11:38:56 +0200493
494 if (client->tls_use) {
495 if (!osmo_tls_init_server_session(client, server)) {
496 close_connection(client);
497 return;
498 }
499 client->tls_session.error = tls_error_cb;
500 client->tls_session.read = tls_read_cb;
501 client->direct_read = false;
502 } else {
503 client->rem_wq.bfd.cb = osmo_wqueue_bfd_cb;
504 client->rem_wq.bfd.data = client;
505 client->rem_wq.bfd.when = BSC_FD_READ;
506 client->rem_wq.read_cb = read_cb;
507 client->direct_read = true;
508 }
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200509}
510
511static int accept_cb(struct osmo_fd *fd, unsigned int when)
512{
513 struct osmo_pcap_conn *conn;
514 struct osmo_pcap_server *server;
515 struct sockaddr_in addr;
516 socklen_t size = sizeof(addr);
517 int new_fd;
518
519 new_fd = accept(fd->fd, (struct sockaddr *) &addr, &size);
520 if (new_fd < 0) {
521 LOGP(DSERVER, LOGL_ERROR, "Failed to accept socket: %d\n", errno);
522 return -1;
523 }
524
525 server = fd->data;
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200526
527 /* count any accept to see no clients */
528 rate_ctr_inc(&server->ctrg->ctr[SERVER_CTR_CONNECT]);
529
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200530 llist_for_each_entry(conn, &server->conn, entry) {
531 if (conn->remote_addr.s_addr == addr.sin_addr.s_addr) {
532 LOGP(DSERVER, LOGL_NOTICE,
533 "New connection from %s\n", conn->name);
Holger Hans Peter Freythere0248692016-08-05 15:47:08 +0200534 client_event(conn, "connect", NULL);
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200535 new_connection(server, conn, new_fd);
536 return 0;
537 }
538 }
539
Holger Hans Peter Freyther99526a62016-08-19 19:15:39 +0200540 rate_ctr_inc(&server->ctrg->ctr[SERVER_CTR_NOCLIENT]);
Holger Hans Peter Freyther9ea4da42016-09-06 11:38:56 +0200541
542 /*
543 * TODO: In the future start with a tls handshake and see if we know
544 * this client.
545 */
546
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200547 LOGP(DSERVER, LOGL_ERROR,
548 "Failed to find client for %s\n", inet_ntoa(addr.sin_addr));
549 close(new_fd);
550 return -1;
551}
552
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +0200553int osmo_pcap_server_listen(struct osmo_pcap_server *server)
554{
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200555 int fd;
556
557 fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Daniel Willmannb0003682011-07-17 17:48:19 +0200558 server->addr, server->port, OSMO_SOCK_F_BIND);
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200559 if (fd < 0) {
560 LOGP(DSERVER, LOGL_ERROR, "Failed to create the server socket.\n");
561 return -1;
562 }
563
564 server->listen_fd.fd = fd;
565 server->listen_fd.when = BSC_FD_READ;
566 server->listen_fd.cb = accept_cb;
567 server->listen_fd.data = server;
568
569 if (osmo_fd_register(&server->listen_fd) != 0) {
570 LOGP(DSERVER, LOGL_ERROR, "Failed to register the socket.\n");
571 close(fd);
572 return -1;
573 }
574
575 return 0;
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +0200576}
Daniel Willmannc7401c62011-07-17 17:48:18 +0200577
578void osmo_pcap_server_reopen(struct osmo_pcap_server *server)
579{
580 struct osmo_pcap_conn *conn;
581 LOGP(DSERVER, LOGL_INFO, "Reopening all logfiles.\n");
582 llist_for_each_entry(conn, &server->conn, entry) {
583 /* Write the complete packet out first */
584 if (conn->state == STATE_INITIAL) {
585 restart_pcap(conn);
586 } else {
587 LOGP(DSERVER, LOGL_INFO, "Delaying %s until current packet is complete.\n", conn->name);
588 conn->reopen = 1;
589 }
590 }
591}