ircproxy  The Ultimate Cyborg

ServerSession Class Reference

#include <ServerSession.h>

Inheritance diagram for ServerSession:

Index< ServerSession > IdentityReference

List of all members.


Detailed Description

A server session, from connect till disconnect.

This class represents a server session: from that we successfully connect to a server until the connection is closed or lost again.

Definition at line 47 of file ServerSession.h.


Public Types

typedef target_hold_map_type joined_channels_type
 The type of M_joined_channels.
typedef std::map< std::string,
boost::shared_ptr< Channel > > 
join_pipeline_type
 The type of M_join_pipeline.

Public Member Functions

 ServerSession (Identity &identity, ServerConnection &server_connection)
 Construct a ServerSession instance for identity identity and server connection server_connection.
 ~ServerSession ()
 Destructor.
void start_authentication (void)
 Called from ServerConnection::do_connect. Takes care of sending PASS/NICK/USER/PONG/MODE.
void set_auth_ping_argument (std::string const &auth_ping_argument)
 Called from ServerConnection::decode_ping with the argument of the first PING.
std::string const & auth_ping_argument (void) const
 Return argument of the first PING.
void construct_network_object (std::string const &network_name, std::string const &domain)
 Create a new network object with name network_name and domain domain (if any).
void detected_network (networks_type::iterator network_iter)
 Initialize network. This function is called as soon as the network we are connected to is known.
void authentication_successful (void)
 Called when the authentication was successful (when receiving the 001 numeric).
void fatal_error (char const *error_msg)
 A fatal error occured. Calling this function will terminate the ServerSession.
void found_network_name (void)
 Called when the name of the Network is known (after numeric 005).
MatcherEventServermessage_event_server (void)
 Return a reference to the event server for incoming messages.
MatcherEventServer const & message_event_server (void) const
 Return a const reference to the event server for incoming messages.
NickPairnicks (void)
 Server session nick pair.
NickPair const & nicks (void) const
 Server session nick pair.
joined_channels_typejoined_channels (void)
 Return reference to map with joined channels.
joined_channels_type const & joined_channels (void) const
 Return const reference to map with joined channels.
UserModeuser_mode (void)
 Return my user mode.
UserMode const & user_mode (void) const
 Return my user mode.
void queue_msg (MessageOut const &msg)
 Queue message msg.
void queue_msg_as_is (ClientMessageIn const &msg)
 Queue message msg with default priority without changing it.
WhoRequest current_who_request (void)
 Return the first element of M_who_queue.
void pop_who_request (void)
 Pop the first element of M_who_queue.
void send_nick_write_event (PseudoMessageEventType const &, std::string nick)
 A write event of a pseudo NICK message happened. Actually write the NICK message.
void send_who_write_event (PseudoMessageEventType const &event_type, WhoRequest who_request)
 A write event of a pseudo WHO message happened. Actually write the WHO message.
void force_quit (timer_event_type_ct const &)
 Called 1 second after sending a QUIT and the connection still wasn't terminated.
ISupport const & i_support (void) const
 Accessor for M_i_support.
ISupporti_support (void)
 Accessor for M_i_support.
boost::shared_ptr< Channeljoin_pipeline (std::string const &channel_name)
 Return a pointer to the channel in the pipeline, if any. Channel is removed from pipeline.
void set_disconnect_reason (std::string const &disconnect_reason)
 Set the disconnect reason to disconnect_reason.
ServerConnectionserver_connection (void) const
 Accessor for underlying server connection object.
boost::shared_ptr< Nickget_nick (std::string const &nick_name, bool create=false)
 Get or create a Nick for nick_name.

Public Attributes

Bool M_detected_network
 True if the network is fully detected.

Protected Member Functions

virtual void new_message_received (ServerMessageIn const &)
 Incoming event from ServerSessionInput.
virtual void network_connection_terminated (void)
 A read(2) on the socket returned 0.

Private Member Functions

void send_rejoins (void)
 Send a JOIN to the server for every channel we are on.

Private Attributes

ServerConnectionM_server_connection
 The owning object.
MatcherEventServer M_message_event_server
 Event server for incoming messages.
NickPair M_server_session_nicks
 Server side nick pair.
joined_channels_type M_joined_channels
 Serverside lookup map for channels joined by this identity.
UserMode M_user_mode
 My user mode.
boost::shared_ptr< AuthStateM_auth_state
 Pointer object with temporary authentication state information.
Queue M_output_queue
 Queue for output messages.
std::queue< WhoRequestM_who_queue
 Queue storing WHO request messages.
ISupport M_i_support
 Object that stores the numeric 005 information.
std::string M_network_name
 Temporary storage of the network name as decoded from numeric 001, until numeric 005 is received.
std::string M_umodes
 The user modes as received in numeric 004.
join_pipeline_type M_join_pipeline
 Channels for which we sent a JOIN as part of a reconnect.
std::string M_disconnect_reason
 An error message that should be sent to the client if the connection is lost, if any.

Static Private Attributes

static int S_server_sessions = 0
 Total number of server session objects.

