WvStreams
wvprotostream.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * WvProtoStream is a framework that makes it easy to communicate using
6 * common command-response driven protocols. This is supposed to be flexible
7 * enough to handle FTP, HTTP, SMTP, tunnelv, Weaver rcmd, and many others.
8 */
9#include "wvprotostream.h"
10#include "wvlog.h"
11#include "strutils.h"
12#include <ctype.h>
13#include <assert.h>
14
15
16WvProtoStream::WvProtoStream(WvStream *_cloned, WvLog *_debuglog)
17 : WvStreamClone(_cloned)
18{
19 if (_debuglog)
20 logp = new WvLog(_debuglog->split(WvLog::Debug4));
21 else
22 logp = NULL;
23
24 log_enable = true;
25 state = 0;
26}
27
28
29WvProtoStream::~WvProtoStream()
30{
31 close();
32 WVRELEASE(logp);
33}
34
35
36/* Just like a WvStream::uwrite(), but it copies all output to WvLog if
37 * log_enable==true.
38 */
39size_t WvProtoStream::uwrite(const void *buf, size_t size)
40{
41 if (logp && log_enable)
42 {
43 (*logp)("Sent: ");
44 logp->write(buf, size);
45 (*logp)("\n");
46 }
47
48 return WvStreamClone::uwrite(buf, size);
49}
50
51
52WvProtoStream::Token *WvProtoStream::next_token()
53{
54 static unsigned char whitespace[] = " \t\r\n";
55 size_t len;
56
57 // find and remove up to first non-whitespace
58 tokbuf.get(tokbuf.match(whitespace, sizeof(whitespace)));
59
60 // return a token up to the first whitespace character
61 len = tokbuf.notmatch(whitespace, sizeof(whitespace));
62 return len ? new Token(tokbuf.get(len), len) : NULL;
63}
64
65
66WvString WvProtoStream::next_token_str()
67{
68 Token *t = next_token();
69 if (!t) return WvString("");
70
71 WvString s(t->data);
72 delete t;
73 return s;
74}
75
76
77WvString WvProtoStream::token_remaining()
78{
79 tokbuf.put('\0');
80 return trim_string((char *)tokbuf.get(tokbuf.used()));
81}
82
83
84/* Default input tokenizer. "line" is NULL-terminated, and individual string
85 * tokens are separated by any amount of whitespace.
86 */
87WvProtoStream::TokenList *WvProtoStream::tokenize()
88{
89 TokenList *tl = new TokenList;
90 Token *t;
91
92 while ((t = next_token()) != NULL)
93 tl->append(t, true);
94#if 0
95 if (logp && log_enable && !tl->isempty())
96 {
97 (*logp)("Read: ");
98 TokenList::Iter i(*tl);
99 for (i.rewind(); i.next(); )
100 (*logp)("(%s) ", i.data);
101 (*logp)("\n");
102 }
103#endif
104 return tl;
105}
106
107
108/* convert a TokenList to an array of Token.
109 * The TokenList becomes invalid after this operation!
110 * Remember to free the array afterwards!
111 */
112size_t WvProtoStream::list_to_array(TokenList *tl, Token **array)
113{
114 size_t total = tl->count(), count;
115
116 assert(array);
117 *array = new Token[total];
118
119 TokenList::Iter i(*tl);
120 for (count = 0, i.rewind(); i.next(); count++)
121 {
122 Token &t = *i;
123 (*array)[count].fill((unsigned char *)(const char *)t.data, t.length);
124 }
125
126 delete tl;
127 return count;
128}
129
130
131/* Retrieve an input line and parse its first token.
132 * This is the usual high-level interface to the input tokenizer. Remember
133 * to free the array afterwards!
134 * Ths input line is specifically allowed to be a NULL pointer. In that case,
135 * the returned token will be NULL also.
136 */
137WvProtoStream::Token *WvProtoStream::tokline(const char *line)
138{
139 if (!line) return NULL;
140
141 char *newline = strdup(line);
142
143 tokbuf.zap();
144 tokbuf.put(line, strlen(line));
145
146 if (logp && log_enable)
147 {
148 if (strlen(trim_string(newline)) > 0)
149 (*logp)("Read: %s\n", trim_string(newline));
150 }
151
152 free(newline);
153
154 return next_token();
155}
156
157
158/* returns -1 if t is not in lookup[], or else the index into lookup where
159 * the token was found.
160 */
161int WvProtoStream::tokanal(const Token &t, const char **lookup,
162 bool case_sensitive)
163{
164 assert(lookup);
165
166 const char **i;
167
168 for (i = lookup; *i; i++)
169 {
170 if ( (!case_sensitive && !strcasecmp(t.data, *i))
171 || ( case_sensitive && !strcmp(t.data, *i)) )
172 return i - lookup;
173 }
174
175 return -1;
176}
177
178
179void WvProtoStream::do_state(Token &)
180{
181}
182
183
184void WvProtoStream::switch_state(int newstate)
185{
186 state = newstate;
187}
188
189
190/* Default execute() function -- process a line of input, and handle it
191 * (based on the current system state) using do_state().
192 */
194{
196
197 Token *t1 = tokline(getline());
198
199 if (t1)
200 {
201 do_state(*t1);
202 delete t1;
203 }
204}
205
206
207
209
210
211
212WvProtoStream::Token::Token()
213{
214 // leave empty -- you should call fill() manually later!
215}
216
217
218WvProtoStream::Token::Token(const unsigned char *_data, size_t _length)
219{
220 fill(_data, _length);
221}
222
223
224void WvProtoStream::Token::fill(const unsigned char *_data,
225 size_t _length)
226{
227 length = _length;
228
229 data.setsize(length + 1);
230 memcpy(data.edit(), _data, length);
231 data.edit()[length] = 0;
232}
233
234
235WvProtoStream::Token::~Token()
236{
237 // 'data' member is freed automatically
238}
const T * get(size_t count)
Reads exactly the specified number of elements and returns a pointer to a storage location owned by t...
Definition: wvbufbase.h:114
void zap()
Clears the buffer.
Definition: wvbufbase.h:257
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
size_t notmatch(const void *bytelist, size_t numbytes)
Returns the number of leading buffer elements that do not match any of those in the list.
Definition: wvbuf.h:125
size_t match(const void *bytelist, size_t numbytes)
Returns the number of leading buffer elements that match any of those in the list.
Definition: wvbuf.h:106
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
Definition: wvlog.h:57
WvLog split(LogLevel _loglevel) const
split off a new WvLog object with the requested loglevel.
Definition: wvlog.h:142
virtual void execute()
pass input through to the state machine, one line at a time
virtual size_t uwrite(const void *buffer, size_t size)
override uwrite() so we can log all output
int tokanal(const Token &t, const char **lookup, bool case_sensitive=false)
Convert token strings to enum values.
WvStreamClone simply forwards all requests to the "cloned" stream.
Definition: wvstreamclone.h:24
virtual void close()
Close this stream.
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
virtual size_t uwrite(const void *buf, size_t size)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:25
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
Definition: wvstream.cc:532
char * getline(time_t wait_msec=0, char separator='\n', int readahead=1024)
Read up to one line of data from the stream and return a pointer to the internal buffer containing th...
Definition: wvstream.h:175
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330
int lookup(const char *str, const char *const *table, bool case_sensitive=false)
Finds a string in an array and returns its index.
Definition: strutils.cc:850
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition: strutils.cc:59