Atlas  0.7.0
Networking protocol for the Worldforge system.
Stream.cpp
1 // This file may be redistributed and modified only under the terms of
2 // the GNU Lesser General Public License (See COPYING for details).
3 // Copyright (C) 2000 Michael Day, Dmitry Derevyanko
4 
5 // $Id$
6 
7 #include <Atlas/Net/Stream.h>
8 
9 #include <Atlas/Codecs/XML.h>
10 #include <Atlas/Codecs/Packed.h>
11 #include <Atlas/Codecs/Bach.h>
12 
13 #include <iostream>
14 #include <memory>
15 
16 #define Debug(prg) { if (debug_flag) { prg } }
17 
18 static const bool debug_flag = false;
19 
20 static std::string get_line(std::string &s, char ch)
21 {
22  std::string out;
23  int n = (int) s.find(ch);
24  if(n > 0)
25  {
26  out.assign(s, 0, (unsigned long) n);
27  s.erase(0, n+1UL);
28  }
29 
30  return out;
31 }
32 
33 static inline std::string get_line(std::string &s1, char ch, std::string &s2)
34 {
35  s2 = get_line(s1, ch);
36 
37  return s2;
38 }
39 
40 namespace Atlas { namespace Net {
41 
42 NegotiateHelper::NegotiateHelper(std::list<std::string> & names) :
43  m_names(names)
44 {
45 }
46 
47 bool NegotiateHelper::get(std::string &buf, const std::string & header)
48 {
49  std::string s, h;
50 
51  while(!buf.empty())
52  {
53  // check for end condition
54  if(buf.find('\n') == 0)
55  {
56  buf.erase(0, 1);
57  return true;
58  }
59 
60  if(get_line(buf, '\n', s).empty())
61  break;
62 
63  if(get_line(s, ' ', h) == header)
64  {
65  m_names.push_back(s);
66 
67  Debug( std::cout << " got: " << s << std::endl; )
68  }
69  else
70  Debug( std::cerr << "Unknown pattern " << h << std::endl; )
71  }
72  return false;
73 }
74 
75 void NegotiateHelper::put(std::string &buf, const std::string & header)
76 {
77  buf.erase();
78 
79  buf += header;
80  buf += " Packed\n";
81 
82  buf += header;
83  buf += " XML\n";
84 
85  buf += header;
86  buf += " Bach\n";
87 
88  buf += header;
89  buf += " Gzip\n";
90 
91  buf += header;
92  buf += " Bzip2\n";
93 
94  buf += "\n";
95 }
96 
97 StreamConnect::StreamConnect(std::string name, std::istream& inStream, std::ostream& outStream) :
98  m_state(SERVER_GREETING), m_outName(std::move(name)), m_inStream(inStream), m_outStream(outStream),
99  m_codecHelper(m_inCodecs), m_filterHelper(m_inFilters),
100  m_canPacked(true), m_canXML(true), m_canBach(true),m_canGzip(true), m_canBzip2(true)
101 {
102 }
103 
104 void StreamConnect::poll()
105 {
106  Debug( std::cout << "** Client(" << m_state << ") : " << m_inStream.rdbuf()->in_avail() << std::endl; )
107 
108  std::string out;
109 
110  std::streamsize count;
111  while ((count = m_inStream.rdbuf()->in_avail()) > 0) {
112  for (int i = 0 ; i < count; ++i) {
113  m_buf += (char) m_inStream.rdbuf()->sbumpc();
114  }
115  }
116 
117  if(m_state == SERVER_GREETING)
118  {
119  // get server greeting
120 
121  if (!m_buf.empty() && !get_line(m_buf, '\n', m_inName).empty())
122  {
123  Debug( std::cout << "server: " << m_inName << std::endl; )
124  m_state = CLIENT_GREETING;
125  }
126  }
127 
128  if(m_state == CLIENT_GREETING)
129  {
130  // send client greeting
131 
132  m_outStream << "ATLAS " << m_outName << std::endl;
133  m_state = CLIENT_CODECS;
134  }
135 
136  if (m_state == CLIENT_CODECS)
137  {
138  //processClientCodecs();
139  m_codecHelper.put(out, "ICAN");
140  m_outStream << out << std::flush;
141  m_state = SERVER_CODECS;
142  }
143 
144  if(m_state == SERVER_CODECS)
145  {
146  if (m_codecHelper.get(m_buf, "IWILL"))
147  {
148  processServerCodecs();
149  m_state = DONE;
150  }
151  }
152 
153 #if 0
154  if (m_state == CLIENT_FILTERS)
155  {
156  //processClientFilters();
157  m_filterHelper.put(out, "ICAN");
158  m_socket << out << std::flush;
159  m_state++;
160  }
161 
162  if (m_state == SERVER_FILTERS)
163  {
164  if (m_filterHelper.get(m_buf, "IWILL"))
165  {
166  processServerFilters();
167  m_state++;
168  }
169  }
170 #endif
171 }
172 
173 Atlas::Negotiate::State StreamConnect::getState()
174 {
175  if (m_state == DONE)
176  {
177  if (m_canPacked || m_canXML || m_canBach)
178  {
179  return SUCCEEDED;
180  }
181  }
182  else if (m_inStream || m_outStream)
183  {
184  return IN_PROGRESS;
185  }
186  return FAILED;
187 }
188 
190 std::unique_ptr<Atlas::Codec> StreamConnect::getCodec(Atlas::Bridge & bridge)
191 {
192  if (m_canPacked) { return std::make_unique<Atlas::Codecs::Packed>(m_inStream, m_outStream, bridge); }
193  if (m_canXML) { return std::make_unique<Atlas::Codecs::XML>(m_inStream, m_outStream, bridge); }
194  if (m_canBach) { return std::make_unique<Atlas::Codecs::Bach>(m_inStream, m_outStream, bridge); }
195  return {};
196 }
197 
198 void StreamConnect::processServerCodecs()
199 {
200  for (auto& codec : m_inCodecs)
201  {
202  if (codec == "XML") { m_canXML = true; }
203  if (codec == "Packed") { m_canPacked = true; }
204  if (codec == "Bach") { m_canBach = true; }
205  }
206 }
207 
208 void StreamConnect::processServerFilters()
209 {
210  for (auto& filter : m_inFilters)
211  {
212  if (filter == "Gzip") { m_canGzip = true; }
213  if (filter == "Bzip2") { m_canBzip2 = true; }
214  }
215 }
216 
217 #if 0
218 void StreamConnect::processClientCodecs()
219 {
220  std::list<std::string>::const_iterator j;
221 
222  for (j = m_inCodecs.begin(); j != m_inCodecs.end(); ++j)
223  {
224  // Do what?
225  }
226 }
227 
228 void StreamConnect::processClientFilters()
229 {
230  std::list<std::string>::const_iterator j;
231 
232  for (j = m_inFilters.begin(); j != m_inFilters.end(); ++j)
233  {
234  // Do what?
235  }
236 }
237 #endif
238 
239 
240 StreamAccept::StreamAccept(std::string name, std::istream& inStream, std::ostream& outStream) :
241  m_state(SERVER_GREETING),
242  m_outName(std::move(name)),
243  m_inStream(inStream),
244  m_outStream(outStream),
245  m_codecHelper(m_inCodecs),
246  m_filterHelper(m_inFilters),
247  m_canPacked(false),
248  m_canXML(false),
249  m_canBach(false),
250  m_canGzip(false),
251  m_canBzip2(false)
252 {
253 }
254 
255 void StreamAccept::poll()
256 {
257  Debug( std::cout << "** Server(" << m_state << ") : " << std::endl; )
258 
259  if (m_state == SERVER_GREETING)
260  {
261  // send server greeting
262 
263  m_outStream << "ATLAS " << m_outName << std::endl;
264  m_state = CLIENT_GREETING;
265  Debug( std::cout << "server now in state " << m_state << std::endl; )
266  }
267 
268  std::streamsize count;
269  while ((count = m_inStream.rdbuf()->in_avail()) > 0) {
270  for (int i = 0 ; i < count; ++i) {
271  m_buf += (char) m_inStream.rdbuf()->sbumpc();
272  }
273  }
274 
275  if (m_state == CLIENT_GREETING)
276  {
277  // get client greeting
278  if (!m_buf.empty() && !get_line(m_buf, '\n', m_inName).empty())
279  {
280  Debug(std::cout << "client: " << m_inName << std::endl; )
281  m_state = CLIENT_CODECS;
282  }
283  }
284 
285  if (m_state == CLIENT_CODECS)
286  {
287  if (m_codecHelper.get(m_buf, "ICAN"))
288  {
289  m_state = SERVER_CODECS;
290  Debug(std::cout << "server now in state " << m_state << std::endl;)
291  }
292  processClientCodecs();
293  }
294 
295  if (m_state == SERVER_CODECS)
296  {
297  if (m_canPacked) { m_outStream << "IWILL Packed\n"; }
298  else if (m_canXML) { m_outStream << "IWILL XML\n"; }
299  else if (m_canBach) { m_outStream << "IWILL Bach\n"; }
300  m_outStream << std::endl;
301 
302  m_state = DONE;
303  }
304 
305 #if 0
306  if(m_state == CLIENT_FILTERS)
307  {
308  if (m_filterHelper.get(m_buf, "ICAN"))
309  {
310  m_state++;
311  }
312  processClientFilters();
313  }
314 
315  if (m_state == SERVER_FILTERS)
316  {
317  //No Filters until they actually work.
318  //if (m_canGzip) { m_socket << "IWILL Gzip\n"; }
319  //else if (m_canBzip2) { m_socket << "IWILL Bzip2\n"; }
320  m_outStream << std::endl;
321  m_state++;
322  }
323 #endif
324 }
325 
326 Atlas::Negotiate::State StreamAccept::getState()
327 {
328  if (m_state == DONE)
329  {
330  if (m_canPacked || m_canXML || m_canBach)
331  {
332  return SUCCEEDED;
333  }
334 
335  std::cout << "done, but no codec" << std::endl;
336  }
337  else if (m_inStream || m_outStream)
338  {
339  return IN_PROGRESS;
340  }
341  return FAILED;
342 }
343 
345 std::unique_ptr<Atlas::Codec> StreamAccept::getCodec(Atlas::Bridge & bridge)
346 {
347  // XXX XXX XXX XXX
348  // should pass an appropriate filterbuf here instead of socket,
349  // if we found a filter of course.
350  // this poses the problem of the filter being passed by
351  // reference, so we'd have to allocate on the heap, but then who
352  // would deallocate? erk. -- sdt 2001-01-05
353  //return (*outCodecs.begin())->
354  //New(Codec<std::iostream>::Parameters(m_socket,bridge));
355  if (m_canPacked) { return std::make_unique<Atlas::Codecs::Packed>(m_inStream, m_outStream, bridge); }
356  if (m_canXML) { return std::make_unique<Atlas::Codecs::XML>(m_inStream, m_outStream, bridge); }
357  if (m_canBach) { return std::make_unique<Atlas::Codecs::Bach>(m_inStream, m_outStream, bridge); }
358  return nullptr;
359 }
360 
361 #if 0
362 void StreamAccept::processServerCodecs()
363 {
364  FactoryCodecs::iterator i;
365  list<std::string>::iterator j;
366 
367  FactoryCodecs *myCodecs = Factory<Codec<std::iostream> >::factories();
368 
369  for (i = myCodecs->begin(); i != myCodecs->end(); ++i)
370  {
371  for (j = m_inCodecs.begin(); j != m_inCodecs.end(); ++j)
372  {
373  if ((*i)->getName() == *j)
374  {
375  outCodecs.push_back(*i);
376  return;
377  }
378  }
379  }
380 }
381 
382 void StreamAccept::processServerFilters()
383 {
384  FactoryFilters::iterator i;
385  list<std::string>::iterator j;
386 
387  FactoryFilters *myFilters = Factory<Filter>::factories();
388 
389  for (i = myFilters->begin(); i != myFilters->end(); ++i)
390  {
391  for (j = m_inFilters.begin(); j != m_inFilters.end(); ++j)
392  {
393  if ((*i)->getName() == *j)
394  {
395  outFilters.push_back(*i);
396  }
397  }
398  }
399 }
400 #endif
401 
402 void StreamAccept::processClientCodecs()
403 {
404  for (auto& codec : m_inCodecs)
405  {
406  if (codec == "XML") { m_canXML = true; }
407  if (codec == "Packed") { m_canPacked = true; }
408  if (codec == "Bach") { m_canBach = true; }
409  }
410 }
411 
412 void StreamAccept::processClientFilters()
413 {
414  for (auto& filter : m_inFilters)
415  {
416  if (filter == "Gzip") { m_canGzip = true; }
417  if (filter == "Bzip2") { m_canBzip2 = true; }
418  }
419 }
420 
421 } } // namespace Atlas Net
STL namespace.
Definition: Bridge.h:20