-
Notifications
You must be signed in to change notification settings - Fork 0
/
vty_server.cc
167 lines (139 loc) · 4.58 KB
/
vty_server.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <vty_server.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <string>
#include <vector>
#include <algorithm>
#include <slankdev/socketfd.h>
#include <slankdev/net/telnet.h>
#include <slankdev/poll.h>
#include <slankdev/exception.h>
#include <slankdev/string.h>
#include <slankdev/util.h>
#include <slankdev/asciicode.h>
static int open_server_sock(uint32_t addr, uint16_t port)
{
slankdev::socketfd server_sock;
server_sock.noclose_in_destruct = true;
server_sock.socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int option = 1;
server_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
server_sock.bind(addr, port);
server_sock.listen(5);
return server_sock.get_fd();
}
static void preconfig_telnet_fd(int fd)
{
slankdev::socketfd client_sock(fd);
uint32_t on = 1;
client_sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
int flags = client_sock.fcntl(F_GETFL);
client_sock.fcntl(F_SETFL, (flags | O_NONBLOCK));
client_sock.noclose_in_destruct = true;
slankdev::vty_will_echo (fd);
slankdev::vty_will_suppress_go_ahead (fd);
slankdev::vty_dont_linemode (fd);
slankdev::vty_do_window_size (fd);
}
vty_server::vty_server(uint32_t addr, uint16_t port,
const char* bootmsg, const char* prompt)
: bootmsg_(bootmsg), prompt_(prompt)
{
server_fd_ = open_server_sock(addr, port);
using namespace slankdev;
uint8_t up [] = {AC_ESC, '[', AC_A};
uint8_t down [] = {AC_ESC, '[', AC_B};
uint8_t right[] = {AC_ESC, '[', AC_C};
uint8_t left [] = {AC_ESC, '[', AC_D};
install_keyfunction(new KF_hist_search_deep (up , sizeof(up )));
install_keyfunction(new KF_hist_search_shallow(down , sizeof(down )));
install_keyfunction(new KF_right(right, sizeof(right)));
install_keyfunction(new KF_left (left , sizeof(left )));
uint8_t ctrlP[] = {AC_Ctrl_P};
uint8_t ctrlN[] = {AC_Ctrl_N};
uint8_t ctrlF[] = {AC_Ctrl_F};
uint8_t ctrlB[] = {AC_Ctrl_B};
install_keyfunction(new KF_hist_search_deep (ctrlP, sizeof(ctrlP)));
install_keyfunction(new KF_hist_search_shallow(ctrlN, sizeof(ctrlN)));
install_keyfunction(new KF_right(ctrlF, sizeof(ctrlF)));
install_keyfunction(new KF_left (ctrlB, sizeof(ctrlB)));
uint8_t ctrlA[] = {AC_Ctrl_A};
uint8_t ctrlE[] = {AC_Ctrl_E};
install_keyfunction(new KF_cursor_top(ctrlA, sizeof(ctrlA)));
install_keyfunction(new KF_cursor_end(ctrlE, sizeof(ctrlE)));
uint8_t question[] = {'?'};
install_keyfunction(new KF_help(question, sizeof(question)));
uint8_t tab[] = {'\t'};
install_keyfunction(new KF_completion(tab, sizeof(tab)));
uint8_t ret[] = {'\r', '\0'};
install_keyfunction(new KF_return (ret, sizeof(ret)));
uint8_t CtrlJ[] = {AC_Ctrl_J};
install_keyfunction(new KF_return (CtrlJ, sizeof(CtrlJ)));
uint8_t backspace[] = {0x7f};
install_keyfunction(new KF_backspace (backspace, sizeof(backspace)));
}
vty_server::~vty_server()
{
for (vty_cmd* c : commands_) delete c;
for (key_func* f : keyfuncs_) delete f;
}
void vty_server::install_keyfunction(key_func* kf) { keyfuncs_.push_back(kf); }
void vty_server::poll_dispatch()
{
struct Pollfd : public pollfd {
Pollfd(int f, short e) { fd = f; events = e; }
};
std::vector<struct Pollfd> fds;
fds.push_back(Pollfd(server_fd_, POLLIN));
for (const vty_client& sh : clients_) fds.push_back(Pollfd(sh.client_fd_, POLLIN));
if (slankdev::poll(fds.data(), fds.size(), 0)) {
/*
* Server Accept Process
*/
if (fds[0].revents & POLLIN) {
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int fd = accept(fds[0].fd, (sockaddr*)&client, &client_len);
printf("accepted connection host=%s:%d\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));
preconfig_telnet_fd(fd);
clients_.push_back(
vty_client(
fd,
bootmsg_.c_str(),
prompt_.c_str(),
&commands_,
&keyfuncs_,
user_ptr_
)
);
}
/*
* Client Read Process
*/
for (size_t i=1; i<fds.size(); i++) {
if (fds[i].revents & POLLIN) {
clients_[i-1].poll_dispatch();
if (clients_[i-1].closed_) {
close(fds[i].fd);
clients_.erase(clients_.begin() + i);
continue;
}
}
}
} // if(poll)
}
void vty_server::install_command(vty_cmd_match m, vty_cmdcallback_t f, void* arg)
{
vty_cmd* cmd = new vty_cmd;
cmd->match = m;
cmd->f = f;
cmd->arg = arg;
commands_.push_back(cmd);
}