202 lines
5.2 KiB
C
202 lines
5.2 KiB
C
#ifndef SENTRY_UTILS_H_INCLUDED
|
|
#define SENTRY_UTILS_H_INCLUDED
|
|
|
|
#include "sentry_boot.h"
|
|
|
|
#ifdef SENTRY_PLATFORM_DARWIN
|
|
# include <mach/clock.h>
|
|
# include <mach/mach.h>
|
|
#endif
|
|
#ifdef SENTRY_PLATFORM_WINDOWS
|
|
# include <winnt.h>
|
|
#else
|
|
# include <sys/time.h>
|
|
# include <time.h>
|
|
#endif
|
|
|
|
/**
|
|
* This represents a URL parsed into its different parts.
|
|
*/
|
|
typedef struct {
|
|
char *scheme;
|
|
char *host;
|
|
int port;
|
|
char *path;
|
|
char *query;
|
|
char *fragment;
|
|
char *username;
|
|
char *password;
|
|
} sentry_url_t;
|
|
|
|
/**
|
|
* Parse the given `url` into the pre-allocated `url_out` parameter.
|
|
* Returns 0 on success.
|
|
*/
|
|
int sentry__url_parse(sentry_url_t *url_out, const char *url);
|
|
|
|
/**
|
|
* This will free all the internal members of `url`, but not `url` itself, as
|
|
* that might have been stack allocated.
|
|
*/
|
|
void sentry__url_cleanup(sentry_url_t *url);
|
|
|
|
/**
|
|
* This is the internal representation of a parsed DSN.
|
|
*/
|
|
typedef struct sentry_dsn_s {
|
|
char *raw;
|
|
char *host;
|
|
char *path;
|
|
char *secret_key;
|
|
char *public_key;
|
|
char *project_id;
|
|
int port;
|
|
long refcount;
|
|
bool is_valid;
|
|
bool is_secure;
|
|
} sentry_dsn_t;
|
|
|
|
/**
|
|
* This will parse the DSN URL given in `dsn`.
|
|
*
|
|
* The returned `sentry_dsn_t` will have have its `is_valid` flag set when the
|
|
* DSN has been successfully parsed.
|
|
*/
|
|
sentry_dsn_t *sentry__dsn_new(const char *dsn);
|
|
|
|
/**
|
|
* Increases the reference-count of the DSN.
|
|
*/
|
|
sentry_dsn_t *sentry__dsn_incref(sentry_dsn_t *dsn);
|
|
|
|
/**
|
|
* Decrements the reference-count of the DSN.
|
|
*/
|
|
void sentry__dsn_decref(sentry_dsn_t *dsn);
|
|
|
|
/**
|
|
* This will create a new string, with the contents of the `X-Sentry-Auth`, as
|
|
* described here:
|
|
* https://docs.sentry.io/development/sdk-dev/overview/#authentication
|
|
*/
|
|
char *sentry__dsn_get_auth_header(const sentry_dsn_t *dsn);
|
|
|
|
/**
|
|
* Returns the envelope endpoint url used for normal uploads as a newly
|
|
* allocated string.
|
|
*/
|
|
char *sentry__dsn_get_envelope_url(const sentry_dsn_t *dsn);
|
|
|
|
/**
|
|
* Returns the minidump endpoint url used for uploads done by the out-of-process
|
|
* crashpad backend as a newly allocated string.
|
|
*/
|
|
char *sentry__dsn_get_minidump_url(const sentry_dsn_t *dsn);
|
|
|
|
/**
|
|
* Returns the number of milliseconds since the unix epoch.
|
|
*/
|
|
static inline uint64_t
|
|
sentry__msec_time(void)
|
|
{
|
|
#ifdef SENTRY_PLATFORM_WINDOWS
|
|
// Contains a 64-bit value representing the number of 100-nanosecond
|
|
// intervals since January 1, 1601 (UTC).
|
|
FILETIME file_time;
|
|
SYSTEMTIME system_time;
|
|
GetSystemTime(&system_time);
|
|
SystemTimeToFileTime(&system_time, &file_time);
|
|
|
|
uint64_t timestamp = (uint64_t)file_time.dwLowDateTime
|
|
+ ((uint64_t)file_time.dwHighDateTime << 32);
|
|
timestamp -= 116444736000000000LL; // convert to unix epoch
|
|
timestamp /= 10000LL; // 100ns -> 1ms
|
|
|
|
return timestamp;
|
|
#else
|
|
struct timeval tv;
|
|
return (gettimeofday(&tv, NULL) == 0)
|
|
? (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000
|
|
: 0;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Returns a monotonic millisecond resolution time.
|
|
*
|
|
* This should be used for timeouts and similar.
|
|
* For timestamps, use `sentry__msec_time` instead.
|
|
*/
|
|
static inline uint64_t
|
|
sentry__monotonic_time(void)
|
|
{
|
|
#ifdef SENTRY_PLATFORM_WINDOWS
|
|
static LARGE_INTEGER qpc_frequency = { { 0, 0 } };
|
|
|
|
if (!qpc_frequency.QuadPart) {
|
|
QueryPerformanceFrequency(&qpc_frequency);
|
|
}
|
|
|
|
// Fallback to GetTickCount() on QPC fail
|
|
if (!qpc_frequency.QuadPart) {
|
|
# if _WIN32_WINNT >= 0x0600
|
|
return GetTickCount64();
|
|
# else
|
|
return GetTickCount();
|
|
# endif
|
|
}
|
|
|
|
LARGE_INTEGER qpc_counter;
|
|
QueryPerformanceCounter(&qpc_counter);
|
|
return qpc_counter.QuadPart * 1000 / qpc_frequency.QuadPart;
|
|
#elif defined(SENTRY_PLATFORM_DARWIN)
|
|
|
|
// try `clock_gettime` first if available,
|
|
// fall back to `host_get_clock_service` otherwise
|
|
# if defined(MAC_OS_X_VERSION_10_12) && __has_builtin(__builtin_available)
|
|
if (__builtin_available(macOS 10.12, *)) {
|
|
struct timespec tv;
|
|
return (clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
|
|
? (uint64_t)tv.tv_sec * 1000 + tv.tv_nsec / 1000000
|
|
: 0;
|
|
}
|
|
# endif
|
|
|
|
clock_serv_t cclock;
|
|
mach_timespec_t mts;
|
|
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
|
clock_get_time(cclock, &mts);
|
|
mach_port_deallocate(mach_task_self(), cclock);
|
|
return (uint64_t)mts.tv_sec * 1000 + mts.tv_nsec / 1000000;
|
|
#else
|
|
struct timespec tv;
|
|
return (clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
|
|
? (uint64_t)tv.tv_sec * 1000 + tv.tv_nsec / 1000000
|
|
: 0;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Formats a timestamp (milliseconds since epoch) into ISO8601 format.
|
|
*/
|
|
char *sentry__msec_time_to_iso8601(uint64_t time);
|
|
|
|
/**
|
|
* Parses a ISO8601 formatted string into a millisecond resolution timestamp.
|
|
* This only accepts the format `YYYY-MM-DD'T'hh:mm:ss(.zzz)'Z'`, which is
|
|
* produced by the `sentry__msec_time_to_iso8601` function.
|
|
*/
|
|
uint64_t sentry__iso8601_to_msec(const char *iso);
|
|
|
|
/**
|
|
* Locale independent (or rather, using "C" locale) `strtod`.
|
|
*/
|
|
double sentry__strtod_c(const char *ptr, char **endptr);
|
|
|
|
/**
|
|
* Locale independent (or rather, using "C" locale) `snprintf`.
|
|
*/
|
|
int sentry__snprintf_c(char *buf, size_t buf_size, const char *fmt, ...);
|
|
|
|
#endif
|