WvStreams
wvstreamsdebuggerserver.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 */
6#include "wvstreamsdebuggerserver.h"
7#include "wvunixsocket.h"
8#include "wvtcplistener.h"
9#include "wvunixlistener.h"
10
11void WvStreamsDebuggerServer::Connection::choose_salt()
12{
13 const int salt_size = 8;
14 const int salt_alphabet_size = 26+26+10;
15 const char salt_chars[salt_alphabet_size+1] =
16 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
17
18 salt.setsize(salt_size+1);
19 for (int i=0; i<salt_size; ++i)
20 salt.edit()[i] = salt_chars[rand() % salt_alphabet_size];
21 salt.edit()[salt_size] = '\0';
22}
23
24
25WvStreamsDebuggerServer::Connection::Connection(IWvStream *s) :
26 WvStreamClone(s)
27{
28}
29
30
31void WvStreamsDebuggerServer::Connection::result_cb(WvStringParm,
32 WvStringList &results)
33{
34 send("-", results);
35}
36
37
38void WvStreamsDebuggerServer::Connection::send(WvStringParm code,
39 WvStringParm result)
40{
41 WvStringList results;
42 results.append(result);
43 send(code, results);
44}
45
46
47void WvStreamsDebuggerServer::Connection::send(WvStringParm code,
48 WvStringList &results)
49{
50 print("%s %s\n", wvtcl_escape(code), wvtcl_encode(results));
51}
52
53
54WvStreamsDebuggerServer::WvStreamsDebuggerServer(const WvUnixAddr &unix_addr,
55 AuthCallback _auth_cb,
56 const WvIPPortAddr &tcp_addr) :
57 log("WvStreamsDebuggerServer", WvLog::Debug3),
58 unix_listener(NULL),
59 tcp_listener(NULL),
60 auth_cb(_auth_cb)
61{
62 WvIStreamList::globallist.append(&streams, false, "debugger streams");
63
64#ifndef _WIN32
65 if (true)
66 {
67 unix_listener = new WvUnixListener(unix_addr, 0700);
68 unix_listener->set_wsname("wsd listener on %s", unix_addr);
69 unix_listener->onaccept(
70 wv::bind(&WvStreamsDebuggerServer::unix_listener_cb, this, _1));
71 unix_listener->setclosecallback(
72 wv::bind(&WvStreamsDebuggerServer::unix_listener_close_cb, this));
73 streams.append(unix_listener, true, "debugger unix listener");
74 log("Listening on %s\n", unix_addr);
75 }
76#endif
77
78 if (tcp_addr != WvIPPortAddr())
79 {
80 tcp_listener = new WvTCPListener(tcp_addr);
81 tcp_listener->set_wsname("wsd listener on %s", tcp_addr);
82 tcp_listener->onaccept(
83 wv::bind(&WvStreamsDebuggerServer::tcp_listener_cb, this, _1));
84 tcp_listener->setclosecallback(
85 wv::bind(&WvStreamsDebuggerServer::tcp_listener_close_cb, this));
86 streams.append(tcp_listener, true, "debugger tcp listener");
87 log("Listening on %s\n", tcp_addr);
88 }
89}
90
91
92WvStreamsDebuggerServer::~WvStreamsDebuggerServer()
93{
94 WvIStreamList::globallist.unlink(&streams);
95}
96
97
98#ifndef _WIN32
99void WvStreamsDebuggerServer::unix_listener_cb(IWvStream *unix_conn)
100{
101 log("Accepted connection from %s\n", *unix_conn->src());
102 Connection *conn = new Connection(unix_conn);
103 conn->setcallback(wv::bind(&WvStreamsDebuggerServer::ready_cb, this,
104 wv::ref(*conn)));
105 streams.append(conn, true, "debugger unix connection");
106}
107
108
109void WvStreamsDebuggerServer::unix_listener_close_cb()
110{
111 log("Listener on %s closing\n", *unix_listener->src());
112}
113#endif
114
115void WvStreamsDebuggerServer::tcp_listener_cb(IWvStream *tcp_conn)
116{
117 log("Accepted connection from %s\n", *tcp_conn->src());
118 Connection *conn = new Connection(tcp_conn);
119 conn->setcallback(wv::bind(&WvStreamsDebuggerServer::ready_cb, this,
120 wv::ref(*conn)));
121 streams.append(conn, true, "debugger tcp connection");
122}
123
124
125void WvStreamsDebuggerServer::tcp_listener_close_cb()
126{
127 log("Listener on %s closing\n", *tcp_listener->src());
128}
129
130
131void WvStreamsDebuggerServer::auth_request_cb(Connection &s)
132{
133 s.choose_salt();
134 s.send("AUTH", s.salt);
135
136 s.setcallback(wv::bind(&WvStreamsDebuggerServer::auth_response_cb, this,
137 wv::ref(s)));
138}
139
140
141void WvStreamsDebuggerServer::auth_response_cb(Connection &s)
142{
143 const char *line = s.getline();
144 if (line == NULL)
145 return;
146
147 WvStringList args;
148 wvtcl_decode(args, line);
149
150 WvString username = args.popstr();
151 WvString encoded_salted_password = args.popstr();
152
153 if (!auth_cb || !username || !encoded_salted_password
154 || !auth_cb(username, s.salt, encoded_salted_password))
155 {
156 s.send("ERROR", "Authentication failure");
157 s.setcallback(wv::bind(&WvStreamsDebuggerServer::auth_request_cb,
158 this, wv::ref(s)));
159 }
160 else
161 {
162 s.send("OK", "Authenticated");
163 s.setcallback(wv::bind(&WvStreamsDebuggerServer::ready_cb, this,
164 wv::ref(s)));
165 }
166}
167
168
169void WvStreamsDebuggerServer::ready_cb(Connection &s)
170{
171 const char *line = s.getline();
172 if (line == NULL)
173 return;
174
175 WvStringList args;
176 wvtcl_decode(args, line);
177
178 WvString cmd = args.popstr();
179 if (!cmd)
180 {
181 s.send("ERROR", "Empty command");
182 return;
183 }
184
185 WvString result = s.debugger.run(cmd, args,
186 wv::bind(&Connection::result_cb, &s,
187 _1, _2));
188 if (!!result)
189 s.send("ERROR", result);
190 else
191 s.send("OK", "Command successful");
192}
193
194
An IP+Port address also includes a port number, with the resulting form www.xxx.yyy....
This is a WvList of WvStrings, and is a really handy way to parse strings.
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
Class to easily create the Server side of a WvTCPConn.
WvString wvtcl_encode(WvList< WvString > &l, const WvStringMask &nasties=WVTCL_NASTY_SPACES, const WvStringMask &splitchars=WVTCL_SPLITCHARS)
encode a tcl-style list.
WvString wvtcl_escape(WvStringParm s, const WvStringMask &nasties=WVTCL_NASTY_SPACES)
tcl-escape a string.
void wvtcl_decode(WvList< WvString > &l, WvStringParm _s, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
split a tcl-style list.