libt2n: (gerd) fix client-connection-logic, finish wrappers, all tests are working...
[libt2n] / src / socket_wrapper.cpp
1 /***************************************************************************
2  *   Copyright (C) 2008 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 <functional>
21 #include <string>
22
23 #include <socket_wrapper.hxx>
24
25 namespace libt2n
26 {
27
28 client_connection* BasicSocketWrapper::get_connection(void)
29 {
30     if (c.get() == NULL)
31     {
32         if (socket_type == tcp_s)
33             c=std::auto_ptr<socket_client_connection>
34                 (new socket_client_connection(port,server,connect_timeout_usec,max_retries,logstream,log_level));
35         else if (socket_type == unix_s)
36             c=std::auto_ptr<socket_client_connection>
37                 (new socket_client_connection(path,connect_timeout_usec,max_retries,logstream,log_level));
38     }
39
40     return c.get();
41 }
42
43 bool ReconnectSocketWrapper::handle(command_client* stubBase, boost::function< void() > f)
44 {
45     int tries=0;
46
47     while(true)
48     {
49         try
50         {
51             // we always reconnect if something went wrong before:
52             // makes sure the buffers are clean of half-sent packets etc.
53             if (tries > 0)
54                 c->reconnect();
55
56             f();
57             // we were successful
58             return true;
59         }
60         catch(t2n_connect_error &e)
61         {
62             // reconnect already tries max_tries times to reconnect: we are done if that failed
63             throw(e);
64         }
65         catch(t2n_communication_error &e)
66         {
67             // aborts the loop with an exception after max_retries iterations
68             // retries means that the first try doesn't count: use >
69             if (tries > max_retries)
70                 throw(e);
71
72             // otherwise ignore the exception and reconnect in the next iteration
73         }
74         catch(...)
75         {
76             throw;
77         }
78
79         tries++;
80     }
81
82     return false;
83 }
84
85 client_connection* ReconnectIgnoreFailureSocketWrapper::get_connection(void)
86 {
87     client_connection* tmp=BasicSocketWrapper::get_connection();
88
89     if (tmp->is_closed())
90     {
91         // throw away the closed connection...
92         c.reset();
93         // ...return the dummy one instead
94         tmp=&dc;
95     }
96
97     return tmp;
98 }
99
100 bool ReconnectIgnoreFailureSocketWrapper::handle(command_client* stubBase, boost::function< void() > f)
101 {
102     if (!connection_established())
103     {
104         // dummy connection is in place: try to establish a real one
105         client_connection* tmp=get_connection();
106
107         if (tmp != &dc)
108         {
109             // success! we've got a real connection
110             stubBase->replace_connection(tmp);
111         }
112     }
113
114     // only try to handle the call if we've got a real connection
115     if (connection_established())
116     {
117         try
118         {
119             ReconnectSocketWrapper::handle(stubBase,f);
120             return true;
121         }
122         catch(t2n_communication_error &e)
123         {
124             // ignore
125         }
126         catch(...)
127         {
128             throw;
129         }
130     }
131
132     return false;
133 }
134
135 }