// This file may be redistributed and modified only under the terms of // the GNU Lesser General Public License (See COPYING for details). // Copyright (C) 2000 Michael Day, Dmitry Derevyanko #include #include #include #include #include #define Debug(prg) { if (debug_flag) { prg } } static const bool debug_flag = false; static std::string get_line(std::string &s, char ch) { std::string out; int n = (int) s.find(ch); if(n > 0) { out.assign(s, 0, (unsigned long) n); s.erase(0, n+1UL); } return out; } static inline std::string get_line(std::string &s1, char ch, std::string &s2) { s2 = get_line(s1, ch); return s2; } namespace Atlas { namespace Net { NegotiateHelper::NegotiateHelper(std::list & names) : m_names(names) { } bool NegotiateHelper::get(std::string &buf, const std::string & header) { std::string s, h; while(!buf.empty()) { // check for end condition if(buf.find('\n') == 0) { buf.erase(0, 1); return true; } if(get_line(buf, '\n', s) == "") break; if(get_line(s, ' ', h) == header) { m_names.push_back(s); Debug( std::cout << " got: " << s << std::endl; ); } else Debug( std::cerr << "Unknown pattern " << h << std::endl; ); } return false; } void NegotiateHelper::put(std::string &buf, const std::string & header) { buf.erase(); buf += header; buf += " Packed\n"; buf += header; buf += " XML\n"; buf += header; buf += " Bach\n"; buf += header; buf += " Gzip\n"; buf += header; buf += " Bzip2\n"; buf += "\n"; } StreamConnect::StreamConnect(const std::string& name, std::iostream& s) : m_state(SERVER_GREETING), m_outName(name), m_socket(s), m_codecHelper(m_inCodecs), m_filterHelper(m_inFilters), m_canPacked(true), m_canXML(true), m_canBach(true),m_canGzip(true), m_canBzip2(true) { } StreamConnect::~StreamConnect() { } void StreamConnect::poll(bool can_read) { Debug( std::cout << "** Client(" << m_state << ") : " << m_socket.rdbuf()->in_avail() << std::endl; ); std::string out; if (can_read) { // Cause the stream to read from its socket m_socket.peek(); } std::streamsize count; while ((count = m_socket.rdbuf()->in_avail()) > 0) { for (int i = 0 ; i < count; ++i) { m_buf += (char) m_socket.rdbuf()->sbumpc(); } } if(m_state == SERVER_GREETING) { // get server greeting if (m_buf.size() > 0 && get_line(m_buf, '\n', m_inName) != "") { Debug( std::cout << "server: " << m_inName << std::endl; ); m_state = CLIENT_GREETING; } } if(m_state == CLIENT_GREETING) { // send client greeting m_socket << "ATLAS " << m_outName << std::endl; m_state = CLIENT_CODECS; } if (m_state == CLIENT_CODECS) { //processClientCodecs(); m_codecHelper.put(out, "ICAN"); m_socket << out << std::flush; m_state = SERVER_CODECS; } if(m_state == SERVER_CODECS) { if (m_codecHelper.get(m_buf, "IWILL")) { processServerCodecs(); m_state = DONE; } } #if 0 if (m_state == CLIENT_FILTERS) { //processClientFilters(); m_filterHelper.put(out, "ICAN"); m_socket << out << std::flush; m_state++; } if (m_state == SERVER_FILTERS) { if (m_filterHelper.get(m_buf, "IWILL")) { processServerFilters(); m_state++; } } #endif } Atlas::Negotiate::State StreamConnect::getState() { if (m_state == DONE) { if (m_canPacked || m_canXML || m_canBach) { return SUCCEEDED; } } else if (m_socket) { return IN_PROGRESS; } return FAILED; } /// FIXME We should pass in the Bridge here, not at construction time. Atlas::Codec * StreamConnect::getCodec(Atlas::Bridge & bridge) { if (m_canPacked) { return new Atlas::Codecs::Packed(m_socket, bridge); } if (m_canXML) { return new Atlas::Codecs::XML(m_socket, bridge); } if (m_canBach) { return new Atlas::Codecs::Bach(m_socket, bridge); } return NULL; } void StreamConnect::processServerCodecs() { std::list::iterator j; for (j = m_inFilters.begin(); j != m_inFilters.end(); ++j) { if (*j == "XML") { m_canXML = true; } if (*j == "Packed") { m_canPacked = true; } if (*j == "Bach") { m_canBach = true; } } } void StreamConnect::processServerFilters() { std::list::iterator j; for (j = m_inFilters.begin(); j != m_inFilters.end(); ++j) { if (*j == "Gzip") { m_canGzip = true; } if (*j == "Bzip2") { m_canBzip2 = true; } } } #if 0 void StreamConnect::processClientCodecs() { std::list::const_iterator j; for (j = m_inCodecs.begin(); j != m_inCodecs.end(); j++) { // Do what? } } void StreamConnect::processClientFilters() { std::list::const_iterator j; for (j = m_inFilters.begin(); j != m_inFilters.end(); j++) { // Do what? } } #endif StreamAccept::~StreamAccept() { } StreamAccept::StreamAccept(const std::string& name, std::iostream& s) : m_state(SERVER_GREETING), m_outName(name), m_socket(s), m_codecHelper(m_inCodecs), m_filterHelper(m_inFilters), m_canPacked(false), m_canXML(false), m_canGzip(false), m_canBzip2(false) { } void StreamAccept::poll(bool can_read) { Debug( std::cout << "** Server(" << m_state << ") : " << std::endl; ); std::string out; if (m_state == SERVER_GREETING) { // send server greeting m_socket << "ATLAS " << m_outName << std::endl; m_state = CLIENT_GREETING; Debug( std::cout << "server now in state " << m_state << std::endl; ); } if (can_read) { // Cause the stream to read from its socket m_socket.peek(); } std::streamsize count; while ((count = m_socket.rdbuf()->in_avail()) > 0) { for (int i = 0 ; i < count; ++i) { m_buf += (char) m_socket.rdbuf()->sbumpc(); } } if (m_state == CLIENT_GREETING) { // get client greeting if (m_buf.size() > 0 && get_line(m_buf, '\n', m_inName) != "") { Debug(std::cout << "client: " << m_inName << std::endl; ); m_state = CLIENT_CODECS; } } if (m_state == CLIENT_CODECS) { if (m_codecHelper.get(m_buf, "ICAN")) { m_state = SERVER_CODECS; Debug(std::cout << "server now in state " << m_state << std::endl;); } processClientCodecs(); } if (m_state == SERVER_CODECS) { if (m_canPacked) { m_socket << "IWILL Packed\n"; } else if (m_canXML) { m_socket << "IWILL XML\n"; } else if (m_canBach) { m_socket << "IWILL Bach\n"; } m_socket << std::endl; m_state = DONE; } #if 0 if(m_state == CLIENT_FILTERS) { if (m_filterHelper.get(m_buf, "ICAN")) { m_state++; } processClientFilters(); } if (m_state == SERVER_FILTERS) { //No Filters until they actually work. //if (m_canGzip) { m_socket << "IWILL Gzip\n"; } //else if (m_canBzip2) { m_socket << "IWILL Bzip2\n"; } m_socket << std::endl; m_state++; } #endif } Atlas::Negotiate::State StreamAccept::getState() { if (m_state == DONE) { if (m_canPacked || m_canXML || m_canBach) { return SUCCEEDED; } std::cout << "done, but no codec" << std::endl; } else if (m_socket) { return IN_PROGRESS; } return FAILED; } /// FIXME We should pass in the Bridge here, not at construction time. Atlas::Codec * StreamAccept::getCodec(Atlas::Bridge & bridge) { // XXX XXX XXX XXX // should pass an appropriate filterbuf here instead of socket, // if we found a filter of course. // this poses the problem of the filter being passed by // reference, so we'd have to allocate on the heap, but then who // would deallocate? erk. -- sdt 2001-01-05 //return (*outCodecs.begin())-> //New(Codec::Parameters(m_socket,bridge)); if (m_canPacked) { return new Atlas::Codecs::Packed(m_socket, bridge); } if (m_canXML) { return new Atlas::Codecs::XML(m_socket, bridge); } if (m_canBach) { return new Atlas::Codecs::Bach(m_socket, bridge); } return NULL; } #if 0 void StreamAccept::processServerCodecs() { FactoryCodecs::iterator i; list::iterator j; FactoryCodecs *myCodecs = Factory >::factories(); for (i = myCodecs->begin(); i != myCodecs->end(); ++i) { for (j = m_inCodecs.begin(); j != m_inCodecs.end(); ++j) { if ((*i)->getName() == *j) { outCodecs.push_back(*i); return; } } } } void StreamAccept::processServerFilters() { FactoryFilters::iterator i; list::iterator j; FactoryFilters *myFilters = Factory::factories(); for (i = myFilters->begin(); i != myFilters->end(); ++i) { for (j = m_inFilters.begin(); j != m_inFilters.end(); ++j) { if ((*i)->getName() == *j) { outFilters.push_back(*i); } } } } #endif void StreamAccept::processClientCodecs() { std::list::const_iterator j; for (j = m_inCodecs.begin(); j != m_inCodecs.end(); j++) { if (*j == "XML") { m_canXML = true; } if (*j == "Packed") { m_canPacked = true; } if (*j == "Bach") { m_canBach = true; } } } void StreamAccept::processClientFilters() { std::list::const_iterator j; for (j = m_inFilters.begin(); j != m_inFilters.end(); j++) { if (*j == "Gzip") { m_canGzip = true; } if (*j == "Bzip2") { m_canBzip2 = true; } } } } } // namespace Atlas Net