blob: 1abf141dc9dcd5a2a090abd6cf37f1e07017974e [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>
Sylvain Munauta9efc122012-03-01 20:41:40 +010023#include <errno.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020024#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010029#include <osmocom/core/msgb.h>
Sylvain Munauta9efc122012-03-01 20:41:40 +010030#include <osmocom/core/socket.h>
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010031#include <osmocom/core/talloc.h>
32#include <osmocom/core/logging.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020033
34#include <osmocom/vty/telnet_interface.h>
35#include <osmocom/vty/buffer.h>
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +080036#include <osmocom/vty/command.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020037
Harald Weltee881b1b2011-08-17 18:52:30 +020038/*! \addtogroup telnet_interface
Harald Welte7acb30c2011-08-17 17:13:48 +020039 * @{
40 */
41/*! \file telnet_interface.c */
42
Harald Welte3fb0b6f2010-05-19 19:02:52 +020043/* per connection data */
44LLIST_HEAD(active_connections);
45
46static void *tall_telnet_ctx;
47
48/* per network data */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020049static int telnet_new_connection(struct osmo_fd *fd, unsigned int what);
Harald Welte3fb0b6f2010-05-19 19:02:52 +020050
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020051static struct osmo_fd server_socket = {
Harald Welte3fb0b6f2010-05-19 19:02:52 +020052 .when = BSC_FD_READ,
53 .cb = telnet_new_connection,
54 .priv_nr = 0,
55};
56
Sylvain Munauta9efc122012-03-01 20:41:40 +010057/*! \brief Initialize telnet based VTY interface listening to 127.0.0.1
Harald Welte7acb30c2011-08-17 17:13:48 +020058 * \param[in] tall_ctx \ref talloc context
59 * \param[in] priv private data to be passed to callback
60 * \param[in] port UDP port number
61 */
Harald Welte3fb0b6f2010-05-19 19:02:52 +020062int telnet_init(void *tall_ctx, void *priv, int port)
63{
Sylvain Munauta9efc122012-03-01 20:41:40 +010064 return telnet_init_dynif(tall_ctx, priv, "127.0.0.1", port);
65}
66
67/*! \brief Initialize telnet based VTY interface
68 * \param[in] tall_ctx \ref talloc context
69 * \param[in] priv private data to be passed to callback
70 * \param[in] ip IP to listen to ('::1' for localhost, '::0' for all, ...)
71 * \param[in] port UDP port number
72 */
73int telnet_init_dynif(void *tall_ctx, void *priv, const char *ip, int port)
74{
75 int rc;
Harald Welte3fb0b6f2010-05-19 19:02:52 +020076
77 tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
Sylvain Munauta9efc122012-03-01 20:41:40 +010078 "telnet_connection");
Harald Welte3fb0b6f2010-05-19 19:02:52 +020079
Sylvain Munauta9efc122012-03-01 20:41:40 +010080 rc = osmo_sock_init_ofd(
81 &server_socket,
82 AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP,
83 ip, port, OSMO_SOCK_F_BIND
84 );
Harald Welte3fb0b6f2010-05-19 19:02:52 +020085
86 server_socket.data = priv;
Harald Welte3fb0b6f2010-05-19 19:02:52 +020087
Sylvain Munauta9efc122012-03-01 20:41:40 +010088 return (rc < 0) ? -1 : 0;
Harald Welte3fb0b6f2010-05-19 19:02:52 +020089}
90
Holger Hans Peter Freyther2e228fc2010-09-11 13:41:41 +080091extern struct host host;
Harald Welte3fb0b6f2010-05-19 19:02:52 +020092
Harald Welte7acb30c2011-08-17 17:13:48 +020093/*! \brief close a telnet connection */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020094int telnet_close_client(struct osmo_fd *fd)
Harald Welte3fb0b6f2010-05-19 19:02:52 +020095{
96 struct telnet_connection *conn = (struct telnet_connection*)fd->data;
97
98 close(fd->fd);
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020099 osmo_fd_unregister(fd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200100
101 if (conn->dbg) {
102 log_del_target(conn->dbg);
103 talloc_free(conn->dbg);
104 }
105
106 llist_del(&conn->entry);
107 talloc_free(conn);
108 return 0;
109}
110
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200111static int client_data(struct osmo_fd *fd, unsigned int what)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200112{
113 struct telnet_connection *conn = fd->data;
114 int rc = 0;
115
116 if (what & BSC_FD_READ) {
117 conn->fd.when &= ~BSC_FD_READ;
118 rc = vty_read(conn->vty);
119 }
120
121 /* vty might have been closed from vithin vty_read() */
122 if (!conn->vty)
123 return rc;
124
125 if (what & BSC_FD_WRITE) {
126 rc = buffer_flush_all(conn->vty->obuf, fd->fd);
127 if (rc == BUFFER_EMPTY)
128 conn->fd.when &= ~BSC_FD_WRITE;
129 }
130
131 return rc;
132}
133
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200134static int telnet_new_connection(struct osmo_fd *fd, unsigned int what)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200135{
136 struct telnet_connection *connection;
137 struct sockaddr_in sockaddr;
138 socklen_t len = sizeof(sockaddr);
139 int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
140
141 if (new_connection < 0) {
142 LOGP(0, LOGL_ERROR, "telnet accept failed\n");
143 return new_connection;
144 }
145
146 connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
147 connection->priv = fd->data;
148 connection->fd.data = connection;
149 connection->fd.fd = new_connection;
150 connection->fd.when = BSC_FD_READ;
151 connection->fd.cb = client_data;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200152 osmo_fd_register(&connection->fd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200153 llist_add_tail(&connection->entry, &active_connections);
154
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200155 connection->vty = vty_create(new_connection, connection);
156 if (!connection->vty) {
157 LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
158 close(new_connection);
159 talloc_free(connection);
160 return -1;
161 }
162
163 return 0;
164}
165
Harald Welte7acb30c2011-08-17 17:13:48 +0200166/*! \brief callback from core VTY code about VTY related events */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200167void vty_event(enum event event, int sock, struct vty *vty)
168{
169 struct telnet_connection *connection = vty->priv;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200170 struct osmo_fd *bfd = &connection->fd;
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200171
172 if (vty->type != VTY_TERM)
173 return;
174
175 switch (event) {
176 case VTY_READ:
177 bfd->when |= BSC_FD_READ;
178 break;
179 case VTY_WRITE:
180 bfd->when |= BSC_FD_WRITE;
181 break;
182 case VTY_CLOSED:
183 /* vty layer is about to free() vty */
184 connection->vty = NULL;
185 telnet_close_client(bfd);
186 break;
187 default:
188 break;
189 }
190}
191
Andreas.Eversbergdc3be0a2011-11-06 20:09:28 +0100192void telnet_exit(void)
193{
194 struct telnet_connection *tc, *tc2;
195
196 llist_for_each_entry_safe(tc, tc2, &active_connections, entry)
197 telnet_close_client(&tc->fd);
198
199 osmo_fd_unregister(&server_socket);
200 close(server_socket.fd);
201 talloc_free(tall_telnet_ctx);
202}
203
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200204/*! @} */