blob: ed64cdabbf41ccb930fb8be39e86b15dd7d78a67 [file] [log] [blame]
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001/* minimalistic telnet/network interface it might turn into a wire interface */
2/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <unistd.h>
27
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010028#include <osmocom/core/msgb.h>
29#include <osmocom/core/talloc.h>
30#include <osmocom/core/logging.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020031
32#include <osmocom/vty/telnet_interface.h>
33#include <osmocom/vty/buffer.h>
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +080034#include <osmocom/vty/command.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020035
Harald Weltee881b1b2011-08-17 18:52:30 +020036/*! \addtogroup telnet_interface
Harald Welte7acb30c2011-08-17 17:13:48 +020037 * @{
38 */
39/*! \file telnet_interface.c */
40
Harald Welte3fb0b6f2010-05-19 19:02:52 +020041/* per connection data */
42LLIST_HEAD(active_connections);
43
44static void *tall_telnet_ctx;
45
46/* per network data */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020047static int telnet_new_connection(struct osmo_fd *fd, unsigned int what);
Harald Welte3fb0b6f2010-05-19 19:02:52 +020048
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020049static struct osmo_fd server_socket = {
Harald Welte3fb0b6f2010-05-19 19:02:52 +020050 .when = BSC_FD_READ,
51 .cb = telnet_new_connection,
52 .priv_nr = 0,
53};
54
Harald Welte7acb30c2011-08-17 17:13:48 +020055/*! \brief Initialize telnet based VTY interface
56 * \param[in] tall_ctx \ref talloc context
57 * \param[in] priv private data to be passed to callback
58 * \param[in] port UDP port number
59 */
Harald Welte3fb0b6f2010-05-19 19:02:52 +020060int telnet_init(void *tall_ctx, void *priv, int port)
61{
62 struct sockaddr_in sock_addr;
63 int fd, rc, on = 1;
64
65 tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
66 "telnet_connection");
67
Harald Welte7acb30c2011-08-17 17:13:48 +020068 /* FIXME: use new socket.c code of libosmocore */
Harald Welte3fb0b6f2010-05-19 19:02:52 +020069 fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
70
71 if (fd < 0) {
72 LOGP(0, LOGL_ERROR, "Telnet interface socket creation failed\n");
73 return fd;
74 }
75
76 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
77
78 memset(&sock_addr, 0, sizeof(sock_addr));
79 sock_addr.sin_family = AF_INET;
80 sock_addr.sin_port = htons(port);
81 sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
82
83 rc = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
Sylvain Munaut4a4f96d2011-01-03 22:19:40 +010084 if (rc < 0) {
Harald Welte3fb0b6f2010-05-19 19:02:52 +020085 LOGP(0, LOGL_ERROR, "Telnet interface failed to bind\n");
86 close(fd);
87 return rc;
88 }
89
90 rc = listen(fd, 0);
91 if (rc < 0) {
92 LOGP(0, LOGL_ERROR, "Telnet interface failed to listen\n");
93 close(fd);
94 return rc;
95 }
96
97 server_socket.data = priv;
98 server_socket.fd = fd;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020099 osmo_fd_register(&server_socket);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200100
101 return 0;
102}
103
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +0800104extern struct host host;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200105
106static void print_welcome(int fd)
107{
Harald Welteb62b04b2011-05-22 19:15:07 +0200108 static const char *msg1 = "Welcome to the ";
109 static const char *msg2 = " control interface\r\n";
Harald Welte9c3cbfb2011-07-16 11:59:44 +0200110 const char *app_name = "<unnamed>";
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200111
Harald Welteb62b04b2011-05-22 19:15:07 +0200112 if (host.app_info->name)
113 app_name = host.app_info->name;
114
Harald Welte2b322152011-07-16 12:01:52 +0200115 write(fd, msg1, strlen(msg1));
116 write(fd, app_name, strlen(app_name));
117 write(fd, msg2, strlen(msg2));
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +0800118
119 if (host.app_info->copyright)
Harald Welte2b322152011-07-16 12:01:52 +0200120 write(fd, host.app_info->copyright, strlen(host.app_info->copyright));
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200121}
122
Harald Welte7acb30c2011-08-17 17:13:48 +0200123/*! \brief close a telnet connection */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200124int telnet_close_client(struct osmo_fd *fd)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200125{
126 struct telnet_connection *conn = (struct telnet_connection*)fd->data;
127
128 close(fd->fd);
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200129 osmo_fd_unregister(fd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200130
131 if (conn->dbg) {
132 log_del_target(conn->dbg);
133 talloc_free(conn->dbg);
134 }
135
136 llist_del(&conn->entry);
137 talloc_free(conn);
138 return 0;
139}
140
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200141static int client_data(struct osmo_fd *fd, unsigned int what)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200142{
143 struct telnet_connection *conn = fd->data;
144 int rc = 0;
145
146 if (what & BSC_FD_READ) {
147 conn->fd.when &= ~BSC_FD_READ;
148 rc = vty_read(conn->vty);
149 }
150
151 /* vty might have been closed from vithin vty_read() */
152 if (!conn->vty)
153 return rc;
154
155 if (what & BSC_FD_WRITE) {
156 rc = buffer_flush_all(conn->vty->obuf, fd->fd);
157 if (rc == BUFFER_EMPTY)
158 conn->fd.when &= ~BSC_FD_WRITE;
159 }
160
161 return rc;
162}
163
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200164static int telnet_new_connection(struct osmo_fd *fd, unsigned int what)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200165{
166 struct telnet_connection *connection;
167 struct sockaddr_in sockaddr;
168 socklen_t len = sizeof(sockaddr);
169 int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
170
171 if (new_connection < 0) {
172 LOGP(0, LOGL_ERROR, "telnet accept failed\n");
173 return new_connection;
174 }
175
176 connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
177 connection->priv = fd->data;
178 connection->fd.data = connection;
179 connection->fd.fd = new_connection;
180 connection->fd.when = BSC_FD_READ;
181 connection->fd.cb = client_data;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200182 osmo_fd_register(&connection->fd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200183 llist_add_tail(&connection->entry, &active_connections);
184
185 print_welcome(new_connection);
186
187 connection->vty = vty_create(new_connection, connection);
188 if (!connection->vty) {
189 LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
190 close(new_connection);
191 talloc_free(connection);
192 return -1;
193 }
194
195 return 0;
196}
197
Harald Welte7acb30c2011-08-17 17:13:48 +0200198/*! \brief callback from core VTY code about VTY related events */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200199void vty_event(enum event event, int sock, struct vty *vty)
200{
201 struct telnet_connection *connection = vty->priv;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200202 struct osmo_fd *bfd = &connection->fd;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200203
204 if (vty->type != VTY_TERM)
205 return;
206
207 switch (event) {
208 case VTY_READ:
209 bfd->when |= BSC_FD_READ;
210 break;
211 case VTY_WRITE:
212 bfd->when |= BSC_FD_WRITE;
213 break;
214 case VTY_CLOSED:
215 /* vty layer is about to free() vty */
216 connection->vty = NULL;
217 telnet_close_client(bfd);
218 break;
219 default:
220 break;
221 }
222}
223
Harald Welte7acb30c2011-08-17 17:13:48 +0200224/*! }@ */