Member Typedef Documentation

The type of M_joined_channels.

Definition at line 49 of file ServerSession.h.

typedef std::map<std::string, boost::shared_ptr<Channel> > ServerSession::join_pipeline_type

The type of M_join_pipeline.

Definition at line 50 of file ServerSession.h.


Constructor & Destructor Documentation

ServerSession::ServerSession ( Identity identity,
ServerConnection server_connection 
) [inline]

Construct a ServerSession instance for identity identity and server connection server_connection.

Definition at line 73 of file ServerSession.h.

References debug::channels::dc::objects, and S_server_sessions.

00073                                                                            :
00074         IdentityReference(&identity), M_server_connection(server_connection),
00075         M_server_session_nicks(*this), M_output_queue(server_connection, 0.5, 5, 5),
00076         M_i_support(server_connection)
00077 #ifdef CWDEBUG
00078       , M_detected_network("M_detected_network")
00079 #endif
00080         {
00081           Dout(dc::objects, "Constructing ServerSession(" << identity << ", " << server_connection << ")");
00082           ++S_server_sessions;
00083         }
    //! Destructor.

ServerSession::~ServerSession (  ) 

Destructor.

Definition at line 334 of file ServerSession.cc.

References M_server_connection, debug::channels::dc::objects, ServerConnection::reconnect(), S_server_sessions, ServerConnection::secondary_connection(), and ServerConnection::session_lost().

00335 {
00336 #ifdef CWDEBUG
00337   debug::SecondaryConnection dummy(M_server_connection.secondary_connection());
00338 #endif
00339   Dout(dc::objects, "Destructing ServerSession" << *this);
00340   M_server_connection.session_lost();
00341   cancel_all_requests();
00342   // Notify the application when the last server session is terminated.
00343   if (--S_server_sessions == 0 && !M_server_connection.reconnect())
00344     Application::instance().last_server_session_destroyed();
00345 }


Member Function Documentation

void ServerSession::start_authentication ( void   ) 

Called from ServerConnection::do_connect. Takes care of sending PASS/NICK/USER/PONG/MODE.

Definition at line 322 of file ServerSession.cc.

References M_auth_state, and M_server_connection.

Referenced by ServerConnection::do_connect().

00323 {
00324   M_auth_state.reset(NEW(AuthState(M_server_connection)));
00325 }

void ServerSession::set_auth_ping_argument ( std::string const &  auth_ping_argument  )  [inline]

Called from ServerConnection::decode_ping with the argument of the first PING.

Definition at line 91 of file ServerSession.h.

References M_auth_state.

Referenced by ServerConnection::decode_ping().

00091 { if (M_auth_state.get()) M_auth_state->set_auth_ping_argument(auth_ping_argument); }

std::string const& ServerSession::auth_ping_argument ( void   )  const [inline]

Return argument of the first PING.

Definition at line 94 of file ServerSession.h.

References ASSERT, and M_auth_state.

Referenced by ServerConnection::send_pong_and_mode().

00094 { ASSERT(M_auth_state.get()); return M_auth_state->auth_ping_argument(); }

void ServerSession::construct_network_object ( std::string const &  network_name,
std::string const &  domain 
)

Create a new network object with name network_name and domain domain (if any).

Definition at line 442 of file ServerSession.cc.

References detected_network(), IdentityReference::identity(), network_domain_question, and Identity::send_notice().

Referenced by found_network_name(), and Identity::received_network_domain_answer().

00443 {
00444   networks_type& networks = Application::instance().networks();
00445   networks_type::iterator iter;
00446   std::ostringstream buf;
00447   buf << "Added NEW network: \"" << network_name << "\"";
00448   if (domain.empty())
00449   {
00450     iter = networks.insert(networks.end(), Network(network_name));
00451     buf << '.';
00452   }
00453   else
00454   {
00455     iter = networks.insert(networks.end(), Network(network_name, domain));
00456     buf << ", with common domain \"" << domain << "\".";
00457   }
00458   identity().send_notice(buf.str(), network_domain_question);
00459   detected_network(iter);
00460 }

void ServerSession::detected_network ( networks_type::iterator  network_iter  ) 

Initialize network. This function is called as soon as the network we are connected to is known.

Definition at line 462 of file ServerSession.cc.

References ASSERT, DoutEntering, ISupport::get(), IdentityReference::identity(), IRCStringCompare(), M_detected_network, M_i_support, M_server_connection, M_umodes, debug::channels::dc::maps, Identity::mynick(), ServerConnection::secondary_connection(), and ServerConnection::server().

Referenced by construct_network_object(), and found_network_name().

