Watt-32 tcp/ip  2.2 dev-rel.10
winmisc.c
Go to the documentation of this file.
1 
32 #include "socket.h"
33 #include "pcdns.h"
34 #include "get_xby.h"
35 #include "cpumodel.h"
36 #include "run.h"
37 #include "misc.h"
38 
39 #if defined(WIN32) /* rest of file */
40 
41 #include "packet32.h"
42 #include "win_dll.h"
43 
44 #include <w32-fakes/winsock2.h>
45 #include <wchar.h>
46 
47 #define STATUS_SUCCESS 0
48 
49 CRITICAL_SECTION _watt_crit_sect;
50 BOOL _watt_is_win9x = FALSE;
51 BOOL _watt_is_wow64 = FALSE;
52 BOOL _watt_use_bugtrap = TRUE;
53 BOOL _watt_is_gui_app = FALSE;
54 
55 HANDLE stdin_hnd = INVALID_HANDLE_VALUE;
56 HANDLE stdout_hnd = INVALID_HANDLE_VALUE;
57 
58 CONSOLE_SCREEN_BUFFER_INFO console_info;
59 
60 #if defined(USE_STACKWALKER)
61 static void (MS_CDECL *orig_abort_handler)(int) = NULL;
62 #endif
63 
64 /* WinBase.h (SDK) stuff added for Windows 7.
65  */
66 #ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
67 #define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 0x1
68 #endif
69 
70 #ifndef BASE_SEARCH_PATH_PERMANENT
71 #define BASE_SEARCH_PATH_PERMANENT 0x8000
72 #endif
73 
74 /*
75  * 'dns_windns' bits.
76  */
77 #define WINDNS_QUERY_A4 0x0001
78 #define WINDNS_QUERY_A6 0x0002
79 #define WINDNS_QUERY_PTR4 0x0004
80 #define WINDNS_QUERY_PTR6 0x0008
81 #define WINDNS_CACHEPUT_A4 0x0100
82 #define WINDNS_CACHEPUT_A6 0x0200
83 
84 #ifndef DNS_TYPE_AAAA
85 #define DNS_TYPE_AAAA 0x001C
86 #endif
87 
88 #ifndef DNS_ERROR_RESPONSE_CODES_BASE
89 #define DNS_ERROR_RESPONSE_CODES_BASE 9000
90 #endif
91 
92 #ifndef DNS_ERROR_RCODE_LAST
93 #define DNS_ERROR_RCODE_LAST 9018
94 #endif
95 
96 #if defined(__MINGW32__) /* Missing in <winnt.h>, but is in libkernel32.a */
97  __declspec(dllimport) void WINAPI RtlCaptureContext (CONTEXT *ContextRecord);
98 #endif
99 
100 /*
101  * Various stuff to initialise.
102  */
103 static BOOL get_win_version (WORD *ver, BOOL *is_win9x)
104 {
105  OSVERSIONINFO ovi;
106  DWORD os_ver = GetVersion();
107  DWORD major_ver = LOBYTE (LOWORD(os_ver));
108 
109  *is_win9x = (os_ver >= 0x80000000 && major_ver >= 4);
110 
111  memset (&ovi, 0, sizeof(ovi));
112  ovi.dwOSVersionInfoSize = sizeof(ovi);
113 
114  /* We only support Win-NT style OSes.
115  */
116  if (!GetVersionEx(&ovi) || ovi.dwPlatformId != VER_PLATFORM_WIN32_NT)
117  return (FALSE);
118 
119  *ver = (WORD)(ovi.dwMajorVersion << 8) + (WORD)ovi.dwMinorVersion;
120  return (TRUE);
121 }
122 
123 /*
124  * Check if program is a GUI app with no stdout handle.
125  */
126 static BOOL is_gui_app (void)
127 {
128  const IMAGE_DOS_HEADER *dos;
129  const IMAGE_NT_HEADERS *nt;
130  HMODULE mod = GetModuleHandle (NULL);
131  HANDLE hnd;
132 
133  if (!mod)
134  return (FALSE);
135 
136  /* A GUI app should have no stdout handle.
137  */
138  hnd = GetStdHandle (STD_OUTPUT_HANDLE);
139  if (hnd != INVALID_HANDLE_VALUE && GetFileType(hnd) != FILE_TYPE_UNKNOWN)
140  return (FALSE);
141 
142  dos = (const IMAGE_DOS_HEADER*) mod;
143  nt = (const IMAGE_NT_HEADERS*) ((const BYTE*)mod + dos->e_lfanew);
144  return (nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI);
145 }
146 
147 /*
148  * \todo: make a GUI list-control with "Abort, Show-stack" etc.
149  * mimicking the normal console.
150  */
151 int MS_CDECL gui_printf (const char *fmt, ...)
152 {
153  char buf[1024];
154  int len;
155  char *prog_name, *s;
156  DWORD mb_flags;
157  va_list args;
158 
159  va_start (args, fmt);
160  len = VSNPRINTF (buf, sizeof(buf), fmt, args);
161 
162  s = (char*) get_argv0();
163 #if 0
164  if ((prog_name = strrchr(s,'\\')) == NULL &&
165  (prog_name = strrchr(s, ':')) == NULL)
166  prog_name = s;
167  else prog_name++;
168 #else
169  prog_name = s; /* Show the full program-name */
170 #endif
171 
172  mb_flags = MB_ICONSTOP | MB_SETFOREGROUND;
173  mb_flags |= _watt_is_win9x ? MB_SYSTEMMODAL : MB_TASKMODAL;
174  MessageBoxA (NULL, buf, prog_name, mb_flags);
175 
176  va_end (args);
177  return (len);
178 }
179 
180 static void win32_exit (void)
181 {
182  stdin_hnd = INVALID_HANDLE_VALUE;
183  stdout_hnd = INVALID_HANDLE_VALUE;
184 
185  unload_dynamic_table (dyn_funcs, dyn_funcs_num);
186 
187 #if defined(__LCC__)
188  DeleteCriticalSection ((struct _CRITICAL_SECTION*)&_watt_crit_sect);
189 #else
190  DeleteCriticalSection (&_watt_crit_sect);
191 #endif
192  _watt_crit_sect.SpinCount = -1;
193 }
194 
195 /*
196  * Return err-number+string for 'err'. Use only with GetLastError().
197  * (or WSAGetLastError() if Winsock is used somehow ... linked dynamically?).
198  * Does not handle libc errno's. Remove trailing [\r\n.]
199  */
200 char * W32_CALL win_strerror (DWORD err)
201 {
202  static char buf[512+20];
203  char err_buf[512], *p;
204 
205  if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
206  LANG_NEUTRAL, err_buf, sizeof(err_buf)-1, NULL))
207  strcpy (err_buf, "Unknown error");
208  SNPRINTF (buf, sizeof(buf), "%lu/0x%lX: %s", err, err, err_buf);
209  rip (buf);
210  p = strrchr (buf, '.');
211  if (p && p[1] == '\0')
212  *p = '\0';
213  return (buf);
214 }
215 
219 BOOL GetFileVersion (const char *file_name,
220  char *version_buf,
221  size_t version_buf_len)
222 {
223  DWORD ver_info_size; /* Size of version information block */
224  DWORD err, ver_hnd = 0; /* An 'ignored' parameter, always '0' */
225  UINT bytes_read;
226  char sub_block[64];
227  void *res_buf, *vff_info;
228 
229  const struct LANG_AND_CODEPAGE {
230  WORD language;
231  WORD code_page;
232  } *lang_info;
233  void *lang_info_ptr;
234 
235  if (!p_GetFileVersionInfoSizeA || !p_GetFileVersionInfoA || !p_VerQueryValueA)
236  {
237  CONSOLE_MSG (2, ("Missing functions from version.dll\n"));
238  return (FALSE);
239  }
240 
241  /* Pull out the version information
242  */
243  ver_info_size = (*p_GetFileVersionInfoSizeA) ((char*)file_name, &ver_hnd);
244  CONSOLE_MSG (2, ("file %s, ver-size %lu\n", file_name, ver_info_size));
245 
246  if (!ver_info_size)
247  {
248  err = GetLastError();
249  CONSOLE_MSG (2, ("failed to call GetFileVersionInfoSizeA; %s\n",
250  win_strerror(err)));
251  return (FALSE);
252  }
253 
254  vff_info = alloca (ver_info_size);
255 
256  if (!(*p_GetFileVersionInfoA) ((char*)file_name, ver_hnd,
257  ver_info_size, vff_info))
258  {
259  err = GetLastError();
260  CONSOLE_MSG (2, ("failed to call GetFileVersionInfoA; %s\n",
261  win_strerror(err)));
262  return (FALSE);
263  }
264 
265  /* Read the list of languages and code pages.
266  */
267  if (!(*p_VerQueryValueA) (vff_info, "\\VarFileInfo\\Translation",
268  &lang_info_ptr, &bytes_read) ||
269  bytes_read < sizeof(*lang_info))
270  {
271  err = GetLastError();
272  CONSOLE_MSG (2, ("failed to call VerQueryValueA; %s\n",
273  win_strerror(err)));
274  return (FALSE);
275  }
276 
277  lang_info = (const struct LANG_AND_CODEPAGE*) lang_info_ptr;
278 
279  /* Create the file version string for the first (i.e. the only
280  * one) language.
281  */
282  sprintf (sub_block, "\\StringFileInfo\\%04x%04x\\FileVersion",
283  lang_info->language, lang_info->code_page);
284 
285  /* Retrieve the file version string for the language. 'res_buf' will
286  * point into 'vff_info'. Hence it doesn't have to be freed.
287  */
288  if (!(*p_VerQueryValueA) (vff_info, sub_block, &res_buf, &bytes_read))
289  {
290  err = GetLastError();
291  CONSOLE_MSG (2, ("failed to call VerQueryValueA; %s\n",
292  win_strerror(err)));
293  return (FALSE);
294  }
295 
296  CONSOLE_MSG (2, ("sub-block '%s' -> '%.*s'\n",
297  sub_block, bytes_read, (const char*)res_buf));
298 
299  if (strlen(res_buf) >= version_buf_len)
300  {
301  CONSOLE_MSG (2, ("GetFileVersionA(): input buffer too small\n"));
302  return (FALSE);
303  }
304  strcpy (version_buf, res_buf);
305  return (TRUE);
306 }
307 
308 
309 #if defined(USE_STACKWALKER)
310 
311 #include "stkwalk.h"
312 
313 static void MS_CDECL new_abort_handler (int sig)
314 {
315  CONTEXT ctx;
316 
317  memset (&ctx, 0, sizeof(ctx));
318  ctx.ContextFlags = CONTEXT_FULL;
319  RtlCaptureContext (&ctx);
320 
325  CONSOLE_MSG (0, ("\nabort() called. Backtrace:\n"));
326  ShowStack (GetCurrentThread(), &ctx, NULL);
327 
328  if (orig_abort_handler)
329  (*orig_abort_handler) (sig);
330  _exit (-1);
331 }
332 #endif
333 
334 static void init_win_abort (void)
335 {
336 #if defined(USE_STACKWALKER)
337  if (!IsDebuggerPresent())
338  {
339  orig_abort_handler = signal (SIGABRT, new_abort_handler);
340 #ifdef _MSC_VER
341  _set_abort_behavior (0, _WRITE_ABORT_MSG);
342 #endif
343  }
344 #endif
345 }
346 
347 #if defined(USE_BUGTRAP)
348 
349 static void CALLBACK pre_err_handler (INT_PTR arg)
350 {
351  INT_PTR handle = arg;
352 
353  if (!handle)
354  return;
355 
356  (*p_BT_InsLogEntryF) (handle, BTLL_INFO, _T("Starting Watt-32 crash-report:"));
357 
358  if (_watt_assert_buf[0])
359  (*p_BT_InsLogEntryF) (handle, BTLL_IMPORTANT, _watt_assert_buf);
360  (*p_BT_CloseLogFile) (handle);
361 }
362 
363 static int init_win_bugtrap (void)
364 {
365  BUGTRAP_LOGECHOTYPE bt_log_mode = 0;
366  INT_PTR bt_log_handle = 0;
367 
368  if (!p_BT_SetAppName || !p_BT_InstallSehFilter ||
369  !p_BT_SetFlags || !p_BT_SetLogFlags ||
370  !p_BT_SetReportFormat || !p_BT_OpenLogFile ||
371  !p_BT_SetLogSizeInEntries || !p_BT_SetLogEchoMode ||
372  !p_BT_AddLogFile)
373  return (0);
374 
375  (*p_BT_SetAppName) ("Watt-32_library");
376 //(*p_BT_SetSupportEMail) ("gvanem@yahoo.no");
377 
378  (*p_BT_InstallSehFilter)();
379  (*p_BT_SetFlags) (BTF_DETAILEDMODE | BTF_ATTACHREPORT);
380  (*p_BT_SetReportFormat) (BTRF_TEXT);
381 
382  bt_log_handle = (*p_BT_OpenLogFile) ("watt-32.dll.log", BTLF_TEXT);
383  (*p_BT_SetLogSizeInEntries) (bt_log_handle, 100);
384  (*p_BT_SetLogFlags) (bt_log_handle, BTLF_SHOWTIMESTAMP);
385 
386  bt_log_mode = BTLE_DBGOUT;
387  if (!_watt_is_gui_app)
388  bt_log_mode |= BTLE_STDERR;
389  (*p_BT_SetLogEchoMode) (bt_log_handle, bt_log_mode);
390 
391 #if 0
392  PCTSTR pszLogFileName = (*p_BT_GetLogFileName) (bt_log_handle);
393  (*p_BT_AddLogFile) (pszLogFileName);
394 #endif
395 
396  (*p_BT_SetPreErrHandler) (pre_err_handler, bt_log_handle);
397 
398  return (1);
399 }
400 #endif /* USE_BUGTRAP */
401 
402 
403 /*
404  * Called from init_misc() to initialise Win32 specific things.
405  */
406 BOOL init_win_misc (void)
407 {
408  char env[20];
409 
410 #if defined(__LCC__)
411  InitializeCriticalSection ((struct _CRITICAL_SECTION*)&_watt_crit_sect);
412 #else
413  InitializeCriticalSection (&_watt_crit_sect);
414 #endif
415 
416  if ((GetEnvironmentVariableA("WATT32-NOEXC", env, sizeof(env)) ||
417  GetEnvironmentVariableA("WATT32-NOEXCEPT", env, sizeof(env))) &&
418  env[0] != '0')
419  _watt_use_bugtrap = FALSE;
420 
421  _watt_is_gui_app = is_gui_app();
422 
423  _watt_os_ver = 0x0400; /* defaults to Win-NT 4.0 */
424  get_win_version (&_watt_os_ver, &_watt_is_win9x);
425 
426  if (!_watt_is_gui_app)
427  {
428  stdin_hnd = GetStdHandle (STD_INPUT_HANDLE);
429  stdout_hnd = GetStdHandle (STD_OUTPUT_HANDLE);
430  GetConsoleScreenBufferInfo (stdout_hnd, &console_info);
431  }
432 
433  load_dynamic_table (dyn_funcs, dyn_funcs_num);
434 
435 #ifdef WIN64
436  if (p_IsWow64Process)
437  (*p_IsWow64Process) (GetCurrentProcess(), &_watt_is_wow64);
438 #endif
439 
440  if (_watt_use_bugtrap)
441  {
442 #if defined(USE_BUGTRAP)
443  init_win_bugtrap();
444 #endif
445  init_win_abort();
446  }
447 
448  RUNDOWN_ADD (win32_exit, 310);
449  return (TRUE);
450 }
451 
452 #if defined(HAVE_WINDNS_H)
453 /*
454  * Perform a query on the WinDns cache. We ask only for
455  * 'type'; An address (A/AAAA records) or a name (PTR record).
456  */
457 static BOOL WinDnsQueryCommon (WORD type, const void *what,
458  void *result, size_t size)
459 {
460  DNS_RECORD *rr, *dr = NULL;
461  DNS_STATUS rc;
462  BOOL found;
463  DWORD opt = DNS_QUERY_NO_WIRE_QUERY | /* query the cache only */
464  DNS_QUERY_NO_NETBT | /* no NetBT names */
465  DNS_QUERY_NO_HOSTS_FILE; /* no Winsock hosts file */
466 
467  from_windns = FALSE;
468 
469  if (!p_DnsQuery_A || !p_DnsFree)
470  return (FALSE);
471 
472  rc = (*p_DnsQuery_A) ((const char*)what, type, opt, NULL, &dr, NULL);
473 
474  CONSOLE_MSG (2, ("DnsQuery_A: type %d, dr %p: %s\n",
475  type, dr, win_strerror(rc)));
476 
477  if (rc != ERROR_SUCCESS || !dr)
478  return (FALSE);
479 
480  dom_ttl = dr->dwTtl;
481  found = FALSE;
482 
483  for (rr = dr; rr; rr = rr->pNext)
484  {
485  CONSOLE_MSG (2, ("RR-type: %d: ", rr->wType));
486 
487  /* Use only 1st A/AAAA record
488  */
489  if (rr->wType == DNS_TYPE_A && type == DNS_TYPE_A)
490  {
491  DWORD ip = ntohl (rr->Data.A.IpAddress);
492 
493  CONSOLE_MSG (2, ("A: %s, ttl %lus\n",
494  _inet_ntoa(NULL,ip), rr->dwTtl));
495  if (!found)
496  *(DWORD*) result = ip;
497  found = TRUE;
498  }
499 
500 #if defined(USE_BSD_API) || defined(USE_IPV6)
501  else if (rr->wType == DNS_TYPE_AAAA && type == DNS_TYPE_AAAA)
502  {
503  const void *ip6 = &rr->Data.AAAA.Ip6Address.IP6Dword[0];
504 
505  CONSOLE_MSG (2, ("AAAA: %s\n", _inet6_ntoa(ip6)));
506  if (!found)
507  memcpy (result, ip6, size);
508  found = TRUE;
509  }
510 #endif
511 
512  else if (rr->wType == DNS_TYPE_PTR && type == DNS_TYPE_PTR)
513  {
514  _tcsncpy (result, dr->Data.PTR.pNameHost, size);
515  CONSOLE_MSG (2, ("PTR: %" TSTR2ASCII_FMT "\n", (const TCHAR*)result));
516  }
517  else if (rr->wType == DNS_TYPE_CNAME)
518  {
519 #ifdef UNICODE
520  const char *src = wstring_acp (dr->Data.CNAME.pNameHost);
521 #else
522  const char *src = dr->Data.CNAME.pNameHost;
523 #endif
524  _strlcpy (dom_cname, src, sizeof(dom_cname));
525  CONSOLE_MSG (2, ("CNAME: %s\n", dom_cname));
526  }
527  else
528  CONSOLE_MSG (2, ("\n"));
529  }
530  (*p_DnsFree) (dr, DnsFreeRecordList);
531  from_windns = found;
532  return (TRUE);
533 }
534 #endif /* HAVE_WINDNS_H */
535 
536 
537 BOOL WinDnsQuery_A4 (const char *name, DWORD *ip)
538 {
539 #if defined(HAVE_WINDNS_H)
540  if (!(dns_windns & WINDNS_QUERY_A4))
541  return (FALSE);
542  return WinDnsQueryCommon (DNS_TYPE_A, name, ip, sizeof(*ip));
543 #else
544  ARGSUSED (name);
545  ARGSUSED (ip);
546  return (FALSE);
547 #endif
548 }
549 
550 BOOL WinDnsQuery_A6 (const char *name, void *ip)
551 {
552 #if defined(HAVE_WINDNS_H)
553  if (!(dns_windns & WINDNS_QUERY_A6))
554  return (FALSE);
555  return WinDnsQueryCommon (DNS_TYPE_AAAA, name, ip, sizeof(ip6_address));
556 #else
557  ARGSUSED (name);
558  ARGSUSED (ip);
559  return (FALSE);
560 #endif
561 }
562 
563 BOOL WinDnsQuery_PTR4 (DWORD ip, TCHAR *name, size_t size)
564 {
565 #if defined(HAVE_WINDNS_H)
566  if (!(dns_windns & WINDNS_QUERY_PTR4))
567  return (FALSE);
568  return WinDnsQueryCommon (DNS_TYPE_PTR, &ip, name, size);
569 #else
570  ARGSUSED (ip);
571  ARGSUSED (name);
572  ARGSUSED (size);
573  return (FALSE);
574 #endif
575 }
576 
577 BOOL WinDnsQuery_PTR6 (const void *ip, TCHAR *name, size_t size)
578 {
579 #if defined(HAVE_WINDNS_H)
580  if (!(dns_windns & WINDNS_QUERY_PTR6))
581  return (FALSE);
582  return WinDnsQueryCommon (DNS_TYPE_PTR, &ip, name, size);
583 #else
584  ARGSUSED (ip);
585  ARGSUSED (name);
586  ARGSUSED (size);
587  return (FALSE);
588 #endif
589 }
590 
591 /*
592  * This doesn't seem to simply put a name/IP pair in the
593  * local cache, but do a complete registration with the
594  * Winsock registered DNS server(s). Hence off by default.
595  */
596 BOOL WinDnsCachePut_A4 (const char *name, DWORD ip4)
597 {
598 #if defined(HAVE_WINDNS_H)
599  DNS_RECORD rr;
600  DNS_STATUS rc;
601  DWORD opt = DNS_UPDATE_SECURITY_OFF |
602  DNS_UPDATE_CACHE_SECURITY_CONTEXT;
603 
604  if (!p_DnsModifyRecordsInSet_A ||
605  !(dns_windns & WINDNS_CACHEPUT_A4))
606  return (FALSE);
607 
608  memset (&rr, 0, sizeof(rr));
609 
610 #ifdef UNICODE
611  rr.pName = _tcsdup (astring_acp(name));
612 #else
613  rr.pName = strdup (name);
614 #endif
615 
616  rr.wType = DNS_TYPE_A;
617  rr.Data.A.IpAddress = htonl (ip4);
618  rr.wDataLength = sizeof(rr.Data.A);
619 #ifdef USE_BSD_API
620  rr.dwTtl = netdbCacheLife;
621 #else
622  rr.dwTtl = MAX_CACHE_LIFE;
623 #endif
624 
625  rc = (*p_DnsModifyRecordsInSet_A) (&rr, NULL, opt,
626  NULL, NULL, NULL);
627  if (rr.pName)
628  free (rr.pName);
629 
630  CONSOLE_MSG (2, ("DnsModifyRecordsInSet_A: %s ", win_strerror(rc)));
631 
632  if (rc >= DNS_ERROR_RESPONSE_CODES_BASE && rc <= DNS_ERROR_RCODE_LAST)
633  dns_windns &= ~WINDNS_CACHEPUT_A4; /* don't do this again */
634  return (rc == ERROR_SUCCESS);
635 #else
636  ARGSUSED (name);
637  ARGSUSED (ip4);
638  return (FALSE);
639 #endif /* HAVE_WINDNS_H */
640 }
641 
642 BOOL WinDnsCachePut_A6 (const char *name, const void *ip6)
643 {
644  if (!(dns_windns & WINDNS_CACHEPUT_A6))
645  return (FALSE);
646  ARGSUSED (name);
647  ARGSUSED (ip6);
648  return (FALSE);
649 }
650 
651 
652 int __stdcall WSAStartup (WORD version_required, WSADATA *wsa_data)
653 {
654  int rc;
655 
656  if (version_required > MAKEWORD(2,2))
657  return (EINVAL); /* we don't have WSAVERNOTSUPPORTED */
658 
659  _watt_do_exit = 0;
660  rc = watt_sock_init (0, 0, 0);
661 
662  wsa_data->wVersion = version_required;
663  wsa_data->wHighVersion = 2;
664  wsa_data->iMaxSockets = MAX_SOCKETS;
665  wsa_data->iMaxUdpDg = MAX_SOCKETS;
666  wsa_data->lpVendorInfo = NULL;
667  wsa_data->szSystemStatus[0] = '\0';
668  strcpy (wsa_data->szDescription, "Watt-32 tcp/ip");
669  return (rc);
670 }
671 
672 int __stdcall WSACleanup (void)
673 {
674  sock_exit();
675  return (0);
676 }
677 
678 int __stdcall __WSAFDIsSet (int s, winsock_fd_set *fd)
679 {
680  UNFINISHED();
681  ARGSUSED (s);
682  ARGSUSED (fd);
683  return (0);
684 }
685 
686 #ifdef NOT_USED
687 static BOOL CALLBACK callback (LPSTR cp)
688 {
689  printf ("\t callback(): cp: \"%s\", valid: %d\n",
690  cp, IsValidCodePage(atoi(cp)));
691  return (TRUE);
692 }
693 
694 static void enum_codepages (void)
695 {
696  puts ("\nEnumerating codepages");
697  EnumSystemCodePages (callback, CP_INSTALLED);
698 
699  if (IsValidCodePage(65001))
700  SetConsoleCP (65001);
701  else puts ("CP=65001 (UTF-8) is not valid");
702 }
703 #endif /* NOT_USED */
704 
705 
706 #if defined(_MSC_VER) && (_MSC_VER >= 1300) && 0
707 __declspec(naked) unsigned __int64 _ftol2 (double x)
708 {
709  _asm {
710  push ebp
711  mov ebp,esp
712  sub esp,0x00000020
713  and esp,0xfffffff0
714  fld st
715  fst dword ptr 0x18[esp]
716  fistp qword ptr 0x10[esp]
717  fild qword ptr 0x10[esp]
718  mov edx,dword ptr 0x18[esp]
719  mov eax,dword ptr 0x10[esp]
720  test eax,eax
721  je integer_QnaN_or_zero
722 arg_is_not_integer_QnaN:
723  fsubp st(1),st
724  test edx,edx
725  jns positive
726  fstp dword ptr [esp]
727  mov ecx,dword ptr [esp]
728  xor ecx,0x80000000
729  add ecx,0x7fffffff
730  adc eax,0x00000000
731  mov edx,dword ptr 0x14[esp]
732  adc edx,0x00000000
733  jmp localexit
734 positive:
735  fstp dword ptr [esp]
736  mov ecx,dword ptr [esp]
737  add ecx,0x7fffffff
738  sbb eax,0x00000000
739  mov edx,dword ptr 0x14[esp]
740  sbb edx,0x00000000
741  jmp localexit
742 integer_QnaN_or_zero:
743  mov edx,dword ptr 0x14[esp]
744  test edx,0x7fffffff
745  jne arg_is_not_integer_QnaN
746  fstp dword ptr 0x18[esp]
747  fstp dword ptr 0x18[esp]
748 localexit:
749  leave
750  ret
751  }
752 }
753 
754 __declspec(naked) unsigned __int64 _aulldvrm (void)
755 {
756  _asm {
757  push esi
758  mov eax,dword ptr 0x14[esp]
759  or eax,eax
760  jne L1
761  mov ecx,dword ptr 0x10[esp]
762  mov eax,dword ptr 0xc[esp]
763  xor edx,edx
764  div ecx
765  mov ebx,eax
766  mov eax,dword ptr 0x8[esp]
767  div ecx
768  mov esi,eax
769  mov eax,ebx
770  mul dword ptr 0x10[esp]
771  mov ecx,eax
772  mov eax,esi
773  mul dword ptr 0x10[esp]
774  add edx,ecx
775  jmp L2
776 L1:
777  mov ecx,eax
778  mov ebx,dword ptr 0x10[esp]
779  mov edx,dword ptr 0xc[esp]
780  mov eax,dword ptr 0x8[esp]
781 L3:
782  shr ecx,0x01
783  rcr ebx,0x01
784  shr edx,0x01
785  rcr eax,0x01
786  or ecx,ecx
787  jne L3
788  div ebx
789  mov esi,eax
790  mul dword ptr 0x14[esp]
791  mov ecx,eax
792  mov eax,dword ptr 0x10[esp]
793  mul esi
794  add edx,ecx
795  jb L4
796  cmp edx,dword ptr 0xc[esp]
797  ja L4
798  jb L5
799  cmp eax,dword ptr 0x8[esp]
800  jbe L5
801 L4:
802  dec esi
803  sub eax,dword ptr 0x10[esp]
804  sbb edx,dword ptr 0x14[esp]
805 L5:
806  xor ebx,ebx
807 L2:
808  sub eax,dword ptr 0x8[esp]
809  sbb edx,dword ptr 0xc[esp]
810  neg edx
811  neg eax
812  sbb edx,0x00000000
813  mov ecx,edx
814  mov edx,ebx
815  mov ebx,ecx
816  mov ecx,eax
817  mov eax,esi
818  pop esi
819  ret 0x0010
820  }
821 }
822 #endif /* _MSC_VER && 0 */
823 
824 /*
825  * From the Open Watcom Project
826  *
827  * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
828  */
829 static int is_real_key (const INPUT_RECORD *k)
830 {
831  if (k->EventType != KEY_EVENT)
832  return (0);
833 
834  if (k->Event.KeyEvent.bKeyDown)
835  {
836  switch (k->Event.KeyEvent.wVirtualKeyCode)
837  {
838  case VK_SHIFT:
839  case VK_CONTROL:
840  case VK_MENU: /* Alt */
841  return(0);
842  }
843  return (1);
844  }
845  return (0);
846 }
847 
848 
849 /*
850  * CygWin doesn't even have <conio.h>. Let alone a simple kbhit()
851  * and getch(). Hence we make them for all Win32 targets here
852  * (but prefixed with '_w32_').
853  */
854 int W32_NAMESPACE(kbhit) (void)
855 {
856  INPUT_RECORD r;
857  DWORD num;
858 
859  if (stdin_hnd == INVALID_HANDLE_VALUE)
860  return (0);
861 
862  while (1)
863  {
864  PeekConsoleInput (stdin_hnd, &r, 1, &num);
865  if (num == 0)
866  break;
867  if (is_real_key(&r))
868  break;
869  ReadConsoleInput (stdin_hnd, &r, 1, &num); /* flush out mouse, window, and key up events */
870  }
871  return (num);
872 }
873 
874 static int do_getch (HANDLE h)
875 {
876  while (1)
877  {
878  INPUT_RECORD ir;
879  DWORD num;
880  int ch;
881 
882  if (!ReadConsoleInput(h, &ir, 1, &num))
883  break;
884  if (!is_real_key(&ir))
885  continue;
886  ch = ir.Event.KeyEvent.uChar.AsciiChar;
887  if ((ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) || ch == 0)
888  ch = 0;
889  return (ch);
890  }
891  return (EOF);
892 }
893 
894 int W32_NAMESPACE(getch) (void)
895 {
896  DWORD mode;
897  int c;
898 
899  if (stdin_hnd == INVALID_HANDLE_VALUE)
900  return (0);
901 
902  GetConsoleMode (stdin_hnd, &mode);
903  if (!tcp_cbreak_off()) /* if not ignoring ^C */
904  SetConsoleMode (stdin_hnd, 0); /* binary; ignores ^C */
905  c = do_getch (stdin_hnd);
906  SetConsoleMode (stdin_hnd, mode);
907  return (c);
908 }
909 
910 char *W32_NAMESPACE(itoa) (int value, char *buf, int radix)
911 {
912  WATT_ASSERT (radix == 8 || radix == 10);
913  sprintf (buf, (radix == 8) ? "%o" : "%d", value);
914  return (buf);
915 }
916 
917 /*
918  * Return FILETIME in seconds as a double.
919  */
920 static double filetime_sec (const FILETIME *filetime)
921 {
922  const LARGE_INTEGER *ft = (const LARGE_INTEGER*) filetime;
923  long double rc = (long double) ft->QuadPart;
924 
925  return (double) (rc/1E7); /* from 100 nano-sec periods to sec */
926 }
927 
928 /*
929  * Print some times (and CPU cycle counts) for a thread.
930  * I.e. the WinPcap receiver thread.
931  */
932 void print_thread_times (HANDLE thread)
933 {
934  FILETIME ctime, etime, ktime, utime;
935 
936  if (!GetThreadTimes(thread, &ctime, &etime, &ktime, &utime))
937  {
938  DWORD err = GetLastError();
939  CONSOLE_MSG (2, (" GetThreadTimes() %s, ", win_strerror(err)));
940  }
941  CONSOLE_MSG (2, (" kernel-time: %.6fs, user-time: %.6fs, life-span: %.6fs",
942  filetime_sec(&ktime), filetime_sec(&utime),
943  filetime_sec(&etime) - filetime_sec(&ctime)));
944 
945  if (p_QueryThreadCycleTime)
946  {
947  ULONG64 cycle_time;
948  if (!(*p_QueryThreadCycleTime) (thread, &cycle_time))
949  CONSOLE_MSG (2, (", cycle-time: <failed>"));
950  else CONSOLE_MSG (2, (", cycle-time: %" U64_FMT "clocks", cycle_time));
951  }
952 
953  if (p_NtQueryInformationThread)
954  {
955  LARGE_INTEGER perf_count;
956  NTSTATUS rc = (*p_NtQueryInformationThread) (thread, ThreadPerformanceCount,
957  &perf_count, sizeof(perf_count),
958  NULL);
959  if (rc != STATUS_SUCCESS)
960  CONSOLE_MSG (2, (", perf-count: <fail %ld>", rc));
961  else CONSOLE_MSG (2, (", perf-count: %" U64_FMT, perf_count.QuadPart));
962  }
963  CONSOLE_MSG (2, ("\n"));
964 }
965 
966 /*
967  * Print some times for a process.
968  */
969 void print_process_times (void)
970 {
971 #if 0
972  HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
973  GetCurrentProcessId());
974 
975  FILETIME ctime, etime, ktime, utime;
976  PERFORMANCE_INFORMATION perf_info;
977  PROCESS_MEMORY_COUNTERS ctrs;
978 
979  if (GetProcessTimes(proc, &ctime, &etime.ft, &ktime, &utime))
980  {
981  /* The units returned by GetProcessTimes are 100 nanoseconds */
982  u_time.lt = (u_time.lt + 5) / 10;
983  s_time.lt = (s_time.lt + 5) / 10;
984 
985  usage->ru_utime.tv_sec = (long)(u_time.lt / 1000000ll);
986  usage->ru_stime.tv_sec = (long)(s_time.lt / 1000000ll);
987  usage->ru_utime.tv_usec = (long)(u_time.lt % 1000000ll);
988  usage->ru_stime.tv_usec = (long)(s_time.lt % 1000000ll);
989 
990  if (GetProcessMemoryInfo(proc, &ctrs, sizeof(ctrs)))
991  {
992  GetPerformanceInfo (&perf_info, sizeof(perf_info));
993  usage->ru_maxrss = (DWORD) (ctrs.WorkingSetSize / perf_info.PageSize);
994  usage->ru_majflt = ctrs.PageFaultCount;
995  }
996  }
997  CloseHandle (proc);
998 #endif
999 }
1000 
1001 static const char *wide_string (const wchar_t *in_str, UINT cp)
1002 {
1003  static char buf [300];
1004 
1005  if (WideCharToMultiByte(cp, 0, in_str, -1,
1006  buf, sizeof(buf), NULL, NULL) == 0)
1007  SNPRINTF (buf, sizeof(buf),
1008  "WideCharToMultiByte() failed: %s", win_strerror(GetLastError()));
1009  return (buf);
1010 }
1011 
1012 static const wchar_t *ascii_string (const char *in_str, UINT cp)
1013 {
1014  static wchar_t buf [300];
1015 
1016  if (MultiByteToWideChar(cp, 0, in_str, -1, buf, DIM(buf)) == 0)
1017  {
1018  CONSOLE_MSG (2, ("MultiByteToWideChar() failed: %s", win_strerror(GetLastError())));
1019  return (L"??");
1020  }
1021  return (buf);
1022 }
1023 
1024 const wchar_t *astring_acp (const char *in_str)
1025 {
1026  return ascii_string (in_str, CP_ACP);
1027 }
1028 
1029 const wchar_t *astring_utf8 (const char *in_str)
1030 {
1031  return ascii_string (in_str, CP_UTF8);
1032 }
1033 
1034 const char *wstring_acp (const wchar_t *in_str)
1035 {
1036  return wide_string (in_str, CP_ACP);
1037 }
1038 
1039 const char *wstring_utf8 (const wchar_t *in_str)
1040 {
1041  return wide_string (in_str, CP_UTF8);
1042 }
1043 #endif /* WIN32 */
1044 
char _watt_assert_buf[256]
Definition: misc.c:62
const char * get_argv0(void)
Return argv[0] as passed to main().
Definition: pcconfig.c:668
WORD _watt_os_ver
Definition: misc.c:61
static void MS_CDECL new_abort_handler(int sig)
Definition: winmisc.c:313
void MS_CDECL sock_exit(void)
Our only atexit() handler.
Definition: sock_ini.c:1039
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
Definition: if.h:83
int W32_CALL watt_sock_init(size_t tcp_Sock_size, size_t udp_Sock_size, size_t time_t_size)
Definition: sock_ini.c:749
Definition: ip.h:67
BOOL _watt_do_exit
exit program when all boot attempts failed
Definition: sock_ini.c:134
Definition: esp.h:48
BOOL GetFileVersion(const char *file_name, char *version_buf, size_t version_buf_len)
Returns the version of a PE image (.sys, .dll or .exe).
Definition: winmisc.c:219
const char * _inet6_ntoa(const void *ip)
Convert an IPv6-address 'ip' into a string.
Definition: netaddr.c:401
char *W32_CALL _inet_ntoa(char *s, DWORD ip)
Convert an IP-address 'ip' into a string.
Definition: netaddr.c:43
char *W32_CALL rip(char *s)
Removes end-of-line termination from a string.
Definition: strings.c:180