# connector.cc

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