00463 {
00464   DoutEntering(dc::debug, "Identity::detected_network(" << *network_iter << ")");
00465 
00466   boost::shared_ptr<Server> current_server(M_server_connection.server());
00467 
00468   Dout(dc::notice, "Current server is " << *current_server.get());
00469 
00470   // Update the current server as we connected successfully.
00471   ASSERT(is_open());
00472   ASSERT(remote_port() == current_server->port());
00473   current_server->add_port(current_server->port());
00474   Dout(dc::notice, "Added remote port " << current_server->port() << " to server " << *current_server.get());
00475 
00476   Dout(dc::debug, "*network_iter is now: " << *network_iter);
00477 
00478   // Set the network pointer of the current Server object.
00479   current_server->set_network(&(*network_iter));
00480 
00481   if (!M_server_connection.secondary_connection())
00482   {
00483     // Set the network pointer in my own Nick object.
00484     identity().mynick()->set_network(&(*network_iter));
00485     // Make sure my Nick is inserted in the networks targets map.
00486     Dout(dc::maps, "Inserting my nick \"" << identity().mynick()->in_name(*this) << "\" in Network map.");
00487     network_iter->targets().insert(target_lookup_map_type::value_type(identity().mynick()->in_name(*this), identity().mynick()));
00488     ASSERT(network_iter->targets().find(identity().mynick()->in_name(*this)) != network_iter->targets().end());
00489   }
00490 
00491   // Find the current server in the list of known servers for this network.
00492   std::string server_name = current_server->get_irc_name();
00493   Network::servers_type::iterator server = network_iter->servers().begin();
00494   while (server != network_iter->servers().end())
00495   {
00496     if (IRCStringCompare(server_name, (*server)->get_irc_name()) == 0)
00497       break;
00498     ++server;
00499   }
00500   if (server == network_iter->servers().end())
00501     network_iter->servers().push_back(current_server);
00502 
00503   M_detected_network = true;
00504 
00505   // Initialize WHO flag table.
00506   std::string prefix;
00507   if (!M_i_support.get("PREFIX", prefix))
00508   {
00509     prefix = "(ov)@+";
00510     Dout(dc::warning, "No PREFIX ISUPPORT. Using " << prefix);
00511   }
00512   network_iter->init_who_flag_table(M_umodes, prefix);
00513 }

void ServerSession::authentication_successful ( void   ) 

Called when the authentication was successful (when receiving the 001 numeric).

Definition at line 327 of file ServerSession.cc.

References M_auth_state.

Referenced by new_message_received().

00328 {
00329   M_auth_state.reset();
00330 }

void ServerSession::fatal_error ( char const *  error_msg  ) 

A fatal error occured. Calling this function will terminate the ServerSession.

Definition at line 313 of file ServerSession.cc.

00314 {
00315   if (!must_be_removed())               // Only write one error at a time.
00316     *this << "QUIT :Fatal error: " << error_msg << "\r\n";
00317   // The next method sets 'must_be_removed()' to true,
00318   // flushes the error and deletes this object (non-blocking).
00319   del();
00320 }

void ServerSession::found_network_name ( void   ) 

Called when the name of the Network is known (after numeric 005).

Definition at line 389 of file ServerSession.cc.

References ASSERT, Identity::client_session(), construct_network_object(), detected_network(), ServerConnection::disconnect(), IdentityReference::identity(), IRCStringCompare(), M_network_name, M_server_connection, network_domain_question, Identity::network_name(), Identity::received_network_domain_answer(), Identity::send_notice(), ServerConnection::server(), server_port_question, Identity::set_network_name(), and ClientSession::user_answer_event_server.

Referenced by ISupport::end().

00390 {
00391   Dout(dc::notice, "network = \"" << M_network_name << "\".");
00392   if (identity().network_name() != unknown_network_name && identity().network_name() != M_network_name)
00393   {
00394     Dout(dc::warning, "Identity " << identity().key() << " was connected to network " << identity().network_name() <<
00395         " but now tries to connect to network " << M_network_name << '!');
00396     std::string notice("Detected a possible network switch (from ");
00397     notice += identity().network_name();
00398     notice += " to ";
00399     notice += M_network_name;
00400     notice += "). Bailing out!";
00401     identity().send_notice(notice, server_port_question);
00402     M_server_connection.disconnect();
00403     return;
00404   }
00405   identity().send_notice("Successfully connected.", server_port_question);
00406   identity().set_network_name(M_network_name);
00407 
00408   // Try to find if we already know this network.
00409   networks_type& networks = Application::instance().networks();
00410   networks_type::iterator iter = networks.begin();
00411   while (iter != networks.end())
00412   {
00413     if (IRCStringCompare(iter->name(), M_network_name) == 0)
00414       break;
00415     ++iter;
00416   }
00417   if (iter == networks.end())
00418   {
00419     std::string server_name = M_server_connection.server()->get_irc_name();
00420     std::string::size_type pos = server_name.rfind('.');
00421     ASSERT(pos > 0);
00422     pos = server_name.rfind('.', pos - 1);
00423     if (pos != std::string::npos)
00424     {
00425       std::string domain = server_name.substr(pos + 1);
00426       std::transform(domain.begin(), domain.end(), domain.begin(), ToLower);
00427       std::ostringstream the_question;
00428       the_question << "Does the " << M_network_name << " IRC network use \"" <<
00429           domain << "\" as common domain for all servers (type: Yes|No)?";
00430       identity().client_session().user_answer_event_server
00431           (UserAnswerRequestData(identity().client_session(), network_domain_question, the_question.str()),
00432           identity(), &Identity::received_network_domain_answer,
00433           std::pair<std::string, std::string>(M_network_name, domain));
00434     }
00435     else
00436       construct_network_object(M_network_name, "");     // No common domain.
00437   }
00438   else
00439     detected_network(iter);
00440 }

