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 put(const T *data, size_t count)
Writes the specified number of elements from the specified storage location into the buffer at its ta...
Definition wvbufbase.h:483
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
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.
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