diff --git a/src/frontend/mosh-server.cc b/src/frontend/mosh-server.cc index b9af31435..2c4df579c 100644 --- a/src/frontend/mosh-server.cc +++ b/src/frontend/mosh-server.cc @@ -64,6 +64,7 @@ #include "fatal_assert.h" #include "locale_utils.h" #include "select.h" +#include "timestamp.h" #if HAVE_PTY_H #include @@ -114,6 +115,7 @@ void spin( void ) req.tv_sec = 0; req.tv_nsec = 100000000; /* 0.1 sec */ nanosleep( &req, NULL ); + freeze_timestamp(); } } diff --git a/src/frontend/stmclient.cc b/src/frontend/stmclient.cc index cee241fb5..00aef86b3 100644 --- a/src/frontend/stmclient.cc +++ b/src/frontend/stmclient.cc @@ -57,6 +57,7 @@ #include "fatal_assert.h" #include "locale_utils.h" #include "select.h" +#include "timestamp.h" #include "networktransport.cc" @@ -431,6 +432,7 @@ void STMClient::main( void ) req.tv_sec = 0; req.tv_nsec = 200000000; /* 0.2 sec */ nanosleep( &req, NULL ); + freeze_timestamp(); } catch ( Crypto::CryptoException e ) { if ( e.fatal ) { throw; diff --git a/src/network/network.cc b/src/network/network.cc index bf186d22c..c3430d16d 100644 --- a/src/network/network.cc +++ b/src/network/network.cc @@ -40,19 +40,13 @@ #include #include -#if HAVE_CLOCK_GETTIME - #include -#elif HAVE_MACH_ABSOLUTE_TIME - #include -#elif HAVE_GETTIMEOFDAY - #include -#endif - #include "dos_assert.h" #include "byteorder.h" #include "network.h" #include "crypto.h" +#include "timestamp.h" + using namespace std; using namespace Network; using namespace Crypto; @@ -386,41 +380,7 @@ int Connection::port( void ) const uint64_t Network::timestamp( void ) { -#if HAVE_CLOCK_GETTIME - struct timespec tp; - - if ( clock_gettime( CLOCK_MONOTONIC, &tp ) < 0 ) { - throw NetworkException( "clock_gettime", errno ); - } - - uint64_t millis = tp.tv_nsec / 1000000; - millis += uint64_t( tp.tv_sec ) * 1000; - - return millis; -#elif HAVE_MACH_ABSOLUTE_TIME - static mach_timebase_info_data_t s_timebase_info; - - if (s_timebase_info.denom == 0) { - mach_timebase_info(&s_timebase_info); - } - - // NB: mach_absolute_time() returns "absolute time units" - // We need to apply a conversion to get milliseconds. - return ((mach_absolute_time() * s_timebase_info.numer) / (1000000 * s_timebase_info.denom)); -#elif HAVE_GETTIMEOFDAY - // NOTE: If time steps backwards, timeouts may be confused. - struct timeval tv; - if ( gettimeofday(&tv, NULL) ) { - throw NetworkException( "gettimeofday", errno ); - } - - uint64_t millis = tv.tv_usec / 1000; - millis += uint64_t( tv.tv_sec ) * 1000; - - return millis; -#else -# error "Don't know how to get a timestamp on this platform" -#endif + return frozen_timestamp(); } uint16_t Network::timestamp16( void ) diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 2d33d325b..1b5ad5434 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -2,4 +2,4 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) $(HARDEN_CFLAGS) $(MISC_CXXF noinst_LIBRARIES = libmoshutil.a -libmoshutil_a_SOURCES = locale_utils.cc locale_utils.h swrite.cc swrite.h dos_assert.h fatal_assert.h select.h select.cc +libmoshutil_a_SOURCES = locale_utils.cc locale_utils.h swrite.cc swrite.h dos_assert.h fatal_assert.h select.h select.cc timestamp.h timestamp.cc diff --git a/src/util/select.h b/src/util/select.h index 6a2de7273..4bf4b8713 100644 --- a/src/util/select.h +++ b/src/util/select.h @@ -39,6 +39,7 @@ #include #include "fatal_assert.h" +#include "timestamp.h" /* Convenience wrapper for pselect(2). @@ -138,6 +139,8 @@ class Select { ret = 0; } + freeze_timestamp(); + return ret; } diff --git a/src/util/timestamp.cc b/src/util/timestamp.cc new file mode 100644 index 000000000..6486ec18c --- /dev/null +++ b/src/util/timestamp.cc @@ -0,0 +1,98 @@ +/* + Mosh: the mobile shell + Copyright 2012 Keith Winstein + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations including + the two. + + You must obey the GNU General Public License in all respects for all + of the code used other than OpenSSL. If you modify file(s) with this + exception, you may extend this exception to your version of the + file(s), but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. If you delete + this exception statement from all source files in the program, then + also delete it here. +*/ + +#include "config.h" + +#include "timestamp.h" + +#include + +#if HAVE_CLOCK_GETTIME + #include +#elif HAVE_MACH_ABSOLUTE_TIME + #include +#elif HAVE_GETTIMEOFDAY + #include +#endif + +static uint64_t millis_cache = -1; + +uint64_t frozen_timestamp( void ) +{ + if ( millis_cache == uint64_t( -1 ) ) { + freeze_timestamp(); + } + + return millis_cache; +} + +void freeze_timestamp( void ) +{ +#if HAVE_CLOCK_GETTIME + struct timespec tp; + + if ( clock_gettime( CLOCK_MONOTONIC, &tp ) < 0 ) { + /* did not succeed */ + } else { + uint64_t millis = tp.tv_nsec / 1000000; + millis += uint64_t( tp.tv_sec ) * 1000; + + millis_cache = millis; + return; + } +#elif HAVE_MACH_ABSOLUTE_TIME + static mach_timebase_info_data_t s_timebase_info; + + if (s_timebase_info.denom == 0) { + mach_timebase_info(&s_timebase_info); + } + + // NB: mach_absolute_time() returns "absolute time units" + // We need to apply a conversion to get milliseconds. + millis_cache = ((mach_absolute_time() * s_timebase_info.numer) / (1000000 * s_timebase_info.denom)); + return; +#elif HAVE_GETTIMEOFDAY + // NOTE: If time steps backwards, timeouts may be confused. + struct timeval tv; + if ( gettimeofday(&tv, NULL) ) { + perror( "gettimeofday" ); + } else { + uint64_t millis = tv.tv_usec / 1000; + millis += uint64_t( tv.tv_sec ) * 1000; + + millis_cache = millis; + return; + } +#else +# error "Don't know how to get a timestamp on this platform" +#endif +} diff --git a/src/util/timestamp.h b/src/util/timestamp.h new file mode 100644 index 000000000..9ba4947ef --- /dev/null +++ b/src/util/timestamp.h @@ -0,0 +1,41 @@ +/* + Mosh: the mobile shell + Copyright 2012 Keith Winstein + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations including + the two. + + You must obey the GNU General Public License in all respects for all + of the code used other than OpenSSL. If you modify file(s) with this + exception, you may extend this exception to your version of the + file(s), but you are not obligated to do so. If you do not wish to do + so, delete this exception statement from your version. If you delete + this exception statement from all source files in the program, then + also delete it here. +*/ + +#ifndef TIMESTAMP_HPP +#define TIMESTAMP_HPP + +#include + +void freeze_timestamp( void ); +uint64_t frozen_timestamp( void ); + +#endif