MatcherEventServer& ServerSession::message_event_server ( void   )  [inline]

Return a reference to the event server for incoming messages.

Definition at line 112 of file ServerSession.h.

References M_message_event_server.

Referenced by AuthState::auth_notice_looking_up_hostname(), AuthState::auth_notice_looking_up_ident(), AuthState::AuthState(), and ServerConnection::send_pong_and_mode().

00112 { return M_message_event_server; }

MatcherEventServer const& ServerSession::message_event_server ( void   )  const [inline]

Return a const reference to the event server for incoming messages.

Definition at line 114 of file ServerSession.h.

References M_message_event_server.

00114 { return M_message_event_server; }

NickPair const& ServerSession::nicks ( void   )  const [inline]

Server session nick pair.

Definition at line 120 of file ServerSession.h.

References M_server_session_nicks.

00120 { return M_server_session_nicks; }

joined_channels_type& ServerSession::joined_channels ( void   )  [inline]

Return reference to map with joined channels.

Definition at line 123 of file ServerSession.h.

References M_joined_channels.

Referenced by Target::add_channel(), send_rejoins(), Target::serverside_add_channel(), Target::serverside_get_channel(), Target::sub_channel(), and Identity::~Identity().

00123 { return M_joined_channels; }

joined_channels_type const& ServerSession::joined_channels ( void   )  const [inline]

Return const reference to map with joined channels.

Definition at line 126 of file ServerSession.h.

References M_joined_channels.

00126 { return M_joined_channels; }

UserMode& ServerSession::user_mode ( void   )  [inline]

Return my user mode.

Definition at line 129 of file ServerSession.h.

References M_user_mode.

Referenced by new_message_received(), and ServerConnection::send_pong_and_mode().

00129 { return M_user_mode; }

UserMode const& ServerSession::user_mode ( void   )  const [inline]

Return my user mode.

Definition at line 132 of file ServerSession.h.

References M_user_mode.

00132 { return M_user_mode; }

void ServerSession::queue_msg ( MessageOut const &  msg  )  [inline]

void ServerSession::queue_msg_as_is ( ClientMessageIn const &  msg  ) 

Queue message msg with default priority without changing it.

Definition at line 382 of file ServerSession.cc.

References default_priority(), MessageIn::key(), MessageIn::params(), and queue_msg().

Referenced by Identity::new_client_message_received().

00383 {
00384   Prefix prefix(msg);
00385   MessageOut msgout(default_priority(msg.key()));
00386   queue_msg(msgout << prefix << msg.key() << msg.params(0));
00387 }

WhoRequest ServerSession::current_who_request ( void   )  [inline]

Return the first element of M_who_queue.

Definition at line 141 of file ServerSession.h.

References ASSERT, and M_who_queue.

00142         {
00143           ASSERT(!M_who_queue.empty());
00144           Dout(dc::debug, "ServerSession::current_who_request returns " << M_who_queue.front() << ". Number of items: " << M_who_queue.size());
00145           return M_who_queue.front();
00146         }

void ServerSession::pop_who_request ( void   )  [inline]

Pop the first element of M_who_queue.

Definition at line 149 of file ServerSession.h.

References ASSERT, and M_who_queue.

Referenced by Identity::new_server_message_received().

00150         {
00151           ASSERT(!M_who_queue.empty());
00152           M_who_queue.pop();
00153           Dout(dc::debug, "Calling ServerSession::pop_who_request. Remaining number of items: " << M_who_queue.size());
00154         }

void ServerSession::send_nick_write_event ( PseudoMessageEventType const &  ,
std::string  nick 
) [inline]

A write event of a pseudo NICK message happened. Actually write the NICK message.

Definition at line 157 of file ServerSession.h.

References nicks(), and NickPair::send_nick().

Referenced by ClientSession::new_client_nick_received().

00157 { nicks().send_nick(nick); }

void ServerSession::send_who_write_event ( PseudoMessageEventType const &  event_type,
WhoRequest  who_request 
)

A write event of a pseudo WHO message happened. Actually write the WHO message.

Definition at line 347 of file ServerSession.cc.

References ASSERT, DoutEntering, M_who_queue, WhoRequest::mask(), WhoRequest::mask_contains_space(), WhoRequest::mask_is_target(), WhoRequest::mask_target(), WhoRequest::options(), and WhoOptions::str().

Referenced by Identity::new_client_message_received().

