X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c756f7426059bddf6a5688820ae7655cf0cc5835..4a64bee465c0dbf3d97fbf290cb2fef4ad41ca34:/src/unix/dialup.cpp diff --git a/src/unix/dialup.cpp b/src/unix/dialup.cpp index ea9ed63df6..6641d377b4 100644 --- a/src/unix/dialup.cpp +++ b/src/unix/dialup.cpp @@ -11,6 +11,10 @@ #include "wx/setup.h" +#ifdef __GNUG__ +# pragma implementation "dialup.h" +#endif + #if wxUSE_DIALUP_MANAGER #ifndef WX_PRECOMP @@ -19,11 +23,16 @@ #include "wx/string.h" #include "wx/event.h" -#include "wx/net.h" +#include "wx/dialup.h" #include "wx/timer.h" #include "wx/filefn.h" #include "wx/utils.h" #include "wx/log.h" +#include "wx/file.h" +#include "wx/process.h" +#include "wx/intl.h" +#include "wx/app.h" +#include "wx/wxchar.h" #include @@ -35,6 +44,7 @@ #include #include #include +#include // ---------------------------------------------------------------------------- // A class which groups functions dealing with connecting to the network from a @@ -62,14 +72,8 @@ class WXDLLEXPORT wxDialUpManagerImpl : public wxDialUpManager { public: - wxDialUpManagerImpl() - { - m_IsOnline = -1; // unknown - m_timer = NULL; - m_CanUseIfconfig = -1; // unknown - m_BeaconHost = WXDIALUP_MANAGER_DEFAULT_BEACONHOST; - m_BeaconPort = 80; - } + wxDialUpManagerImpl(); + ~wxDialUpManagerImpl(); /** Could the dialup manager be initialized correctly? If this function returns FALSE, no other functions will work neither, so it's a good idea @@ -100,13 +104,27 @@ public: // the "well-known host" (as specified by SetWellKnownHost) is reachable virtual bool IsOnline() const { - if( (! m_timer) // we are not polling, so test now: - || m_IsOnline == -1 - ) - CheckStatus(); - return m_IsOnline != 0; + CheckStatus(); + return m_IsOnline > 0; } + /// do we have a constant net connection? -- GUESS! + bool IsAlwaysOnline() const + { + ((wxDialUpManagerImpl *) this)->HangUp(); // brutal but necessary + return IsOnline(); + } + /// returns TRUE if (async) dialing is in progress + inline virtual bool IsDialing() const + { return m_DialProcess != NULL; } + + // cancel dialing the number initiated with Dial(async = TRUE) + // NB: this won't result in DISCONNECTED event being sent + virtual bool CancelDialing(); + + size_t GetISPNames(class wxArrayString &) const + { return 0; } + // sometimes the built-in logic for determining the online status may fail, // so, in general, the user should be allowed to override it. This function // allows to forcefully set the online status - whatever our internal @@ -150,6 +168,11 @@ private: /// The path to ifconfig wxString m_IfconfigPath; + /// Can we use ping to find hosts? + int m_CanUsePing; + /// The path to ping program + wxString m_PingPath; + /// beacon host: wxString m_BeaconHost; /// beacon host portnumber for connect: @@ -163,13 +186,29 @@ private: wxString m_ISPname; /// a timer for regular testing class AutoCheckTimer *m_timer; - friend class AutoCheckTimer; + + /// a wxProcess for dialling in background + class wxDialProcess *m_DialProcess; + /// pid of dial process + int m_DialPId; + friend class wxDialProcess; + /// determine status - void CheckStatus(void) const; + void CheckStatus(bool fromAsync = FALSE) const; /// real status check void CheckStatusInternal(void); + + /// Check /proc/net (Linux only) + int CheckProcNet(void); + /// Check output of ifconfig command for PPP/SLIP/PLIP devices + int CheckIfconfig(void); + /// Ping a host: 1 on success, -1 if it cannot be used, 0 if unreachable + int CheckPing(void); + /// Check by connecting to host on given port. + int CheckConnect(void); + }; @@ -182,11 +221,11 @@ public: m_started = FALSE; } - virtual bool Start( int millisecs = -1 ) + virtual bool Start( int millisecs = -1, bool WXUNUSED(one_shot) = FALSE ) { m_started = TRUE; return wxTimer::Start(millisecs, FALSE); } virtual void Notify() - { wxLogTrace("Checking dial up network status."); m_dupman->CheckStatus(); } + { wxLogTrace(wxT("Checking dial up network status.")); m_dupman->CheckStatus(); } virtual void Stop() { if ( m_started ) wxTimer::Stop(); } @@ -195,6 +234,66 @@ public: wxDialUpManagerImpl *m_dupman; }; +class wxDialProcess : public wxProcess +{ +public: + wxDialProcess(wxDialUpManagerImpl *dupman) + { + m_DupMan = dupman; + } + void Disconnect(void) { m_DupMan = NULL; } + virtual void OnTerminate(int WXUNUSED(pid), int WXUNUSED(status)) + { + if(m_DupMan) + { + m_DupMan->m_DialProcess = NULL; + m_DupMan->CheckStatus(TRUE); + } + } +private: + wxDialUpManagerImpl *m_DupMan; +}; + + +wxDialUpManagerImpl::wxDialUpManagerImpl() +{ + /* The isOnline flag can have the following values internally: + 0 : not connected + 1 : connected + -1 : unknown/undefined status + */ + m_IsOnline = -1; + m_DialProcess = NULL; + m_timer = NULL; + m_CanUseIfconfig = -1; // unknown + m_CanUsePing = -1; // unknown + m_BeaconHost = WXDIALUP_MANAGER_DEFAULT_BEACONHOST; + m_BeaconPort = 80; + +#ifdef __SGI__ + m_ConnectCommand = _T("/usr/etc/ppp"); +#elif defined(__LINUX__) + // default values for Debian/GNU linux + m_ConnectCommand = _T("pon"); + m_HangUpCommand = _T("poff"); +#endif + + wxChar * dial = wxGetenv(_T("WXDIALUP_DIALCMD")); + wxChar * hup = wxGetenv(_T("WXDIALUP_HUPCMD")); + SetConnectCommand(dial ? wxString(dial) : m_ConnectCommand, + hup ? wxString(hup) : m_HangUpCommand); +} + +wxDialUpManagerImpl::~wxDialUpManagerImpl() +{ + if(m_timer) delete m_timer; + if(m_DialProcess) + { + m_DialProcess->Disconnect(); + m_DialProcess->Detach(); + } +} + bool wxDialUpManagerImpl::Dial(const wxString &isp, const wxString & WXUNUSED(username), @@ -203,22 +302,28 @@ wxDialUpManagerImpl::Dial(const wxString &isp, { if(m_IsOnline == 1) return FALSE; - m_IsOnline = -1; m_ISPname = isp; wxString cmd; - if(m_ConnectCommand.Find("%s")) + if(m_ConnectCommand.Find(wxT("%s"))) cmd.Printf(m_ConnectCommand,m_ISPname.c_str()); else cmd = m_ConnectCommand; if ( async ) { - wxFAIL_MSG(_T("TODO")); + m_DialProcess = new wxDialProcess(this); + m_DialPId = (int)wxExecute(cmd, FALSE, m_DialProcess); + if(m_DialPId == 0) + { + delete m_DialProcess; + m_DialProcess = NULL; + return FALSE; + } + else + return TRUE; } else - { return wxExecute(cmd, /* sync */ TRUE) == 0; - } } bool @@ -226,20 +331,32 @@ wxDialUpManagerImpl::HangUp(void) { if(m_IsOnline == 0) return FALSE; - m_IsOnline = -1; + if(IsDialing()) + { + wxLogError(_("Already dialling ISP.")); + return FALSE; + } wxString cmd; - if(m_HangUpCommand.Find("%s")) - cmd.Printf(m_HangUpCommand,m_ISPname.c_str()); + if(m_HangUpCommand.Find(wxT("%s"))) + cmd.Printf(m_HangUpCommand,m_ISPname.c_str(), m_DialProcess); else cmd = m_HangUpCommand; return wxExecute(cmd, /* sync */ TRUE) == 0; } +bool +wxDialUpManagerImpl::CancelDialing() +{ + if(! IsDialing()) + return FALSE; + return kill(m_DialPId, SIGTERM) > 0; +} + bool wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds) { - wxASSERT(m_timer == NULL); + DisableAutoCheckOnlineStatus(); m_timer = new AutoCheckTimer(this); bool rc = m_timer->Start(nSeconds*1000); if(! rc) @@ -253,22 +370,31 @@ wxDialUpManagerImpl::EnableAutoCheckOnlineStatus(size_t nSeconds) void wxDialUpManagerImpl::DisableAutoCheckOnlineStatus() { - wxASSERT(m_timer != NULL); - m_timer->Stop(); - delete m_timer; - m_timer = NULL; + if(m_timer != NULL) + { + m_timer->Stop(); + delete m_timer; + m_timer = NULL; + } } void wxDialUpManagerImpl::SetWellKnownHost(const wxString& hostname, int portno) { + if(hostname.Length() == 0) + { + m_BeaconHost = WXDIALUP_MANAGER_DEFAULT_BEACONHOST; + m_BeaconPort = 80; + return; + } + /// does hostname contain a port number? - wxString port = hostname.After(':'); + wxString port = hostname.After(wxT(':')); if(port.Length()) { - m_BeaconHost = hostname.Before(':'); - m_BeaconPort = atoi(port); + m_BeaconHost = hostname.Before(wxT(':')); + m_BeaconPort = wxAtoi(port); } else { @@ -279,7 +405,7 @@ wxDialUpManagerImpl::SetWellKnownHost(const wxString& hostname, int portno) void -wxDialUpManagerImpl::CheckStatus(void) const +wxDialUpManagerImpl::CheckStatus(bool fromAsync) const { // This function calls the CheckStatusInternal() helper function // which is OS - specific and then sends the events. @@ -288,12 +414,15 @@ wxDialUpManagerImpl::CheckStatus(void) const ( /* non-const */ (wxDialUpManagerImpl *)this)->CheckStatusInternal(); // now send the events as appropriate: - if(m_IsOnline != oldIsOnline) + if(m_IsOnline != oldIsOnline // it changed + && ( m_IsOnline == 1 // and it is a defined status + || m_IsOnline == 0) + // only send events for well defined transitions + && ( oldIsOnline == 1 || oldIsOnline == 0) + ) { - if(m_IsOnline) - ; // send ev - else - ; // send ev + wxDialUpEvent event(m_IsOnline, ! fromAsync); + (void)wxTheApp->ProcessEvent(event); } } @@ -315,14 +444,113 @@ wxDialUpManagerImpl::CheckStatusInternal(void) { m_IsOnline = -1; - // First time check for ifconfig location. We only use the variant - // which does not take arguments, a la GNU. - if(m_CanUseIfconfig == -1) // unknown + int testResult; + + testResult = CheckProcNet(); + if(testResult == -1) + testResult = CheckIfconfig(); + if(testResult == -1) + testResult = CheckConnect(); + if(testResult == -1) + testResult = CheckPing(); + m_IsOnline = testResult; +} + +int +wxDialUpManagerImpl::CheckConnect(void) +{ + // second method: try to connect to a well known host: + // This can be used under Win 9x, too! + struct hostent *hp; + struct sockaddr_in serv_addr; + + if((hp = gethostbyname(m_BeaconHost.mb_str())) == NULL) + return 0; // no DNS no net + + serv_addr.sin_family = hp->h_addrtype; + memcpy(&serv_addr.sin_addr,hp->h_addr, hp->h_length); + serv_addr.sin_port = htons(m_BeaconPort); + + int sockfd; + if( ( sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) + { + return -1; // no info + } + + if( connect(sockfd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) >= 0) + { + close(sockfd); + return 1; // we cant connect, so we have a network! + } + //connected! + close(sockfd); + if(errno == ENETUNREACH) + return 0; // network is unreachable + // connect failed, but don't know why + return -1; +} + + +int +wxDialUpManagerImpl::CheckProcNet(void) +{ + int rc = -1; + +#ifdef __LINUX__ + if (wxFileExists(_T("/proc/net/route"))) + { + // NOTE: cannot use wxFile::Length because file doesn't support + // seeking + FILE *f = fopen("/proc/net/route", "rt"); + if (f != NULL) + { + char output[256]; + + while (fgets(output, 256, f) != NULL) + { + if (strstr(output,"ppp") // ppp + || strstr(output,"sl") // slip + || strstr(output,"pl")) // plip + rc = 1; + } + if (rc == -1) rc = 0; + fclose(f); + } + } +#endif + + return rc; +} + + +int +wxDialUpManagerImpl::CheckIfconfig(void) +{ + int rc = -1; + + // First time check for ifconfig location. We only use the variant which + // does not take arguments, a la GNU. + if ( m_CanUseIfconfig == -1 ) // unknown { - if(wxFileExists("/sbin/ifconfig")) - m_IfconfigPath = "/sbin/ifconfig"; - else if(wxFileExists("/usr/sbin/ifconfig")) - m_IfconfigPath = "/usr/sbin/ifconfig"; + static const wxChar *ifconfigLocations[] = + { + _T("/sbin"), // Linux, FreeBSD + _T("/usr/sbin"), // SunOS, Solaris, AIX, HP-UX + _T("/usr/etc"), // IRIX + }; + + for ( size_t n = 0; n < WXSIZEOF(ifconfigLocations); n++ ) + { + wxString path(ifconfigLocations[n]); + path << _T("/ifconfig"); + + if ( wxFileExists(path) ) + { + m_IfconfigPath = path; + break; + } + } } wxLogNull ln; // suppress all error messages @@ -330,38 +558,31 @@ wxDialUpManagerImpl::CheckStatusInternal(void) if(m_CanUseIfconfig != 0) // unknown or yes { wxASSERT(m_IfconfigPath.length()); - + wxString tmpfile = wxGetTempFileName("_wxdialuptest"); wxString cmd = "/bin/sh -c \'"; - cmd << m_IfconfigPath << " >" << tmpfile << '\''; + cmd << m_IfconfigPath; +#if defined(__SOLARIS__) || defined (__SUNOS__) + // need to add -a flag + cmd << " -a"; +#elif defined(__LINUX__) || defined(__SGI__) + // nothing to be added to ifconfig +#elif defined(__FREEBSD__) + // add -l flag + cmd << " -l"; +#elif defined(__HPUX__) + // VZ: a wild guess (but without it, ifconfig fails completely) + cmd << _T(" ppp0"); +#else +# pragma warning "No ifconfig information for this OS." + m_CanUseIfconfig = 0; + return -1; +#endif + cmd << " >" << tmpfile << '\''; /* I tried to add an option to wxExecute() to not close stdout, so we could let ifconfig write directly to the tmpfile, but - this does not work. That should be faster, as it doesn´t call + this does not work. That should be faster, as it doesn´t call the shell first. I have no idea why. :-( (KB) */ -#if 0 - // temporarily redirect stdout/stderr: - int - new_stdout = dup(STDOUT_FILENO), - new_stderr = dup(STDERR_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - - int - // new stdout: - output_fd = open(tmpfile, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR), - // new stderr: - null_fd = open("/dev/null", O_CREAT, S_IRUSR|S_IWUSR); - // verify well behaved unix behaviour: - wxASSERT(output_fd == STDOUT_FILENO); - wxASSERT(null_fd == STDERR_FILENO); - int rc = wxExecute(m_IfconfigPath,TRUE /* sync */,NULL ,wxEXECUTE_DONT_CLOSE_FDS); - close(null_fd); close(output_fd); - // restore old stdout, stderr: - int test; - test = dup(new_stdout); close(new_stdout); wxASSERT(test == STDOUT_FILENO); - test = dup(new_stderr); close(new_stderr); wxASSERT(test == STDERR_FILENO); - if(rc == 0) -#endif if(wxExecute(cmd,TRUE /* sync */) == 0) { m_CanUseIfconfig = 1; @@ -372,57 +593,81 @@ wxDialUpManagerImpl::CheckStatusInternal(void) output[file.Length()] = '\0'; if(file.Read(output,file.Length()) == file.Length()) { - if(strstr(output,"ppp") // ppp - || strstr(output,"sl") // slip - || strstr(output,"pl") // plip - ) - m_IsOnline = 1; - else - m_IsOnline = 0; + // FIXME shouldn't we grep for "^ppp"? (VZ) + +#if defined(__SOLARIS__) || defined (__SUNOS__) + // dialup device under SunOS/Solaris + rc = strstr(output,"ipdptp") != (char *)NULL; +#elif defined(__LINUX__) || defined (__FREEBSD__) + rc = strstr(output,"ppp") // ppp + || strstr(output,"sl") // slip + || strstr(output,"pl"); // plip +#elif defined(__SGI__) // IRIX + rc = (int) strstr(output, "ppp"); // PPP +#elif defined(__HPUX__) + // if could run ifconfig on interface, then it exists + rc = TRUE; +#endif } file.Close(); delete [] output; } - // else m_IsOnline remains -1 as we don't know for sure + // else rc remains -1 as we don't know for sure } else // could not run ifconfig correctly m_CanUseIfconfig = 0; // don´t try again (void) wxRemoveFile(tmpfile); - if(m_IsOnline != -1) // we are done - return; } - // second method: try to connect to well known host: - // This can be used under Win 9x, too! - struct hostent *hp; - struct sockaddr_in serv_addr; - int sockfd; + return rc; +} - m_IsOnline = 0; // assume false - if((hp = gethostbyname(m_BeaconHost)) == NULL) - return; // no DNS no net - - serv_addr.sin_family = hp->h_addrtype; - memcpy(&serv_addr.sin_addr,hp->h_addr, hp->h_length); - serv_addr.sin_port = htons(m_BeaconPort); - if( ( sockfd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) - { - // sys_error("cannot create socket for gw"); - return; - } - if( connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) - { - //sys_error("cannot connect to server"); - return; +int +wxDialUpManagerImpl::CheckPing(void) +{ + if(! m_CanUsePing) + return -1; + + // First time check for ping location. We only use the variant + // which does not take arguments, a la GNU. + if(m_CanUsePing == -1) // unknown + { + if(wxFileExists("/bin/ping")) + m_PingPath = "/bin/ping"; + else if(wxFileExists("/usr/sbin/ping")) + m_PingPath = "/usr/sbin/ping"; + if(! m_PingPath) + { + m_CanUsePing = 0; + return -1; + } } - //connected! - close(sockfd); -} + wxLogNull ln; // suppress all error messages + wxASSERT(m_PingPath.length()); + wxString cmd; + cmd << m_PingPath << ' '; +#if defined(__SOLARIS__) || defined (__SUNOS__) + // nothing to add to ping command +#elif defined(__LINUX__) || defined ( __FREEBSD__) + cmd << "-c 1 "; // only ping once +#elif defined(__HPUX__) + cmd << "64 1 "; // only ping once (need also specify the packet size) +#else +# pragma warning "No Ping information for this OS." + m_CanUsePing = 0; + return -1; +#endif + cmd << m_BeaconHost; + if(wxExecute(cmd, TRUE /* sync */) == 0) + return 1; + else + return 0; +} /* static */ wxDialUpManager * -wxDialUpManager::wxDialUpManager::Create(void) +wxDialUpManager::Create(void) { return new wxDialUpManagerImpl; }