connector.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       connector.cc
00003 ///             Base class interface for handling Mode connections to device
00004 ///
00005 
00006 /*
00007     Copyright (C) 2011-2012, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "connector.h"
00023 #include "router.h"
00024 #include "controller.h"
00025 #include "m_desktop.h"
00026 #include "debug.h"
00027 #include <unistd.h>
00028 
00029 using namespace std;
00030 using namespace Barry;
00031 
00032 namespace Barry {
00033 
00034 //////////////////////////////////////////////////////////////////////////////
00035 // Connector base class
00036 
00037 // we use a const char *password here because we don't want the
00038 // responsibility of clear its memory... that's the application's job
00039 Connector::Connector(const char *password,
00040                      const std::string &locale,
00041                      Barry::Pin pin)
00042         : m_password(password)
00043         , m_needs_reconnect(false)
00044         , m_ic(locale.c_str())
00045         , m_probe_result(FindDevice(pin))
00046         , m_connect_count(0)
00047         , m_last_disconnect(0)
00048         , m_bpcopy("", 0, 0)
00049 {
00050 }
00051 
00052 Connector::Connector(const char *password,
00053                      const std::string &locale,
00054                      const Barry::ProbeResult &result)
00055         : m_password(password)
00056         , m_needs_reconnect(false)
00057         , m_ic(locale.c_str())
00058         , m_probe_result(result)
00059         , m_connect_count(0)
00060         , m_last_disconnect(0)
00061         , m_bpcopy("", 0, 0)
00062 {
00063 }
00064 
00065 Connector::~Connector()
00066 {
00067 }
00068 
00069 Barry::ProbeResult Connector::FindDevice(Barry::Pin pin)
00070 {
00071         Barry::Probe probe;
00072         int i = probe.FindActive(pin);
00073         if( i != -1 )
00074                 return probe.Get(i);
00075         else
00076                 throw Barry::PinNotFound(pin, probe.GetCount());
00077 }
00078 
00079 void Connector::ClearPassword()
00080 {
00081         // blank the memory first
00082         size_t len = m_password.size();
00083         while( len ) {
00084                 len--;
00085                 m_password[len] = '0';
00086         }
00087 
00088         // free it
00089         m_password.clear();
00090 }
00091 
00092 void Connector::SetPassword(const char *password)
00093 {
00094         ClearPassword();
00095         m_password = password;
00096 }
00097 
00098 bool Connector::Connect()
00099 {
00100         Disconnect();
00101 
00102         bool started = false;
00103         for(;;) {
00104 
00105                 try {
00106                         if( !started ) {
00107                                 started = true;
00108                                 StartConnect(m_password.c_str());
00109                         }
00110                         else {
00111                                 RetryPassword(m_password.c_str());
00112                         }
00113 
00114                         FinishConnect();
00115                         m_connect_count++;
00116                         return true;
00117 
00118                 }
00119                 catch( BadPassword &bp ) {
00120                         if( bp.out_of_tries() ) {
00121                                 throw;
00122                         }
00123 
00124                         m_bpcopy = bp;
00125 
00126                         // fall through to password prompt
00127                 }
00128 
00129                 // ask user for device password
00130                 ClearPassword();
00131                 if( !PasswordPrompt(m_bpcopy, m_password) ) {
00132                         // user wants out
00133                         return false;
00134                 }
00135         }
00136 }
00137 
00138 void Connector::Disconnect()
00139 {
00140         m_needs_reconnect = false;
00141         if( !IsDisconnected() ) {
00142                 DoDisconnect();
00143                 m_last_disconnect = time(NULL);
00144         }
00145 }
00146 
00147 bool Connector::Reconnect(int total_tries)
00148 {
00149         int tries = 0;
00150 
00151         while(1) try {
00152 
00153                 tries++;
00154 
00155                 Disconnect();
00156 
00157                 if( m_connect_count ) {
00158                         // let the device settle... this seems to help prevent
00159                         // the firmware hang, and therefore ultimately speeds
00160                         // up the sync
00161                         if( (time(NULL) - m_last_disconnect) < 2 ) {
00162                                 // don't bother sleeping if 2 seconds have
00163                                 // already passed
00164                                 sleep(1);
00165                         }
00166 
00167                         // temporary fix for odd reconnect message...
00168                         // without this probe, the reconnect will often fail on
00169                         // newer Blackberries due to an unexpected close socket
00170                         // message.
00171                         //
00172                         // It is unclear if this is really a message from
00173                         // the device, but until then, we add this probe.
00174                         m_probe_result = FindDevice(m_probe_result.m_pin);
00175                 }
00176 
00177                 return Connect();
00178         }
00179         catch( Usb::Timeout & ) {
00180                 if( tries >= total_tries ) {
00181                         throw;
00182                 }
00183                 else {
00184                         dout("Timeout in Connector::Reconnect()... trying again");
00185                 }
00186         }
00187 }
00188 
00189 bool Connector::ReconnectForDirtyFlags()
00190 {
00191         if( m_needs_reconnect ) {
00192                 return Reconnect();
00193         }
00194         else {
00195                 return true;
00196         }
00197 }
00198 
00199 void Connector::RequireDirtyReconnect()
00200 {
00201         m_needs_reconnect = true;
00202 }
00203 
00204 
00205 //////////////////////////////////////////////////////////////////////////////
00206 // DesktopConnector class
00207 
00208 DesktopConnector::DesktopConnector(const char *password,
00209                                 const std::string &locale,
00210                                 Barry::Pin pin,
00211                                 Barry::SocketRoutingQueue *router,
00212                                 int connect_timeout)
00213         : Connector(password, locale, pin)
00214         , m_router(router)
00215         , m_connect_timeout(connect_timeout)
00216 {
00217 }
00218 
00219 DesktopConnector::DesktopConnector(const char *password,
00220                                 const std::string &locale,
00221                                 const Barry::ProbeResult &result,
00222                                 Barry::SocketRoutingQueue *router,
00223                                 int connect_timeout)
00224         : Connector(password, locale, result)
00225         , m_router(router)
00226         , m_connect_timeout(connect_timeout)
00227 {
00228 }
00229 
00230 void DesktopConnector::StartConnect(const char *password)
00231 {
00232         // Note that there is a firmware issue that causes the firmware
00233         // to sometimes hang during a connect and it fails to respond
00234         // to a Desktop::Open() call.  To work around this, set the
00235         // timeout to something lower than the usual 30 seconds.
00236         // The default in DesktopConnector is 10 seconds, which should
00237         // be fine.
00238         //
00239         // If this bug triggers, a Timeout exception will be thrown,
00240         // which will be caught by the Reconnect() method, and Reconnect()
00241         // will retry according to the total number of retries it is
00242         // set to do.
00243         //
00244         if( m_router ) {
00245                 m_con.reset( new Barry::Controller(m_probe_result,
00246                                                 *m_router, m_connect_timeout) );
00247         }
00248         else {
00249                 m_con.reset( new Barry::Controller(m_probe_result,
00250                                                 m_connect_timeout) );
00251         }
00252         m_desktop.reset( new Barry::Mode::Desktop(*m_con, m_ic) );
00253         m_desktop->Open(password);
00254 }
00255 
00256 void DesktopConnector::RetryPassword(const char *password)
00257 {
00258         m_desktop->RetryPassword(password);
00259 }
00260 
00261 void DesktopConnector::FinishConnect()
00262 {
00263 }
00264 
00265 void DesktopConnector::DoDisconnect()
00266 {
00267         m_desktop.reset();
00268         m_con.reset();
00269 }
00270 
00271 bool DesktopConnector::IsDisconnected()
00272 {
00273         // return true if DoDisconnect can safely be skipped
00274         return !m_con.get() && !m_desktop.get();
00275 }
00276 
00277 bool DesktopConnector::IsConnected()
00278 {
00279         if( m_con.get() && m_desktop.get() )
00280                 return true;
00281         return false;
00282 }
00283 
00284 }
00285