00348 {
00349   ASSERT(!debug::secondary_connection);
00350   DoutEntering(dc::debug, "ServerSession::send_who_write_event((PseudoMessageEventType&){" << (void*)&event_type << "), " << who_request << ")");
00351   // Actually sent the WHO message to the server.
00352   std::string options(who_request.options().str());
00353   bool has_options = !options.empty();
00354   if (who_request.mask_contains_space())
00355   {
00356     if (has_options)
00357       *this << "WHO dummy";
00358     else
00359       *this << "WHO :" << who_request.mask();
00360   }
00361   else if (who_request.mask_is_target())
00362     *this << "WHO " << who_request.mask_target()->out_name(*this);
00363   else
00364     *this << "WHO " << who_request.mask();
00365   if (has_options)
00366   {
00367     *this << ' ' << options;
00368     if (who_request.mask_contains_space())
00369     {
00370       *this << " :";
00371       if (who_request.mask_is_target())
00372         *this << who_request.mask_target()->out_name(*this);
00373       else
00374         *this << who_request.mask();
00375     }
00376   }
00377   *this << "\r\n";
00378   Dout(dc::debug, "Pushing " << who_request << " onto M_who_queue.");
00379   M_who_queue.push(who_request);
00380 }

void ServerSession::force_quit ( timer_event_type_ct const &   ) 

Called 1 second after sending a QUIT and the connection still wasn't terminated.

Definition at line 515 of file ServerSession.cc.

References ServerConnection::disconnect(), DoutEntering, and M_server_connection.

00516 {
00517   DoutEntering(dc::debug, "ServerSession::force_quit(" << expired_at.get_expire_time() << ")");
00518   M_server_connection.disconnect();
00519 }

ISupport const& ServerSession::i_support ( void   )  const [inline]

Accessor for M_i_support.

Definition at line 166 of file ServerSession.h.

References M_i_support.

00166 { return M_i_support; }

ISupport& ServerSession::i_support ( void   )  [inline]

Accessor for M_i_support.

Definition at line 169 of file ServerSession.h.

References M_i_support.

00169 { return M_i_support; }

boost::shared_ptr< Channel > ServerSession::join_pipeline ( std::string const &  channel_name  ) 

Return a pointer to the channel in the pipeline, if any. Channel is removed from pipeline.

Definition at line 227 of file ServerSession.cc.

References M_join_pipeline.

Referenced by new_message_received().

00228 {
00229   boost::shared_ptr<Channel> result;
00230   join_pipeline_type::iterator iter = M_join_pipeline.find(channel_name);
00231   if (iter != M_join_pipeline.end())
00232   {
00233     result = iter->second;
00234     M_join_pipeline.erase(iter);
00235   }
00236   return result;
00237 }

void ServerSession::set_disconnect_reason ( std::string const &  disconnect_reason  )  [inline]

Set the disconnect reason to disconnect_reason.

Definition at line 175 of file ServerSession.h.

References ASSERT, and M_disconnect_reason.

Referenced by ServerConnection::error_message_received().

00175 { ASSERT(M_disconnect_reason.empty()); M_disconnect_reason = disconnect_reason; }

ServerConnection& ServerSession::server_connection ( void   )  const [inline]

Accessor for underlying server connection object.

Definition at line 178 of file ServerSession.h.

References M_server_connection.

Referenced by get_nick(), Matcher_noarg::match_impl(), new_message_received(), and Target::serverside_add_channel().

00178 { return M_server_connection; }

boost::shared_ptr< Nick > ServerSession::get_nick ( std::string const &  nick_name,
bool  create = false 
)

Get or create a Nick for nick_name.

Definition at line 537 of file ServerSession.cc.

References ASSERT, IdentityReference::identity(), is_nick(), Network::is_private(), debug::channels::dc::maps, server_connection(), Network::targets(), and THROW_EXCEPTION.

Referenced by Identity::new_server_message_received().

00538 {
00539   ASSERT(is_nick(nick_name));
00540 
00541   boost::shared_ptr<Nick> new_nick;
00542   // Get the network.
00543   Network& network(identity().server_connection().network());
00544   ASSERT(!network.is_private());
00545   // Get the nick, if any, or else create one.
00546   target_lookup_map_type::iterator network_iter = network.targets().find(nick_name);
00547   if (network_iter != network.targets().end())
00548     new_nick = boost::static_pointer_cast<Nick>(network_iter->second.lock());
00549   else if (create)
00550   {
00551     Nick* nick = new Nick(*this, nick_name);
00552     AllocTag(nick, nick_name);
00553     new_nick.reset(nick);
00554     Dout(dc::maps, "Inserting " << nick_name << " in Network map.");
00555 #if defined(CWDEBUG) || defined(DEBUG)
00556     std::pair<target_lookup_map_type::iterator, bool> res =
00557 #endif
00558         network.targets().insert(target_lookup_map_type::value_type(nick_name, new_nick));
00559     ASSERT(res.second);
00560   }
00561   else
00562     THROW_EXCEPTION(unknown_target(), "The identity " << identity().key() << " has no server side nick \"" << nick_name << "\"");
00563 
00564   return new_nick;
00565 }

void ServerSession::new_message_received ( ServerMessageIn const &  msg  )  [protected, virtual]

Incoming event from ServerSessionInput.

Definition at line 32 of file ServerSession.cc.

