libt2n: (gerd) fix exception passing
[libt2n] / src / server.cpp
1 /***************************************************************************
2  *   Copyright (C) 2006 by Gerd v. Egidy                                   *
3  *   gve@intra2net.com                                                     *
4  *                                                                         *
5  *   This library is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Lesser General Public License version   *
7  *   2.1 as published by the Free Software Foundation.                     *
8  *                                                                         *
9  *   This library is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU Lesser General Public License for more details.                   *
13  *                                                                         *
14  *   You should have received a copy of the GNU Lesser General Public      *
15  *   License along with this program; if not, write to the                 *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19
20 #include <sstream>
21
22 #include "server.hxx"
23 #include "log.hxx"
24
25 namespace libt2n
26 {
27
28 server_connection::server_connection(int _timeout)
29     : connection()
30 {
31     set_timeout(_timeout);
32     reset_timeout();
33     connection_id=0;
34     my_server=0;
35 }
36
37
38 /// get pointer to logging stream, returns NULL if no logging needed
39 std::ostream* server_connection::get_logstream(log_level_values level)
40 {
41     if (my_server != NULL)
42     {
43         std::ostream* ostr=my_server->get_logstream(level);
44         if (ostr != NULL)
45             (*ostr) << "connection " << get_id() << ": ";
46         return ostr;
47     }
48     else
49         return NULL;
50 }
51
52 /// check if timeout is expired, close connection if so
53 void server_connection::check_timeout()
54 {
55     if (timeout != -1 && last_action_time+timeout < time(NULL))
56     {
57         LOGSTREAM(debug,"timeout on connection " << connection_id << ", closing");
58         this->close();
59     }
60 }
61
62 /// reset the timeout, e.g. if something is received
63 void server_connection::reset_timeout()
64 {
65     last_action_time=time(NULL);
66 }
67
68 server::server()
69 {
70     set_default_timeout(30);
71     set_logging(NULL,none);
72     next_id=1;
73 }
74
75 server::~server()
76 {
77     std::map<unsigned int, server_connection*>::iterator ie=connections.end();
78     for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
79         delete i->second;
80 }
81
82 int server::add_connection(server_connection* newconn)
83 {
84     unsigned int cid=next_id++;
85     newconn->set_id(cid);
86     newconn->set_server(this);
87     connections[cid]=newconn;
88
89     LOGSTREAM(debug,"new connection accepted, id: " << cid);
90
91     return cid;
92 }
93
94 /// activate logging to the given stream. everything above the given level is logged.
95 void server::set_logging(std::ostream *_logstream, log_level_values _log_level)
96 {
97     log_level=_log_level;
98     logstream=_logstream;
99 }
100
101 /**
102     @brief Gets a connection by id
103     
104     @param conn_id Connection ID
105     
106     @retval Pointer to connection object
107 */
108 server_connection* server::get_connection(unsigned int conn_id)
109 {
110     std::map<unsigned int, server_connection*>::iterator p=connections.find(conn_id);
111     if (p==connections.end())
112         return NULL;
113     else
114         return p->second;
115 }
116
117 /// check for timeouts, remove closed connections. don't forget to call this from time to time.
118 void server::cleanup()
119 {
120     std::map<unsigned int, server_connection*>::iterator ie=connections.end();
121     for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
122         i->second->check_timeout();
123
124     for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie;)
125     {
126         if (i->second->is_closed() && !i->second->packet_available())
127         {
128             // closed and no usable data in buffer -> remove
129             LOGSTREAM(debug,"removing conneciton " << i->first << " because it is closed and no more data waiting");
130
131             delete i->second;
132             connections.erase(i);
133             i=connections.begin();
134             ie=connections.end();
135         }
136         else
137             i++;
138     }
139 }
140
141 /** @brief get a complete data packet from any client. The packet is removed from the
142             connection buffer.
143     @param[out] data the data package
144     @param[out] conn_id the connection id we got this packet from
145     @retval true if packet found
146 */
147 bool server::get_packet(std::string& data, unsigned int& conn_id)
148 {
149     // todo: this is somehow unfair: the first connections in the map get checked more
150     // often than the others and can thus block them out
151
152     std::map<unsigned int, server_connection*>::iterator ie=connections.end();
153     for(std::map<unsigned int, server_connection*>::iterator i=connections.begin(); i != ie; i++)
154         if (i->second->get_packet(data))
155         {
156             LOGSTREAM(debug,"got packet (" << data.size() << " bytes) from connection " << i->first);
157
158             conn_id=i->first;
159             return true;
160         }
161
162     return false;
163 }
164
165 /// get pointer to logging stream, returns NULL if no logging needed
166 std::ostream* server::get_logstream(log_level_values level)
167 {
168     if (logstream && log_level >= level)
169         return logstream;
170     else
171         return NULL;
172 }
173 };