blob: 19e5c3cda4ada13619184cff3e107ae2379eac2f [file] [log] [blame]
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +02001/*
2 * osmo-pcap-server 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_server.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020024#include <osmo-pcap/common.h>
25
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020026#include <osmocom/core/socket.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020027#include <osmocom/core/talloc.h>
28
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020029#include <arpa/inet.h>
30#include <sys/socket.h>
31#include <sys/types.h>
32
33#include <errno.h>
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020034#include <string.h>
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020035#include <unistd.h>
36
37static void close_connection(struct osmo_pcap_conn *conn)
38{
39 if (conn->rem_fd.fd != -1) {
40 close(conn->rem_fd.fd);
41 conn->rem_fd.fd = -1;
42 osmo_fd_unregister(&conn->rem_fd);
43 }
44
45 if (conn->local_fd != -1) {
46 close(conn->local_fd);
47 conn->local_fd = -1;
48 }
49}
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020050
51void osmo_pcap_server_delete(struct osmo_pcap_conn *conn)
52{
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020053 close_connection(conn);
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020054 llist_del(&conn->entry);
55 talloc_free(conn);
56}
57
58
59struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
60 const char *name)
61{
62 struct osmo_pcap_conn *conn;
63 llist_for_each_entry(conn, &server->conn, entry) {
64 if (strcmp(conn->name, name) == 0)
65 return conn;
66 }
67
68 conn = talloc_zero(server, struct osmo_pcap_conn);
69 if (!conn) {
70 LOGP(DSERVER, LOGL_ERROR,
71 "Failed to find the connection.\n");
72 return NULL;
73 }
74
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020075 conn->name = talloc_strdup(conn, name);
76 conn->rem_fd.fd = -1;
77 conn->server = server;
Holger Hans Peter Freyther9f6127f2011-05-31 22:52:41 +020078 llist_add_tail(&conn->entry, &server->conn);
79 return conn;
80}
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +020081
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +020082static int read_cb(struct osmo_fd *fd, unsigned int what)
83{
84 struct osmo_pcap_conn *conn;
85 char buf[4096];
86 int rc;
87
88 conn = fd->data;
89 rc = read(fd->fd, buf, sizeof(buf));
90 if (rc < 0) {
91 LOGP(DSERVER, LOGL_ERROR, "Failed to read from %s\n", conn->name);
92 close_connection(conn);
93 return -1;
94 }
95
96 return 0;
97}
98
99static void new_connection(struct osmo_pcap_server *server,
100 struct osmo_pcap_conn *client, int new_fd)
101{
102 close_connection(client);
103
104 memset(&client->file_hdr, 0, sizeof(client->file_hdr));
105 client->rem_fd.fd = new_fd;
106 if (osmo_fd_register(&client->rem_fd) != 0) {
107 LOGP(DSERVER, LOGL_ERROR, "Failed to register fd.\n");
108 client->rem_fd.fd = -1;
109 close(new_fd);
110 return;
111 }
112
113 client->rem_fd.data = client;
114 client->rem_fd.when = BSC_FD_READ;
115 client->rem_fd.cb = read_cb;
116}
117
118static int accept_cb(struct osmo_fd *fd, unsigned int when)
119{
120 struct osmo_pcap_conn *conn;
121 struct osmo_pcap_server *server;
122 struct sockaddr_in addr;
123 socklen_t size = sizeof(addr);
124 int new_fd;
125
126 new_fd = accept(fd->fd, (struct sockaddr *) &addr, &size);
127 if (new_fd < 0) {
128 LOGP(DSERVER, LOGL_ERROR, "Failed to accept socket: %d\n", errno);
129 return -1;
130 }
131
132 server = fd->data;
133 llist_for_each_entry(conn, &server->conn, entry) {
134 if (conn->remote_addr.s_addr == addr.sin_addr.s_addr) {
135 LOGP(DSERVER, LOGL_NOTICE,
136 "New connection from %s\n", conn->name);
137 new_connection(server, conn, new_fd);
138 return 0;
139 }
140 }
141
142 LOGP(DSERVER, LOGL_ERROR,
143 "Failed to find client for %s\n", inet_ntoa(addr.sin_addr));
144 close(new_fd);
145 return -1;
146}
147
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +0200148int osmo_pcap_server_listen(struct osmo_pcap_server *server)
149{
Holger Hans Peter Freyther80b8b602011-05-31 23:42:20 +0200150 int fd;
151
152 fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
153 server->addr, server->port, 1);
154 if (fd < 0) {
155 LOGP(DSERVER, LOGL_ERROR, "Failed to create the server socket.\n");
156 return -1;
157 }
158
159 server->listen_fd.fd = fd;
160 server->listen_fd.when = BSC_FD_READ;
161 server->listen_fd.cb = accept_cb;
162 server->listen_fd.data = server;
163
164 if (osmo_fd_register(&server->listen_fd) != 0) {
165 LOGP(DSERVER, LOGL_ERROR, "Failed to register the socket.\n");
166 close(fd);
167 return -1;
168 }
169
170 return 0;
Holger Hans Peter Freyther13619dd2011-05-31 22:09:08 +0200171}