References ISupport::add(), ASSERT, authentication_successful(), ISupport::begin(), ServerConnection::change_state(), ClientSession::client_out_nick(), Identity::client_session(), ServerConnection::decode_ping(), default_priority(), ServerConnection::disconnect(), DoutEntering, ISupport::end(), ServerConnection::error_message_received(), IdentityReference::identity(), NickPair::in_nick(), MatchRequest::is_match(), join_pipeline(), MessageIn::key(), login_sent, M_i_support, M_join_pipeline, M_message_event_server, M_network_name, M_server_connection, M_server_session_nicks, M_umodes, Identity::mynick(), Identity::new_server_message_received(), UserMode::new_server_message_received(), NickPair::nick_received(), nicks(), MessageIn::param(), MessageIn::params(), MessageIn::params_size(), MessageIn::prefix_str(), ClientSession::queue_msg(), ClientSession::queue_msg_me_as_is(), real_nick_accepted, real_nick_sent, MatchRequest::regexp(), ServerConnection::secondary_connection(), Identity::secondary_server_connection(), NickPair::send_nick(), Identity::send_notice(), send_rejoins(), ServerConnection::server(), server_connection(), server_port_question, ServerMessageIn::server_session(), Target::serverside_add_channel(), Identity::set_hostname(), ServerConnection::state(), Identity::swap_primary_and_secondary_connection(), and user_mode().

00033 {
00034 #ifdef CWDEBUG
00035   // Suppress all debug output related to PING messages.
00036   bool suppress_debug_output =
00037       (msg.key() == keys::PING && Application::instance().suppress_ping()) ||
00038       ((msg.key() == 352 || msg.key() == 354 || msg.key() == 315) && Application::instance().suppress_who());
00039   Debug(if (suppress_debug_output) libcw_do.off());
00040 #endif
00041 
00042   DoutEntering(dc::debug, "ServerSession::new_message_received(" << msg << ")");
00043 
00044   // Trigger message match events.
00045   if (M_message_event_server.trigger(MatcherEventType(msg)))
00046   {
00047     Debug(if (suppress_debug_output) libcw_do.on());
00048     return;
00049   }
00050 
00051   // Decode messages that can happen prior to network detection here.
00052   // Other messages are decoded in default:.
00053   bool pre_network_message = true;              // non-Default.
00054   bool fully_processed = true;                  // No reason to call Identity::new_server_message_received.
00055   switch(msg.key())
00056   {
00057     case 1:
00058     {
00059       // My own nick name should equal parameter 0.
00060       ASSERT(msg.param(0) == nicks().in_nick());
00061       ASSERT(M_server_connection.secondary_connection() || msg.param(0) == identity().mynick()->in_name(*this));
00062       authentication_successful();
00063       M_server_connection.server()->set_irc_name(msg.prefix_str());
00064       MatchRequest match_request;
00065       match_request(1).regexp("Welcome to [Tt]he [^ ]* IRC [Nn]etwork", 1);
00066       if (!match_request.is_match(msg))
00067       {
00068         std::ostringstream buf;
00069         buf << "Unrecognized 001 format [" << msg.param(1) << "]. Bailing out.";
00070         identity().send_notice(buf.str(), server_port_question);
00071         M_server_connection.disconnect();
00072       }
00073       else
00074         M_network_name.assign(msg.param(1), 15, msg.param(1).find(' ', 16) - 15);
00075       break;
00076     }
00077     case 4:
00078     {
00079       // We can use this numeric to detect the start of a possible sequence of 005 messages.
00080       // See also the call to i_support().end().
00081       M_i_support.begin();
00082       // Store the supported user modes.
00083       M_umodes = msg.param(3);
00084       // Store the server version.
00085       M_server_connection.server()->version().set_version(msg.param(2), timerRequest.get_now().tv_sec);
00086       break;
00087     }
00088     case 5:
00089     {
00090       // Decode the params. Param 0 is my nick, param n-1 is "is supported by this server".
00091       for (unsigned int n = 1; n < msg.params_size() - 1; ++n)
00092         M_i_support.add(msg.param(n));
00093       break;
00094     }
00095     case 251:
00096     {
00097       // This means that all 005 numerics have been received.
00098       M_i_support.end();
00099       break;
00100     }
00101     case 2:
00102     case 3:
00103     case 252:
00104     case 253:
00105     case 254:
00106     case 255:
00107     case 372:
00108     case 375:
00109     case 376:
00110       break;
00111     default:
00112     {
00113       pre_network_message = false;
00114       // Decode messages that do not only happen once per (re)connect.
00115       switch (msg.key())
00116       {
00117         using namespace keys;
00118         case ERROR:
00119           M_server_connection.error_message_received(msg); 
00120           break;
00121         case PING:                      // No target
00122           M_server_connection.decode_ping(msg);
00123           break;
00124         case NICK:
00125         {
00126           if (!M_server_session_nicks.nick_received(msg.param(0)))
00127           {
00128             fully_processed = false;
00129             break;
00130           }
00131           // It was my own nick change.
00132           identity().mynick()->serverside_nick_changed_to(msg.server_session(), M_server_session_nicks.in_nick());
00133           if (!M_server_connection.secondary_connection())
00134           {
00135             // FIXME: We should only pass nick changes to the client that the client itself requested.
00136             ASSERT(identity().client_session().client_in_nick() == msg.param(0));
00137             Prefix prefix(msg);
00138             // For now, pass everything on to the client.
00139             MessageOut msgout(default_priority(keys::NICK));
00140             // FIXME: client_out_nick() should be updated first (is currently equal to client_in_nick, so no change needed now).
00141             identity().client_session().queue_msg(msgout << prefix << keys::NICK << identity().client_session().client_out_nick());
00142             identity().mynick()->clientside_nick_changed_to(identity().client_session(), identity().client_session().client_out_nick());
00143           }
00144           if (M_server_connection.state() == real_nick_sent)
00145           {
00146             M_server_connection.change_state(real_nick_sent, real_nick_accepted); 
00147             send_rejoins();
00148           }
00149           break;
00150         }
00151         case MODE:
00152           if (msg.param(0) == nicks().in_nick())
00153             user_mode().new_server_message_received(msg);
00154           else
00155             fully_processed = false;
00156           break;
00157         case 221:
00158           break;
00159         case 396:       // ... is now your hidden host
00160         {
00161           server_connection().change_state(login_sent, real_nick_sent);
00162           // Numeric 396 has the hidden hostname in parameter 1.
00163           identity().set_hostname(msg.param(1));
00164           if (!server_connection().secondary_connection())
00165           {
00166             identity().client_session().queue_msg_me_as_is(msg);
00167             nicks().send_nick(identity().client_session().client_in_nick());
00168           }
00169           else
00170             send_rejoins();
00171           break;
00172         }
00173         case JOIN:
00174         {
00175           // Handle JOIN's from the pipeline.
00176           boost::shared_ptr<Channel> channel(join_pipeline(msg.param(0)));
00177           if (!channel.get())
00178           {
00179             // Not in the pipeline. Process normally.
00180             ASSERT(!server_connection().secondary_connection());
00181             fully_processed = false;
00182             break;
00183           }
00184           Target::serverside_add_channel(*this, channel);
00185           if (!server_connection().secondary_connection())
00186             channel->reset_received_names();
00187           else if (M_join_pipeline.empty())
00188           {
00189             // This was the last join.
00190             // FIXME: switch ServerConnection etc.
00191             identity().swap_primary_and_secondary_connection();
00192             identity().secondary_server_connection()->disconnect();
00193           }
00194           break;
00195         }
00196         default:
00197           fully_processed = false;
00198           break;
00199       }
00200       break;
00201     }
00202   }
00203   if (pre_network_message)
00204   {
00205     // Pass message on as-is, only replacing my own nick name at param 0.
00206     Prefix prefix(msg);
00207     MessageOut msgout(default_priority(msg.key()));
00208     identity().client_session().queue_msg(msgout << prefix << msg.key() << identity().client_session().client_out_nick() << msg.params(1));
00209   }
00210   else if (!fully_processed)
00211   {
00212     if (!M_server_connection.secondary_connection())
00213     {
00214       // Decode messages other than PING, ERROR, own nick changes.
00215       identity().new_server_message_received(msg);
00216     }
00217 #ifdef CWDEBUG
00218     else
00219       Dout(dc::warning, "IGNORING secondary server message: " << msg);
00220 #endif
00221   }
00222 
00223   // Turn debug output on again, if it was suppressed.
00224   Debug(if (suppress_debug_output) libcw_do.on());
00225 }

