1 /*----------------------------------------------------------------------------
  2 Name:      Timestampc.c
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Time handling and unique counter
  6 Author:    "Marcel Ruff" <xmlBlaster@marcelruff.info>
  7 See:       http://www.xmlblaster.org/xmlBlaster/doc/requirements/protocol.socket.html
  8 -----------------------------------------------------------------------------*/
  9 #include <stdio.h>  /* snprintf */
 10 #include <string.h> /* memset */
 11 #include "basicDefs.h"
 12 #include "helper.h"
 13 #include "Timestampc.h"
 14 
 15 #ifdef _WINDOWS
 16 #  if defined(WINCE)
 17      /* time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds */
 18 #    if !defined(PTW32_TIMESPEC_TO_FILETIME_OFFSET)
 19 #       define PTW32_TIMESPEC_TO_FILETIME_OFFSET \
 20           ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 )
 21 #    endif
 22 #  else
 23 #    include <sys/timeb.h>
 24 #  endif
 25 #  if XB_USE_PTHREADS
 26 #    include <pthreads/pthread.h> /* Our pthreads.h: For logging output of thread ID, for Windows and WinCE downloaded from http://sources.redhat.com/pthreads-win32 */
 27 #  endif
 28 #else
 29 #  include <unistd.h>         /* sleep(), only used in main */
 30 #  include <errno.h>          /* errno */
 31 #  include <sys/time.h>       /* sleep with select(), gettimeofday() */
 32 #  if XB_USE_PTHREADS
 33 #    include <pthread.h>      /* The original pthreads.h from the OS */
 34 #  endif
 35 #  include <inttypes.h>       /* PRId64 %lld format specifier */
 36 #endif
 37 
 38 #define  MICRO_SECS_PER_SECOND 1000000
 39 #define  NANO_SECS_PER_SECOND MICRO_SECS_PER_SECOND * 1000
 40 
 41 
 42 #if XB_USE_PTHREADS
 43 static pthread_mutex_t tsMutex = PTHREAD_MUTEX_INITIALIZER;
 44 /*pthread_mutex_init(&tsMutex, NULL); */
 45 /*pthread_mutex_destroy(&tsMutex);*/
 46 #endif
 47 
 48 /**
 49  * Create a timestamp in nano seconds elapsed since 1970-01-01.
 50  * The timestamp is guaranteed to be ascending and unique.
 51  * <p>
 52  * The call is thread safe
 53  */
 54 Dll_Export int64_t getTimestamp() {
 55    struct timespec abstime;
 56    int64_t timestamp;
 57    static int64_t lastNanos=0;
 58 
 59    getAbsoluteTime(0L, &abstime);
 60 
 61    timestamp = (int64_t)abstime.tv_sec * NANO_SECS_PER_SECOND;
 62    timestamp += abstime.tv_nsec;
 63 #  if XB_USE_PTHREADS
 64       pthread_mutex_lock(&tsMutex);
 65 #  endif
 66    if (timestamp <= lastNanos) {
 67       timestamp = lastNanos + 1;
 68    }
 69    lastNanos = timestamp;
 70 #  if XB_USE_PTHREADS
 71       pthread_mutex_unlock(&tsMutex);
 72 #  endif
 73    return timestamp;
 74 }
 75 
 76 Dll_Export char *getTimestampStr(char *buf, size_t buflen) {
 77    int64_t ts = getTimestamp(); /* INT_LEAST64_MAX=9223372036854775807 */
 78    SNPRINTF(buf, buflen, PRINTF_PREFIX_INT64_T, ts); /* Windows does not know "%"PRId64 (from inttypes.h) */
 79    return buf;
 80 }
 81 
 82 /**
 83  * Fills the given abstime with absolute time, using the given timeout relativeTimeFromNow in milliseconds
 84  * On Linux < 2.5.64 does not support high resolution timers clock_gettime(),
 85  * but patches are available at http://sourceforge.net/projects/high-res-timers
 86  * @param relativeTimeFromNow the relative time from now in milliseconds
 87  * @param abstime
 88  * @return true If implemented
 89  */
 90 Dll_Export bool getAbsoluteTime(long relativeTimeFromNow, struct timespec *abstime)
 91 {
 92 # if defined(WINCE)
 93    /* Copied from pthreads_win32: thank you! */
 94    FILETIME ft;
 95    SYSTEMTIME st;
 96    GetSystemTime(&st);
 97    SystemTimeToFileTime(&st, &ft);
 98    /*
 99     * GetSystemTimeAsFileTime(&ft); would be faster,
100     * but it does not exist on WinCE
101     */
102      /*
103       * -------------------------------------------------------------------
104       * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is
105       * expressed in 100 nanoseconds from Jan 1, 1601,
106       * into struct timespec
107       * where the time is expressed in seconds and nanoseconds from Jan 1, 1970.
108       * -------------------------------------------------------------------
109       */
110    abstime->tv_sec =
111     (int) ((*(LONGLONG *) &ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
112    abstime->tv_nsec =
113     (int) ((*(LONGLONG *) &ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET -
114             ((LONGLONG) abstime->tv_sec * (LONGLONG) 10000000)) * 100);
115 
116    if (relativeTimeFromNow > 0) {
117       abstime->tv_sec += relativeTimeFromNow / 1000;
118       abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
119    }
120    if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
121       abstime->tv_nsec -= NANO_SECS_PER_SECOND;
122       abstime->tv_sec += 1;
123    }
124    return true;
125 
126 # elif defined(_WINDOWS)
127    struct _timeb tm;
128 #  if _MSC_VER >= 1400  /* _WINDOWS: 1200->VC++6.0, 1310->VC++7.1 (2003), 1400->VC++8.0 (2005) */
129         errno_t err = _ftime_s(&tm);
130       if (err) return false;
131 #  else
132         (void) _ftime(&tm);
133 #  endif
134 
135    abstime->tv_sec = (long)tm.time;
136    abstime->tv_nsec = tm.millitm * 1000 * 1000; /* TODO !!! How to get the more precise current time on Win? */
137 
138    if (relativeTimeFromNow > 0) {
139       abstime->tv_sec += relativeTimeFromNow / 1000;
140       abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
141    }
142    if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
143       abstime->tv_nsec -= NANO_SECS_PER_SECOND;
144       abstime->tv_sec += 1;
145    }
146    return true;
147 # else /* LINUX, __sun */
148    struct timeval tv;
149 
150    memset(abstime, 0, sizeof(struct timespec));
151 
152    /* Better?
153         if (clock_gettime(CLOCK_REALTIME, &abstime) == -1) {
154                 printf("Timeout.c clock_gettime failed%d\n", errno);
155         }
156    */
157 
158    gettimeofday(&tv, 0);
159    abstime->tv_sec = tv.tv_sec;
160    abstime->tv_nsec = tv.tv_usec * 1000;  /* microseconds to nanoseconds */
161 
162    if (relativeTimeFromNow > 0) {
163       abstime->tv_sec += relativeTimeFromNow / 1000;
164       abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
165    }
166    if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
167       abstime->tv_nsec -= NANO_SECS_PER_SECOND;
168       abstime->tv_sec += 1;
169    }
170    return true;
171 # endif
172 # ifdef MORE_REALTIME
173    clock_gettime(CLOCK_REALTIME, abstime);
174 
175    if (relativeTimeFromNow > 0) {
176       abstime->tv_sec += relativeTimeFromNow / 1000;
177       abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
178    }
179    if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
180       abstime->tv_nsec -= NANO_SECS_PER_SECOND;
181       abstime->tv_sec += 1;
182    }
183    return true;
184 # endif
185 }
186 
187 /**
188  * Get current timestamp string in ISO 8601 notation.
189  * @param bufSize at least 26
190  * @param timeStr out parameter, filled with e.g. "1997-07-16T19:20:30.45-02:00"
191  * @return Your param timeStr for easy usage in printf() and such
192  * @see http://en.wikipedia.org/wiki/ISO_8601
193  */
194 Dll_Export const char *getCurrentLocalIsoTimestampStr(char *timeStr, int bufSize) {
195 #  if defined(WINCE)
196         /*http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcekernl/html/_wcesdk_win32_systemtime_str.asp*/
197         SYSTEMTIME st;
198         GetSystemTime(&st);
199         snprintf0(timeStr, bufSize, "%hd-%hd-%hdT%hd:%hd:%hd.%hd\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
200 #  elif _MSC_VER >= 1400
201         /* TODO */
202         /*__time64_t timer;
203          _time64(&timer);*/
204         time_t t1; /* unsigned long */
205         (void) time(&t1); /* in seconds since the Epoch. 1970 */
206         ctime_s(timeStr, bufSize-1, &t1);
207 #  elif defined(_WINDOWS)
208         /* TODO */
209         time_t t1; /* unsigned long */
210         (void) time(&t1);
211         strncpy0(timeStr, ctime(&t1), bufSize);
212 #  elif defined(__sun)
213         /* TODO */
214         time_t t1; /* unsigned long */
215         (void) time(&t1);
216         ctime_r(&t1, (char *)timeStr, bufSize-1);
217 #  else
218         time_t t1; /* unsigned long */
219         struct tm st;
220         (void) time(&t1);
221         /*ctime_r(&t1, (char *)timeStr);*/
222         gmtime_r(&t1, &st); /* TODO: localtime_r() with zone offset*/
223         snprintf0(timeStr, (size_t)bufSize,
224                         "20%0.2hd-%0.2hd-%0.2hdT%0.2hd:%0.2hd:%0.2hdZ\n", st.tm_year - 100,
225                         st.tm_mon + 1, st.tm_mday, st.tm_hour, st.tm_min, st.tm_sec);
226 #  endif
227         *(timeStr + strlen(timeStr) - 1) = '\0'; /* strip \n */
228         return timeStr;
229 }
230 
231 /**
232  * Get a human readable time string for logging.
233  * @param timeStr out parameter, e.g. "12:34:46" or "2006-11-14 12:34:46"
234  * @param bufSize The size of timeStr
235  * @return timeStr Your parameter given (for easy usage in printf())
236  */
237 Dll_Export const char *getCurrentTimeStr(char *timeStr, int bufSize) {
238 #  if defined(WINCE)
239       /*http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcekernl/html/_wcesdk_win32_systemtime_str.asp*/
240       SYSTEMTIME st;
241       GetSystemTime(&st);
242       snprintf0(timeStr, bufSize, "%hd:%hd:%hd\n", st.wHour, st.wMinute, st.wSecond);
243       /*wDay, wMilliseconds etc. */
244 #  elif _MSC_VER >= 1400
245       /*__time64_t timer;
246       _time64(&timer);*/
247       time_t t1; /* unsigned long */
248       (void) time(&t1); /* in seconds since the Epoch. 1970 */
249       ctime_s(timeStr, bufSize-1, &t1);
250 #  elif defined(_WINDOWS)
251       time_t t1; /* unsigned long */
252       (void) time(&t1);
253       strncpy0(timeStr, ctime(&t1), bufSize);
254 #  elif defined(__sun)
255       time_t t1; /* unsigned long */
256       (void) time(&t1);
257       ctime_r(&t1, (char *)timeStr, bufSize-1);
258 #  else
259       time_t t1; /* unsigned long */
260       (void) time(&t1);
261       ctime_r(&t1, (char *)timeStr);
262       if (bufSize > 0) bufSize = 0; /* to avoid compiler warning */
263 #  endif
264    *(timeStr + strlen(timeStr) - 1) = '\0'; /* strip \n */
265    return timeStr;
266 }


syntax highlighted by Code2HTML, v. 0.9.1