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 
16 WvProtoStream::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 
29 WvProtoStream::~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  */
39 size_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 
52 WvProtoStream::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 
66 WvString 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 
77 WvString 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  */
87 WvProtoStream::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  */
112 size_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  */
137 WvProtoStream::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  */
161 int 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 
179 void WvProtoStream::do_state(Token &)
180 {
181 }
182 
183 
184 void 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 
212 WvProtoStream::Token::Token()
213 {
214  // leave empty -- you should call fill() manually later!
215 }
216 
217 
218 WvProtoStream::Token::Token(const unsigned char *_data, size_t _length)
219 {
220  fill(_data, _length);
221 }
222 
223 
224 void 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 
235 WvProtoStream::Token::~Token()
236 {
237  // 'data' member is freed automatically
238 }
WvBufBaseCommonImpl::get
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
WvStream::write
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
Definition: wvstream.cc:532
lookup
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
WvStreamClone::execute
virtual void execute()
The callback() function calls execute(), and then calls the user- specified callback if one is define...
Definition: wvstreamclone.cc:272
WvStreamClone::close
virtual void close()
Close this stream.
Definition: wvstreamclone.cc:83
WvProtoStream::execute
virtual void execute()
pass input through to the state machine, one line at a time
Definition: wvprotostream.cc:193
WvProtoStream::Token
Definition: wvprotostream.h:22
WvStreamClone::uwrite
virtual size_t uwrite(const void *buf, size_t size)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
Definition: wvstreamclone.cc:125
trim_string
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition: strutils.cc:59
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvLog
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
Definition: wvlog.h:56
WvProtoStream::tokanal
int tokanal(const Token &t, const char **lookup, bool case_sensitive=false)
Convert token strings to enum values.
Definition: wvprotostream.cc:161
WvStream::getline
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
WvStreamClone
WvStreamClone simply forwards all requests to the "cloned" stream.
Definition: wvstreamclone.h:23
WvBufBaseCommonImpl::zap
void zap()
Clears the buffer.
Definition: wvbufbase.h:257
WvBufBase< unsigned char >::notmatch
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
WvProtoStream::uwrite
virtual size_t uwrite(const void *buffer, size_t size)
override uwrite() so we can log all output
Definition: wvprotostream.cc:39
WvStream
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:24
WvLog::split
WvLog split(LogLevel _loglevel) const
split off a new WvLog object with the requested loglevel.
Definition: wvlog.h:142
WvBufBaseCommonImpl::used
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
WvBufBase< unsigned char >::match
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