void ServerSession::network_connection_terminated ( void   )  [protected, virtual]

A read(2) on the socket returned 0.

Definition at line 521 of file ServerSession.cc.

References DoutEntering, IdentityReference::identity(), M_disconnect_reason, M_server_connection, ServerConnection::secondary_connection(), Identity::send_notice(), and ServerConnection::server().

00522 {
00523 #ifdef CWDEBUG
00524   debug::SecondaryConnection dummy(M_server_connection.secondary_connection());
00525 #endif
00526   DoutEntering(dc::debug, "ServerSession::network_connection_terminated()");
00527 
00528   std::string disconnect_reason;
00529   if (M_disconnect_reason.empty())
00530     disconnect_reason = "EOF from server";
00531   else
00532     disconnect_reason = M_disconnect_reason;
00533 
00534   identity().send_notice("Lost connection with " + M_server_connection.server()->get_irc_name() + ": " + disconnect_reason);
00535 }

void ServerSession::send_rejoins ( void   )  [private]

Send a JOIN to the server for every channel we are on.

Definition at line 239 of file ServerSession.cc.

References ASSERT, Identity::client_session(), default_priority(), DoutEntering, IdentityReference::identity(), ClientSession::joined_channels(), joined_channels(), M_join_pipeline, and queue_msg().

Referenced by new_message_received().

