DSL
dsl.cpp
1 //@AUTOHEADER@BEGIN@
2 /***********************************************************************\
3 | Drift Standard Libraries v1.01 |
4 | Copyright 2010-2023 Drift Solutions / Indy Sams |
5 | Docs and more information available at https://www.driftsolutions.dev |
6 | This file released under the 3-clause BSD license, |
7 | see included DSL.LICENSE.TXT file for details. |
8 \***********************************************************************/
9 //@AUTOHEADER@END@
10 
11 #include <drift/dslcore.h>
12 #include <drift/GenLib.h>
13 #include <drift/Mutex.h>
14 #include <drift/Threading.h>
15 #include <drift/os_version.h>
16 #include <stdarg.h>
17 #if defined(WIN32)
18 #include <tchar.h>
19 #endif
20 
21 DSL_Mutex * dslMutex()
22 {
23  static DSL_Mutex actualMutex;
24  return &actualMutex;
25 }
26 
27 int dsl_init_count = 0;
28 bool dsl_init_ret = false;
29 uint32 dsl_runtime_options = 0;
30 
31 vector<DSL_LIBRARY_FUNCTIONS> dsl_lib_funcs;
32 
33 void DSL_CC dsl_register_lib(DSL_LIBRARY_FUNCTIONS funcs) {
34  AutoMutexPtr(dslMutex());
35  if (dsl_init_count > 0 && dsl_init_ret) {
36  //if this is somehow called late, init the library now
37  funcs.has_init = true;
38  dsl_runtime_options |= funcs.nOption;
39  }
40  dsl_lib_funcs.push_back(funcs);
41 }
42 DSL_Library_Registerer::~DSL_Library_Registerer() {}
43 void DSL_Library_Registerer::EnsureLinked() {}
44 
45 bool DSL_CC dsl_init() {
46  AutoMutexPtr(dslMutex());
47  dsl_init_count++;
48 #if defined(DEBUG)
49  //printf("dsl_init: %d\n", dsl_init_count);
50 #endif
51  if (dsl_init_count > 1) {
52  return dsl_init_ret;
53  }
54  dsl_init_ret = false;
55 
56 #if defined(WIN32)
57  WSADATA wsd;
58  if (WSAStartup(MAKEWORD(2,2),&wsd) != 0) {
59  printf("DSL: Error initializing Winsock!\n");
60  return false;
61  }
62 #else
63  GetTickCount64(); //seeds the start time
64 #endif
65 
66  for (auto x = dsl_lib_funcs.begin(); x != dsl_lib_funcs.end(); x++) {
67  if (x->init == NULL || x->init()) {
68  x->has_init = true;
69  dsl_runtime_options |= x->nOption;
70  }
71  }
72 
73  dsl_init_ret = true;
74  return true;
75 }
76 
77 void dsl_cleanup() {
78  AutoMutexPtr(dslMutex());
79  if (dsl_init_count > 0) {
80  dsl_init_count--;
81  }
82 #if defined(DEBUG)
83  //printf("dsl_cleanup: %d\n", dsl_init_count);
84 #endif
85  if (dsl_init_count > 0) {
86  return;
87  }
88 
89  for (auto x = dsl_lib_funcs.begin(); x != dsl_lib_funcs.end(); x++) {
90  if (x->has_init && x->cleanup != NULL) {
91  x->cleanup();
92  }
93  x->has_init = false;
94  dsl_runtime_options &= ~x->nOption;
95  }
96 
97 #if defined(WIN32)
98  WSACleanup();
99 #endif
100 }
101 
102 void DSL_CC dsl_get_version(DSL_VERSION * ver) {
103  //DSL_OPTION_SSL
104  ver->major = 1;
105  ver->minor = 1;
106  ver->compile_options = 0;
107 #if defined(ENABLE_ZLIB)
108  ver->compile_options |= DSL_OPTION_ZLIB;
109 #endif
110 #if defined(MEMLEAK)
111  ver->compile_options |= DSL_OPTION_MEMLEAK;
112 #endif
113  ver->compile_options |= dsl_runtime_options;
114 }
115 
116 const char * DSL_CC dsl_get_version_string() {
117  AutoMutexPtr(dslMutex());
118  static char version[64]={0};
119 
120  DSL_VERSION ver;
121  dsl_get_version(&ver);
122  sprintf(version, "%d.%02d", ver.major, ver.minor);
123 #if defined(ENABLE_ZLIB)
124  sstrcat(version, "-zlib");
125 #endif
126 #if defined(MEMLEAK)
127  sstrcat(version, "-memleak");
128 #endif
129  if (dsl_runtime_options & DSL_OPTION_OPENSSL) {
130  sstrcat(version, "-openssl");
131  }
132  if (dsl_runtime_options & DSL_OPTION_GNUTLS) {
133  sstrcat(version, "-gnutls");
134  }
135  if (dsl_runtime_options & DSL_OPTION_CURL) {
136  sstrcat(version, "-curl");
137  }
138  if (dsl_runtime_options & DSL_OPTION_MYSQL) {
139  sstrcat(version, "-mysql");
140  }
141  if (dsl_runtime_options & DSL_OPTION_PHYSFS) {
142  sstrcat(version, "-physfs");
143  }
144  if (dsl_runtime_options & DSL_OPTION_SQLITE) {
145  sstrcat(version, "-sqlite");
146  }
147  if (dsl_runtime_options & DSL_OPTION_SODIUM) {
148  sstrcat(version, "-sodium");
149  }
150  return version;
151 }
152 
153 bool DSL_CC dsl_rdrand(uint8 * buf, size_t len);
154 
155 bool DSL_CC dsl_fill_random_buffer(uint8 * buf, size_t len, bool secure_only) {
156  int tries = 0;
157 
158 #if !defined(WIN32)
159  size_t left = len;
160  uint8 *p = buf;
161 #if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 25))
162  while (left > 0 && tries++ < 10) {
163  int grn = getrandom(p, left, GRND_NONBLOCK);
164  if (grn > 0) {
165  left -= grn;
166  p += grn;
167  } else {
168  tries++;
169  }
170  }
171  tries = 0;
172 #elif defined(SYS_getrandom)
173  while (left > 0 && tries++ < 10) {
174  int grn = syscall(SYS_getrandom, p, left, GRND_NONBLOCK);
175  if (grn > 0) {
176  left -= grn;
177  p += grn;
178  } else {
179  tries++;
180  }
181  }
182  tries = 0;
183 #endif
184  while (left > 0 && tries++ < 10) {
185  FILE * fp = fopen("/dev/urandom", "rb");
186  if (fp == NULL) {
187  fp = fopen("/dev/random", "rb");
188  }
189  if (fp != NULL) {
190  while (left > 0) {
191  size_t n = fread(p, 1, left, fp);
192  if (n > 0) {
193  p += n;
194  left -= n;
195  } else {
196  break;
197  }
198  }
199  fclose(fp);
200  }
201  }
202  if (left == 0) {
203  return true;
204  }
205 #else
206  while (tries++ < 10) {
207  if (RtlGenRandom(buf, (ULONG)len)) {
208  return true;
209  }
210  }
211 #endif
212 
213 #if defined(WIN32) || defined(GCC_RDRAND)
214  // try RDRAND if supported
215  if (dsl_rdrand(buf, len)) {
216  return true;
217  }
218 #endif
219 
220  if (!secure_only) {
221  // crappy fallback
222  for (unsigned int i = 0; i < len; i++) {
223  buf[i] = rand() % 256;
224  }
225  return true;
226  }
227 
228  return false;
229 }
230 
231 #if defined(WIN32) || defined(GCC_RDRAND)
232 // On Linux this uses malloc somewhere so have to move it down here so it's not throwing #error
233 #include <immintrin.h>
234 
235 bool DSL_CC dsl_rdrand(uint8 * buf, size_t len) {
236  if (!InstructionSet::RDRAND()) {
237  return false;
238  }
239  int tries = 0;
240  size_t left = len;
241  uint8 *p = buf;
242 
243  while (left > 0 && tries < 10) {
244 #if defined(WIN64) || defined(__x86_64__)
245  if (left >= 8) {
246 #ifdef WIN32
247  uint64_t tmp;
248 #else
249  long long unsigned int tmp;
250 #endif
251  if (_rdrand64_step(&tmp)) {
252  memcpy(p, &tmp, sizeof(tmp));
253  p += sizeof(tmp);
254  left -= sizeof(tmp);
255  } else {
256  tries++;
257  }
258  } else
259 #endif
260  if (left >= 4) {
261  uint32_t tmp;
262  if (_rdrand32_step(&tmp)) {
263  memcpy(p, &tmp, sizeof(tmp));
264  p += sizeof(tmp);
265  left -= sizeof(tmp);
266  } else {
267  tries++;
268  }
269  } else {
270  uint16_t tmp;
271  if (_rdrand16_step(&tmp)) {
272  size_t toGen = (left < sizeof(tmp)) ? left : sizeof(tmp);
273  memcpy(p, &tmp, toGen);
274  p += toGen;
275  left -= toGen;
276  } else {
277  tries++;
278  }
279  }
280  }
281 
282  return (left == 0) ? true : false;
283 }
284 
285 #endif // defined(WIN32) || defined(GCC_RDRAND)
286 
287 char * DSL_CC dsl_mprintf(const char * fmt, ...) {
288  va_list va;
289  va_start(va, fmt);
290  char * ret = dsl_vmprintf(fmt, va);
291  va_end(va);
292  return ret;
293 }
294 string mprintf(const string fmt, ...) {
295  va_list va;
296  va_start(va, fmt);
297  char * tmp = dsl_vmprintf(fmt.c_str(), va);
298  va_end(va);
299  string ret = tmp;
300  dsl_free(tmp);
301  return ret;
302 }
303 
304 char * DSL_CC dsl_vmprintf(const char * fmt, va_list va) {
305 #if defined(WIN32)
306  int len = vscprintf(fmt, va) + 1;
307 #else
308  int len = vsnprintf(NULL, 0, fmt, va) + 1;
309 #endif
310  if (len < 1) {
311  return dsl_strdup("vsnprintf error");
312  }
313  char * ret = (char *)dsl_malloc(len);
314  if (vsnprintf(ret, len, fmt, va) < 0) {
315  return dsl_strdup("vsnprintf error");
316  }
317  return ret;
318 }
319 
320 wchar_t * DSL_CC dsl_wmprintf(const wchar_t * fmt, ...) {
321  va_list va;
322  va_start(va, fmt);
323 #if defined(WIN32)
324  int len = vscwprintf(fmt, va);
325  wchar_t * ret = (wchar_t *)dsl_malloc((len+1)*sizeof(wchar_t));
326  wvsprintfW(ret, fmt, va);
327 #else
328  wchar_t * ret = NULL;
329 #endif
330  va_end(va);
331  return ret;
332 }
333 
334 #undef malloc
335 #undef realloc
336 #undef strdup
337 #undef wcsdup
338 #undef free
339 
340 void * DSL_CC dsl_malloc(size_t lSize) { return malloc(lSize); }
341 void * DSL_CC dsl_zmalloc(size_t lSize) { return calloc(1, lSize); }
342 void * DSL_CC dsl_realloc(void * ptr, size_t lSize) { return realloc(ptr, lSize); }
343 char * DSL_CC dsl_strdup(const char * ptr) { return strdup(ptr); }
344 wchar_t * DSL_CC dsl_wcsdup(const wchar_t * ptr) { return wcsdup(ptr); }
345 void DSL_CC dsl_free(void * ptr) { free(ptr); }
346 void DSL_CC dsl_freep(void ** ptr) {
347  if (*ptr != NULL) {
348  free(*ptr);
349  *ptr = NULL;
350  }
351 }
string mprintf(const string fmt,...)
Definition: dsl.cpp:294
const char *DSL_CC dsl_get_version_string()
Returns the DSL version string.
Definition: dsl.cpp:116
wchar_t *DSL_CC dsl_wmprintf(const wchar_t *fmt,...)
Definition: dsl.cpp:320
void DSL_CC dsl_free(void *ptr)
Definition: dsl.cpp:345
void *DSL_CC dsl_zmalloc(size_t lSize)
Definition: dsl.cpp:341
void dsl_cleanup()
Definition: dsl.cpp:77
char *DSL_CC dsl_vmprintf(const char *fmt, va_list va)
Definition: dsl.cpp:304
void DSL_CC dsl_freep(void **ptr)
Definition: dsl.cpp:346
bool DSL_CC dsl_init()
Definition: dsl.cpp:45
void DSL_CC dsl_get_version(DSL_VERSION *ver)
Fills in a DSL_VERSION struct you provide.
Definition: dsl.cpp:102
char *DSL_CC dsl_mprintf(const char *fmt,...)
Definition: dsl.cpp:287
bool DSL_CC dsl_fill_random_buffer(uint8 *buf, size_t len, bool secure_only)
Definition: dsl.cpp:155
DSL_API uint64 DSL_CC GetTickCount64()
Linux version of GetTickCount64.
Definition: GenLib.cpp:795
#define sstrcat(x, y)
Definition: GenLib.h:106
uint32 compile_options
See the DSL_OPTION_* defines. Will be a bitmask of 0 or more of them.
Definition: dslcore.h:103