00240 {
00241   DoutEntering(dc::debug, "ServerSession::send_rejoins()");
00242   // Sent a JOIN for each channel that the client still thinks it is on.
00243   MessageOut msgout(default_priority(keys::JOIN));
00244   msgout << keys::JOIN;
00245   size_t total_buffer_size = 8; // "JOIN \r\n\0"
00246   bool first_channel = true;
00247   bool first_key = true;
00248   std::string keys;
00249   // First do all channels that have a key.
00250   for (int with_keys = 1; with_keys >= 0; --with_keys)
00251   {
00252     for (ClientSession::joined_channels_type::iterator iter = identity().client_session().joined_channels().begin();
00253          iter != identity().client_session().joined_channels().end(); ++iter)
00254     {
00255       boost::shared_ptr<Channel> channel(boost::static_pointer_cast<Channel>(iter->second));
00256       if (with_keys == channel->has_key())
00257       {
00258         for(;;)
00259         {
00260           total_buffer_size +=
00261               (first_channel ? 0 : 1) +                 // 1 for comma.
00262               channel->out_name(*this).size() +
00263               (with_keys ? 1 + channel->key().size() : 0);      // 1 for space or comma.
00264           if (total_buffer_size <= 512)                 // We always break out here the first or second time,
00265             break;                                              // because 8 + MAXCHANLEN (~200) + 1 + MAXKEYLEN (23) <= 512.
00266           if (!first_key)
00267             msgout << keys;
00268           queue_msg(msgout);                            // Send message constructed so far.
00269           msgout << keys::JOIN;                         // This resets the msgout.
00270           total_buffer_size = 8;
00271           first_channel = true;
00272           first_key = true;
00273         }
00274         if (first_channel)
00275         {
00276           msgout << channel;
00277           first_channel = false;
00278         }
00279         else
00280         {
00281           msgout << JustInTimeCatenate(',');
00282           msgout << JustInTimeCatenate(channel);
00283         }
00284         if (with_keys)
00285         {
00286           if (first_key)
00287           {
00288             keys = channel->key();
00289             first_key = false;
00290           }
00291           else
00292           {
00293             keys += ',';
00294             keys += channel->key();
00295           }
00296         }
00297         // Remember that we sent a re-JOIN for this channel.
00298 #if defined(CWDEBUG) || defined(DEBUG)
00299         std::pair<join_pipeline_type::iterator, bool> res =
00300 #endif
00301             M_join_pipeline.insert(join_pipeline_type::value_type(channel->out_name(*this), channel));
00302         ASSERT(res.second);
00303       }
00304     }
00305   }
00306   // Finish up.
00307   if (!first_key)
00308     msgout << keys;
00309   if (!first_channel)
00310     queue_msg(msgout);
00311 }


Member Data Documentation

Event server for incoming messages.

Definition at line 54 of file ServerSession.h.

Referenced by message_event_server(), and new_message_received().

Server side nick pair.

Definition at line 55 of file ServerSession.h.

Referenced by new_message_received(), and nicks().

Serverside lookup map for channels joined by this identity.

Definition at line 56 of file ServerSession.h.

Referenced by joined_channels().

My user mode.

Definition at line 57 of file ServerSession.h.

Referenced by user_mode().

boost::shared_ptr<AuthState> ServerSession::M_auth_state [private]

Pointer object with temporary authentication state information.

Definition at line 58 of file ServerSession.h.

Referenced by auth_ping_argument(), authentication_successful(), set_auth_ping_argument(), and start_authentication().

Queue for output messages.

Definition at line 59 of file ServerSession.h.

Referenced by queue_msg().

std::queue<WhoRequest> ServerSession::M_who_queue [private]

Queue storing WHO request messages.

Definition at line 60 of file ServerSession.h.

Referenced by current_who_request(), pop_who_request(), and send_who_write_event().

Object that stores the numeric 005 information.

Definition at line 61 of file ServerSession.h.

Referenced by detected_network(), i_support(), and new_message_received().

std::string ServerSession::M_network_name [private]

Temporary storage of the network name as decoded from numeric 001, until numeric 005 is received.

Definition at line 62 of file ServerSession.h.

Referenced by found_network_name(), and new_message_received().

int ServerSession::S_server_sessions = 0 [static, private]

Total number of server session objects.

Definition at line 63 of file ServerSession.h.

Referenced by ServerSession(), and ~ServerSession().

std::string ServerSession::M_umodes [private]

The user modes as received in numeric 004.

Definition at line 64 of file ServerSession.h.

Referenced by detected_network(), and new_message_received().

Channels for which we sent a JOIN as part of a reconnect.

Definition at line 65 of file ServerSession.h.

Referenced by join_pipeline(), new_message_received(), and send_rejoins().

std::string ServerSession::M_disconnect_reason [private]

An error message that should be sent to the client if the connection is lost, if any.

Definition at line 66 of file ServerSession.h.

Referenced by network_connection_terminated(), and set_disconnect_reason().

True if the network is fully detected.

Definition at line 69 of file ServerSession.h.

Referenced by detected_network(), and ServerConnection::send_pong_and_mode().


The documentation for this class was generated from the following files:

Copyright © 2005-2007 Carlo Wood.  All rights reserved.