1 //////////////////////////////////////////////////////////////////////////////////////////
2 // w32util.c Windows porting functions
3 //////////////////////////////////////////////////////////////////////////////////////////
4 // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under the Q Public License
5 // (http://www.hercules-390.org/herclic.html) as modifications to Hercules.
6 //////////////////////////////////////////////////////////////////////////////////////////
7 //
8 // IMPORTANT PROGRAMMING NOTE!
9 //
10 // Please see the "VERY IMPORTANT SPECIAL NOTE" comments accompanying the
11 // select, fdopen, etc, #undef's in the Windows Socket Handling section!!
12 //
13 //////////////////////////////////////////////////////////////////////////////////////////
14
15
16 #include "hstdinc.h"
17
18 #define _W32UTIL_C_
19 #define _HUTIL_DLL_
20
21 #include "hercules.h"
22
23 #if defined( _MSVC_ )
24
25 ///////////////////////////////////////////////////////////////////////////////
26 // Support for disabling of CRT Invalid Parameter Handler...
27
28 #if defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
29
DummyCRTInvalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)30 static void DummyCRTInvalidParameterHandler
31 (
32 const wchar_t* expression,
33 const wchar_t* function,
34 const wchar_t* file,
35 unsigned int line,
36 uintptr_t pReserved
37 )
38 {
39 // Do nothing to cause CRT to simply ignore the invalid parameter
40 // and to instead just pass back the return code to the caller.
41 }
42
43 static _invalid_parameter_handler old_iph = NULL;
44 static int prev_rm = 0;
45
46 // This function's sole purpose is to bypass Microsoft's default handling of
47 // invalid parameters being passed to CRT functions, which ends up causing
48 // two completely different assertion dialogs to appear for each problem
49
DisableInvalidParameterHandling()50 DLL_EXPORT void DisableInvalidParameterHandling()
51 {
52 if ( old_iph ) return;
53 old_iph = _set_invalid_parameter_handler( DummyCRTInvalidParameterHandler );
54 #if defined(DEBUG) || defined(_DEBUG)
55 prev_rm = _CrtSetReportMode( _CRT_ASSERT, 0 );
56 #endif
57 }
58
EnableInvalidParameterHandling()59 DLL_EXPORT void EnableInvalidParameterHandling()
60 {
61 if ( !old_iph ) return;
62 _set_invalid_parameter_handler( old_iph ); old_iph = NULL;
63 #if defined(DEBUG) || defined(_DEBUG)
64 _CrtSetReportMode( _CRT_ASSERT, prev_rm );
65 #endif
66 }
67
68 #endif // defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
69
70 //////////////////////////////////////////////////////////////////////////////////////////
71
72 struct ERRNOTAB
73 {
74 DWORD dwLastError; // Win32 error from GetLastError()
75 int nErrNo; // corresponding 'errno' value
76 };
77
78 typedef struct ERRNOTAB ERRNOTAB;
79
80 // PROGRAMMING NOTE: we only need to translate values which
81 // are in the same range as existing defined errno values. If
82 // the Win32 GetLastError() value is outside the defined errno
83 // value range, then we just use the raw GetLastError() value.
84
85 // The current 'errno' value range is 0 - 43, so only those
86 // GetLastError() values (defined in winerror.h) which are 43
87 // or less need to be remapped.
88
89 ERRNOTAB w32_errno_tab[] =
90 {
91 { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
92 { ERROR_ACCESS_DENIED, EACCES },
93 { ERROR_INVALID_HANDLE, EBADF },
94 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
95 { ERROR_OUTOFMEMORY, ENOMEM },
96 { ERROR_INVALID_DRIVE, ENOENT },
97 { ERROR_WRITE_PROTECT, EACCES },
98 { ERROR_NOT_READY, EIO },
99 { ERROR_CRC, EIO },
100 { ERROR_WRITE_FAULT, EIO },
101 { ERROR_READ_FAULT, EIO },
102 { ERROR_GEN_FAILURE, EIO },
103 { ERROR_SHARING_VIOLATION, EACCES },
104 };
105
106 #define NUM_ERRNOTAB_ENTRIES (sizeof(w32_errno_tab)/sizeof(w32_errno_tab[0]))
107
108 //////////////////////////////////////////////////////////////////////////////////////////
109 // Translates a Win32 '[WSA]GetLastError()' value into a 'errno' value (if possible
110 // and/or if needed) that can then be used in the below 'w32_strerror' string function...
111
w32_trans_w32error(const DWORD dwLastError)112 DLL_EXPORT int w32_trans_w32error( const DWORD dwLastError )
113 {
114 int i; for ( i=0; i < NUM_ERRNOTAB_ENTRIES; i++ )
115 if ( dwLastError == w32_errno_tab[i].dwLastError )
116 return w32_errno_tab[i].nErrNo;
117 return (int) dwLastError;
118 }
119
120 //////////////////////////////////////////////////////////////////////////////////////////
121 // ("unsafe" version -- use "safer" 'w32_strerror_r' instead if possible)
122
w32_strerror(int errnum)123 DLL_EXPORT char* w32_strerror( int errnum )
124 {
125 static char szMsgBuff[ 256 ]; // (s/b plenty big enough)
126 w32_strerror_r( errnum, szMsgBuff, sizeof(szMsgBuff) );
127 return szMsgBuff;
128 }
129
130 //////////////////////////////////////////////////////////////////////////////////////////
131 // Handles both regular 'errno' values as well as [WSA]GetLastError() values too...
132
w32_strerror_r(int errnum,char * buffer,size_t buffsize)133 DLL_EXPORT int w32_strerror_r( int errnum, char* buffer, size_t buffsize )
134 {
135 // Route all 'errno' values outside the normal CRT (C Runtime) error
136 // message table range to the Win32 'w32_w32errmsg' function instead.
137 // Otherwise simply use the CRT's error message table directly...
138
139 if ( !buffer || !buffsize ) return -1;
140
141 if ( errnum >= 0 && errnum < _sys_nerr )
142 {
143 // Use CRT's error message table directly...
144 strlcpy( buffer, _sys_errlist[ errnum ], buffsize );
145 }
146 else
147 {
148 // 'errno' value is actually a Win32 [WSA]GetLastError value...
149 w32_w32errmsg( errnum, buffer, buffsize );
150 }
151
152 return 0;
153 }
154
155 //////////////////////////////////////////////////////////////////////////////////////////
156 // Return Win32 error message text associated with an error number value
157 // as returned by a call to either GetLastError() or WSAGetLastError()...
158
w32_w32errmsg(int errnum,char * pszBuffer,size_t nBuffSize)159 DLL_EXPORT char* w32_w32errmsg( int errnum, char* pszBuffer, size_t nBuffSize )
160 {
161 DWORD dwBytesReturned = 0;
162 DWORD dwBuffSize = (DWORD)nBuffSize;
163
164 ASSERT( pszBuffer && nBuffSize );
165
166 dwBytesReturned = FormatMessageA
167 (
168 0
169 | FORMAT_MESSAGE_FROM_SYSTEM
170 | FORMAT_MESSAGE_IGNORE_INSERTS
171 ,
172 NULL,
173 errnum,
174 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
175 pszBuffer,
176 dwBuffSize,
177 NULL
178 );
179
180 ASSERT( dwBytesReturned );
181
182 // (remove trailing whitespace)
183 {
184 char* p = pszBuffer + dwBytesReturned - 1;
185 while ( p >= pszBuffer && isspace(*p) ) p--;
186 *++p = 0;
187 }
188
189 return pszBuffer;
190 }
191
192 //////////////////////////////////////////////////////////////////////////////////////////
193 // Large File Support...
194
195 #if (_MSC_VER < 1400)
196
197 //----------------------------------------------------------------------------------------
198
199 #if defined( _POSIX_ )
200 // (promote/demote long to/from __int64)
201 #define FPOS_T_TO_INT64(pos) ((__int64)(pos))
202 #define INT64_TO_FPOS_T(i64,pos) ((pos) = (long)(i64))
203 #if _INTEGRAL_MAX_BITS < 64
204 #pragma message( MSVC_MESSAGE_LINENUM "warning: fseek/ftell use offset arguments of insufficient size" )
205 #endif
206 #else
207 #if !__STDC__ && _INTEGRAL_MAX_BITS >= 64
208 // (already __int64!)
209 #define FPOS_T_TO_INT64(pos) (pos)
210 #define INT64_TO_FPOS_T(i64,pos) ((pos) = (i64))
211 #else
212 // (construct an __int64 from fpos_t structure members and vice-versa)
213 #define FPOS_T_TO_INT64(pos) ((__int64)(((unsigned __int64)(pos).hipart << 32) | \
214 (unsigned __int64)(pos).lopart))
215 #define INT64_TO_FPOS_T(i64,pos) ((pos).hipart = (int)((i64) >> 32), \
216 (pos).lopart = (unsigned int)(i64))
217 #endif
218 #endif
219
220 //----------------------------------------------------------------------------------------
221
w32_ftelli64(FILE * stream)222 DLL_EXPORT __int64 w32_ftelli64 ( FILE* stream )
223 {
224 fpos_t pos; if ( fgetpos( stream, &pos ) != 0 )
225 return -1; else return FPOS_T_TO_INT64( pos );
226 }
227
228 //----------------------------------------------------------------------------------------
229
w32_fseeki64(FILE * stream,__int64 offset,int origin)230 DLL_EXPORT int w32_fseeki64 ( FILE* stream, __int64 offset, int origin )
231 {
232 __int64 offset_from_beg;
233 fpos_t pos;
234
235 if (SEEK_CUR == origin)
236 {
237 if ( (offset_from_beg = w32_ftelli64( stream )) < 0 )
238 return -1;
239 offset_from_beg += offset;
240 }
241 else if (SEEK_END == origin)
242 {
243 struct stat fst;
244 if ( fstat( fileno( stream ), &fst ) != 0 )
245 return -1;
246 offset_from_beg = (__int64)fst.st_size + offset;
247 }
248 else if (SEEK_SET == origin)
249 {
250 offset_from_beg = offset;
251 }
252 else
253 {
254 errno = EINVAL;
255 return -1;
256 }
257
258 INT64_TO_FPOS_T( offset_from_beg, pos );
259 return fsetpos( stream, &pos );
260 }
261
262 //----------------------------------------------------------------------------------------
263
w32_ftrunc64(int fd,__int64 new_size)264 DLL_EXPORT int w32_ftrunc64 ( int fd, __int64 new_size )
265 {
266 HANDLE hFile;
267 int rc = 0, save_errno;
268 __int64 old_pos, old_size;
269
270 if ( new_size < 0 )
271 {
272 errno = EINVAL;
273 return -1;
274 }
275
276 hFile = (HANDLE) _get_osfhandle( fd );
277
278 if ( (HANDLE) -1 == hFile )
279 {
280 errno = EBADF; // (probably not a valid opened file descriptor)
281 return -1;
282 }
283
284 // The value of the seek pointer shall not be modified by a call to ftruncate().
285
286 if ( ( old_pos = _telli64( fd ) ) < 0 )
287 return -1;
288
289 // PROGRAMMING NOTE: from here on, all errors
290 // need to goto error_return to restore the original
291 // seek pointer...
292
293 if ( ( old_size = _lseeki64( fd, 0, SEEK_END ) ) < 0 )
294 {
295 rc = -1;
296 goto error_return;
297 }
298
299 // pad with zeros out to new_size if needed
300
301 rc = 0; // (think positively)
302
303 if ( new_size > old_size )
304 {
305 #define ZEROPAD_BUFFSIZE ( 128 * 1024 )
306 BYTE zeros[ZEROPAD_BUFFSIZE];
307 size_t write_amount = sizeof(zeros);
308 memset( zeros, 0, sizeof(zeros) );
309
310 do
311 {
312 write_amount = min( sizeof(zeros), ( new_size - old_size ) );
313
314 if ( !WriteFile( hFile, zeros, write_amount, NULL, NULL ) )
315 {
316 errno = (int) GetLastError();
317 rc = -1;
318 break;
319 }
320 }
321 while ( ( old_size += write_amount ) < new_size );
322
323 save_errno = errno;
324 ASSERT( old_size == new_size || rc < 0 );
325 errno = save_errno;
326 }
327
328 if ( rc < 0 )
329 goto error_return;
330
331 // set the new file size (eof)
332
333 if ( _lseeki64( fd, new_size, SEEK_SET ) < 0 )
334 {
335 rc = -1;
336 goto error_return;
337 }
338
339 if ( !SetEndOfFile( hFile ) )
340 {
341 errno = (int) GetLastError();
342 rc = -1;
343 goto error_return;
344 }
345
346 rc = 0; // success!
347
348 error_return:
349
350 // restore the original seek pointer and return
351
352 save_errno = errno;
353 _lseeki64( fd, old_pos, SEEK_SET );
354 errno = save_errno;
355
356 return rc;
357 }
358
359 #endif // (_MSC_VER < 1400)
360
361 //////////////////////////////////////////////////////////////////////////////////////////
362
363 #if !defined( HAVE_FORK )
364
fork(void)365 DLL_EXPORT pid_t fork( void )
366 {
367 errno = ENOTSUP;
368 return -1; // *** NOT SUPPORTED ***
369 }
370
371 #endif
372
373 //////////////////////////////////////////////////////////////////////////////////////////
374
375 #if !defined( HAVE_SCHED_YIELD )
376
sched_yield(void)377 DLL_EXPORT int sched_yield ( void )
378 {
379 Sleep(0);
380 return 0;
381 }
382
383 #endif
384
385 //////////////////////////////////////////////////////////////////////////////////////////
386 // Win32's runtime library functions are reentrant as long as you link
387 // with one of the multi-threaded libraries (i.e. LIBCMT, MSVCRT, etc.)
388
389 #if !defined( HAVE_STRTOK_R )
390
strtok_r(char * s,const char * sep,char ** lasts)391 DLL_EXPORT char* strtok_r ( char* s, const char* sep, char** lasts )
392 {
393 UNREFERENCED( lasts );
394 return strtok( s, sep );
395 }
396
397 #endif
398
399 //////////////////////////////////////////////////////////////////////////////////////////
400 // Can't use "HAVE_SLEEP" since Win32's "Sleep" causes HAVE_SLEEP to
401 // be erroneously #defined due to autoconf AC_CHECK_FUNCS case issues...
402
403 //#if !defined( HAVE_SLEEP )
404
sleep(unsigned seconds)405 DLL_EXPORT unsigned sleep ( unsigned seconds )
406 {
407 Sleep( seconds * 1000 );
408 return 0;
409 }
410
411 //#endif
412
413 //////////////////////////////////////////////////////////////////////////////////////////
414 // high resolution sleep
415
416 #if !defined( HAVE_NANOSLEEP ) || !defined( HAVE_USLEEP )
417
w32_nanosleep(const struct timespec * rqtp)418 static int w32_nanosleep ( const struct timespec* rqtp )
419 {
420 /*
421 DESCRIPTION
422
423 The nanosleep() function shall cause the current thread
424 to be suspended from execution until either the time interval
425 specified by the rqtp argument has elapsed or a signal is
426 delivered to the calling thread, and its action is to invoke
427 a signal-catching function or to terminate the process. The
428 suspension time may be longer than requested because the argument
429 value is rounded up to an integer multiple of the sleep resolution
430 or because of the scheduling of other activity by the system.
431 But, except for the case of being interrupted by a signal, the
432 suspension time shall not be less than the time specified by rqtp,
433 as measured by the system clock CLOCK_REALTIME.
434
435 The use of the nanosleep() function has no effect on the action
436 or blockage of any signal.
437
438 RETURN VALUE
439
440 If the nanosleep() function returns because the requested time
441 has elapsed, its return value shall be zero.
442
443 If the nanosleep() function returns because it has been interrupted
444 by a signal, it shall return a value of -1 and set errno to indicate
445 the interruption. If the rmtp argument is non-NULL, the timespec
446 structure referenced by it is updated to contain the amount of time
447 remaining in the interval (the requested time minus the time actually
448 slept). If the rmtp argument is NULL, the remaining time is not returned.
449
450 If nanosleep() fails, it shall return a value of -1 and set errno
451 to indicate the error.
452
453 ERRORS
454
455 The nanosleep() function shall fail if:
456
457 [EINTR] The nanosleep() function was interrupted by a signal.
458
459 [EINVAL] The rqtp argument specified a nanosecond value less than zero
460 or greater than or equal to 1000 million.
461 */
462
463 static BOOL bDidInit = FALSE;
464 static HANDLE hTimer = NULL;
465 LARGE_INTEGER liDueTime;
466
467 // Create the waitable timer if needed...
468
469 if (unlikely( !bDidInit ))
470 {
471 bDidInit = TRUE;
472
473 VERIFY( ( hTimer = CreateWaitableTimer( NULL, TRUE, NULL ) ) != NULL );
474 }
475
476 // Check passed parameters...
477
478 if (unlikely(!rqtp
479 || rqtp->tv_nsec < 0
480 || rqtp->tv_nsec >= 1000000000
481 ))
482 {
483 errno = EINVAL;
484 return -1;
485 }
486
487 // Note: Win32 waitable timers: parameter is #of 100-nanosecond intervals.
488 // Positive values indicate absolute UTC time. Negative values indicate
489 // relative time. The actual timer accuracy depends on the capability
490 // of your hardware.
491
492 liDueTime.QuadPart = -( // (negative means relative)
493 (((__int64)rqtp->tv_sec * 10000000))
494 +
495 (((__int64)rqtp->tv_nsec + 99) / 100)
496 );
497
498 // Set the waitable timer...
499
500 VERIFY( SetWaitableTimer( hTimer, &liDueTime, 0, NULL, NULL, FALSE ) );
501
502 // Wait for the waitable timer to expire...
503
504 VERIFY( WaitForSingleObject( hTimer, INFINITE ) == WAIT_OBJECT_0 );
505
506 return 0;
507 }
508
509 #endif
510
511 //////////////////////////////////////////////////////////////////////////////////////////
512 // nanosleep - high resolution sleep
513
514 #if !defined( HAVE_NANOSLEEP )
515
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)516 DLL_EXPORT int nanosleep ( const struct timespec* rqtp, struct timespec* rmtp )
517 {
518 if (unlikely(rmtp))
519 {
520 rmtp->tv_sec = 0;
521 rmtp->tv_nsec = 0;
522 }
523
524 return w32_nanosleep ( rqtp );
525 }
526
527 #endif
528
529 //////////////////////////////////////////////////////////////////////////////////////////
530 // usleep - suspend execution for an interval
531
532 #if !defined( HAVE_USLEEP )
533
usleep(useconds_t useconds)534 DLL_EXPORT int usleep ( useconds_t useconds )
535 {
536 // "The useconds argument shall be less than one million. If the value of
537 // useconds is 0, then the call has no effect."
538
539 // "Implementations may place limitations on the granularity of timer values.
540 // For each interval timer, if the requested timer value requires a finer
541 // granularity than the implementation supports, the actual timer value shall
542 // be rounded up to the next supported value."
543
544 // "Upon successful completion, usleep() shall return 0; otherwise, it shall
545 // return -1 and set errno to indicate the error."
546
547 // "The usleep() function may fail if:
548 //
549 // [EINVAL] The time interval specified
550 // one million or more microseconds"
551
552 struct timespec rqtp;
553
554 if (unlikely( useconds < 0 || useconds >= 1000000 ))
555 {
556 errno = EINVAL;
557 return -1;
558 }
559
560 rqtp.tv_sec = 0;
561 rqtp.tv_nsec = useconds * 1000;
562
563 return w32_nanosleep ( &rqtp );
564 }
565
566 #endif
567
568 //////////////////////////////////////////////////////////////////////////////////////////
569 // gettimeofday...
570
571 #if !defined( HAVE_GETTIMEOFDAY )
572
573 // Number of 100-nanosecond units from 1 Jan 1601 to 1 Jan 1970
574
575 #define EPOCH_BIAS 116444736000000000ULL
576
577 // Helper function to convert Windows system-time value to microseconds...
578
FileTimeToMicroseconds(const FILETIME * pFT)579 static LARGE_INTEGER FileTimeToMicroseconds( const FILETIME* pFT )
580 {
581 LARGE_INTEGER liWork; // (work area)
582
583 // Copy value to be converted to work area
584
585 liWork.HighPart = pFT->dwHighDateTime;
586 liWork.LowPart = pFT->dwLowDateTime;
587
588 // Convert to 100-nanosecond units since 1 Jan 1970
589
590 liWork.QuadPart -= EPOCH_BIAS;
591
592 // Convert to microseconds since 1 Jan 1970
593
594 liWork.QuadPart /= (LONGLONG) 10;
595
596 return liWork;
597 }
598
gettimeofday(struct timeval * pTV,void * pTZ)599 DLL_EXPORT int gettimeofday ( struct timeval* pTV, void* pTZ )
600 {
601 LARGE_INTEGER liCurrentHPCValue; // (high-performance-counter tick count)
602 static LARGE_INTEGER liStartingHPCValue; // (high-performance-counter tick count)
603 static LARGE_INTEGER liStartingSystemTime; // (time of last resync in microseconds)
604 static struct timeval tvPrevSyncVal = {0,0}; // (time of last resync as timeval)
605 static struct timeval tvPrevRetVal = {0,0}; // (previously returned value)
606 static double dHPCTicksPerMicrosecond; // (just what it says)
607 static BOOL bInSync = FALSE; // (work flag)
608
609 UNREFERENCED(pTZ);
610
611 // One-time (and periodic!) initialization...
612
613 if (unlikely( !bInSync ))
614 {
615 FILETIME ftStartingSystemTime;
616 LARGE_INTEGER liHPCTicksPerSecond;
617
618 // The "GetSystemTimeAsFileTime" function obtains the current system date
619 // and time. The information is in Coordinated Universal Time (UTC) format.
620
621 GetSystemTimeAsFileTime( &ftStartingSystemTime );
622 VERIFY( QueryPerformanceCounter( &liStartingHPCValue ) );
623
624 VERIFY( QueryPerformanceFrequency( &liHPCTicksPerSecond ) );
625 dHPCTicksPerMicrosecond = (double) liHPCTicksPerSecond.QuadPart / 1000000.0;
626
627 liStartingSystemTime = FileTimeToMicroseconds( &ftStartingSystemTime );
628
629 tvPrevSyncVal.tv_sec = 0; // (to force init further below)
630 tvPrevSyncVal.tv_usec = 0; // (to force init further below)
631
632 bInSync = TRUE;
633 }
634
635 // The following check for user error must FOLLOW the above initialization
636 // code block so the above initialization code block ALWAYS gets executed!
637
638 if (unlikely( !pTV ))
639 return EFAULT;
640
641 // Query current high-performance counter value...
642
643 VERIFY( QueryPerformanceCounter( &liCurrentHPCValue ) );
644
645 // Calculate elapsed HPC ticks...
646
647 liCurrentHPCValue.QuadPart -= liStartingHPCValue.QuadPart;
648
649 // Convert to elapsed microseconds...
650
651 liCurrentHPCValue.QuadPart = (LONGLONG)
652 ( (double) liCurrentHPCValue.QuadPart / dHPCTicksPerMicrosecond );
653
654 // Add to starting system time...
655
656 liCurrentHPCValue.QuadPart += liStartingSystemTime.QuadPart;
657
658 // Build results...
659
660 pTV->tv_sec = (long)(liCurrentHPCValue.QuadPart / 1000000);
661 pTV->tv_usec = (long)(liCurrentHPCValue.QuadPart % 1000000);
662
663 // Re-sync to system clock every so often to prevent clock drift
664 // since high-performance timer updated independently from clock.
665
666 #define RESYNC_GTOD_EVERY_SECS 30
667
668 // (initialize time of previous 'sync')
669
670 if (unlikely( !tvPrevSyncVal.tv_sec ))
671 {
672 tvPrevSyncVal.tv_sec = pTV->tv_sec;
673 tvPrevSyncVal.tv_usec = pTV->tv_usec;
674 }
675
676 // (is is time to resync again?)
677
678 if (unlikely( (pTV->tv_sec - tvPrevSyncVal.tv_sec ) > RESYNC_GTOD_EVERY_SECS ))
679 {
680 bInSync = FALSE; // (force resync)
681 return gettimeofday( pTV, NULL );
682 }
683
684 // Ensure that each call returns a unique, ever-increasing value...
685
686 if (unlikely( !tvPrevRetVal.tv_sec ))
687 {
688 tvPrevRetVal.tv_sec = pTV->tv_sec;
689 tvPrevRetVal.tv_usec = pTV->tv_usec;
690 }
691
692 if (unlikely
693 (0
694 || pTV->tv_sec < tvPrevRetVal.tv_sec
695 || (1
696 && pTV->tv_sec == tvPrevRetVal.tv_sec
697 && pTV->tv_usec <= tvPrevRetVal.tv_usec
698 )
699 ))
700 {
701 pTV->tv_sec = tvPrevRetVal.tv_sec;
702 pTV->tv_usec = tvPrevRetVal.tv_usec + 1;
703
704 if (unlikely(pTV->tv_usec >= 1000000))
705 {
706 pTV->tv_sec += pTV->tv_usec / 1000000;
707 pTV->tv_usec = pTV->tv_usec % 1000000;
708 }
709 }
710
711 // Save previously returned value for next time...
712
713 tvPrevRetVal.tv_sec = pTV->tv_sec;
714 tvPrevRetVal.tv_usec = pTV->tv_usec;
715
716 // Done!
717
718 return 0; // (always unless user error)
719 }
720
721 #endif
722
723 //////////////////////////////////////////////////////////////////////////////////////////
724 // scandir...
725
726 #if !defined( HAVE_SCANDIR )
727
728 // (fishfix: fix benign "passing incompatible pointer type" compiler warning..)
729 typedef int (*PFN_QSORT_COMPARE_FUNC)( const void* elem1, const void* elem2 );
730
731 // Found the following on Koders.com ... (http://www.koders.com/) ...
732
733 /*
734 Copyright (c) 2000 Petter Reinholdtsen
735
736 Permission is hereby granted, free of charge, to any person
737 obtaining a copy of this software and associated documentation
738 files (the "Software"), to deal in the Software without
739 restriction, including without limitation the rights to use, copy,
740 modify, merge, publish, distribute, sublicense, and/or sell copies
741 of the Software, and to permit persons to whom the Software is
742 furnished to do so, subject to the following conditions:
743
744 The above copyright notice and this permission notice shall be
745 included in all copies or substantial portions of the Software.
746
747 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
748 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
749 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
750 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
751 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
752 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
753 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
754 SOFTWARE.
755 */
scandir(const char * dir,struct dirent *** namelist,int (* filter)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))756 DLL_EXPORT int scandir
757 (
758 const char *dir,
759 struct dirent ***namelist,
760 int (*filter)(const struct dirent *),
761 int (*compar)(const struct dirent **, const struct dirent **)
762 )
763 {
764 WIN32_FIND_DATA file_data;
765 HANDLE handle;
766 int count, pos;
767 struct dirent **names;
768 char *pattern;
769
770 /* 3 for "*.*", 1 for "\", 1 for zero termination */
771 pattern = (char*)malloc(strlen(dir) + 3 +1 +1);
772 strcpy(pattern, dir);
773 if (pattern[ strlen(pattern) - 1] != '\\')
774 strcat(pattern, "\\");
775 strcat(pattern, "*.*");
776
777 /* 1st pass thru is just to count them */
778 handle = FindFirstFile(pattern, &file_data);
779 if (handle == INVALID_HANDLE_VALUE)
780 {
781 free(pattern);
782 return -1;
783 }
784
785 count = 0;
786 while (1)
787 {
788 count++;
789 if (!FindNextFile(handle, &file_data))
790 break;
791 }
792 FindClose(handle);
793
794 /* Now we know how many, we can alloc & make 2nd pass to copy them */
795 names = (struct dirent**)malloc(sizeof(struct dirent*) * count);
796 memset(names, 0, sizeof(*names));
797 handle = FindFirstFile(pattern, &file_data);
798 if (handle == INVALID_HANDLE_VALUE)
799 {
800 free(pattern);
801 free(names);
802 return -1;
803 }
804
805 /* Now let caller filter them if requested */
806 pos = 0;
807 while (1)
808 {
809 int rtn;
810 struct dirent current;
811
812 strcpy(current.d_name, file_data.cFileName);
813
814 if (!filter || filter(¤t))
815 {
816 struct dirent *copyentry = malloc(sizeof(struct dirent));
817 strcpy(copyentry->d_name, current.d_name);
818 names[pos] = copyentry;
819 pos++;
820 }
821
822 rtn = FindNextFile(handle, &file_data);
823 if (!rtn || rtn==ERROR_NO_MORE_FILES)
824 break;
825 }
826
827 free(pattern);
828 /* Now sort them */
829 if (compar)
830 // (fishfix: fix benign "passing incompatible pointer type" compiler warning..)
831 qsort(names, pos, sizeof(names[0]), (PFN_QSORT_COMPARE_FUNC)compar);
832 *namelist = names;
833 return pos;
834 }
835
836 #endif
837
838 //////////////////////////////////////////////////////////////////////////////////////////
839
840 #if !defined( HAVE_ALPHASORT )
841
alphasort(const struct dirent ** a,const struct dirent ** b)842 DLL_EXPORT int alphasort ( const struct dirent **a, const struct dirent **b )
843 {
844 return strfilenamecmp ( (*a)->d_name, (*b)->d_name );
845 }
846
847 #endif
848
849 //////////////////////////////////////////////////////////////////////////////////////////
850 // "Poor man's" getrusage...
851
852 #if !defined(HAVE_SYS_RESOURCE_H)
853
DoGetRUsage(HANDLE hProcess,struct rusage * r_usage)854 static int DoGetRUsage( HANDLE hProcess, struct rusage* r_usage )
855 {
856 FILETIME ftCreation; // When the process was created(*)
857 FILETIME ftExit; // When the process exited(*)
858
859 // (*) Windows standard FILETIME format: date/time expressed as the
860 // amount of time that has elapsed since midnight January 1, 1601.
861
862 FILETIME ftKernel; // CPU time spent in kernel mode (in #of 100-nanosecond units)
863 FILETIME ftUser; // CPU time spent in user mode (in #of 100-nanosecond units)
864
865 LARGE_INTEGER liWork; // (work area)
866
867 if ( !GetProcessTimes( hProcess, &ftCreation, &ftExit, &ftKernel, &ftUser ) )
868 {
869 ftCreation.dwHighDateTime = ftCreation.dwLowDateTime = 0;
870 ftExit .dwHighDateTime = ftExit .dwLowDateTime = 0;
871 ftKernel .dwHighDateTime = ftKernel .dwLowDateTime = 0;
872 ftUser .dwHighDateTime = ftUser .dwLowDateTime = 0;
873 }
874
875 // Kernel time...
876
877 liWork.HighPart = ftKernel.dwHighDateTime;
878 liWork.LowPart = ftKernel.dwLowDateTime;
879
880 liWork.QuadPart /= 10; // (convert to microseconds)
881
882 r_usage->ru_stime.tv_sec = (long)(liWork.QuadPart / 1000000);
883 r_usage->ru_stime.tv_usec = (long)(liWork.QuadPart % 1000000);
884
885 // User time...
886
887 liWork.HighPart = ftUser.dwHighDateTime;
888 liWork.LowPart = ftUser.dwLowDateTime;
889
890 liWork.QuadPart /= 10; // (convert to microseconds)
891
892 r_usage->ru_utime.tv_sec = (long)(liWork.QuadPart / 1000000);
893 r_usage->ru_utime.tv_usec = (long)(liWork.QuadPart % 1000000);
894
895 return 0;
896 }
897
getrusage(int who,struct rusage * r_usage)898 DLL_EXPORT int getrusage ( int who, struct rusage* r_usage )
899 {
900 if ( !r_usage )
901 {
902 errno = EFAULT;
903 return -1;
904 }
905
906 if ( RUSAGE_SELF == who )
907 return DoGetRUsage( GetCurrentProcess(), r_usage );
908
909 if ( RUSAGE_CHILDREN != who )
910 {
911 errno = EINVAL;
912 return -1;
913 }
914
915 // RUSAGE_CHILDREN ...
916
917 {
918 DWORD dwOurProcessId = GetCurrentProcessId();
919 HANDLE hProcessSnap = NULL;
920 PROCESSENTRY32 pe32;
921 HANDLE hChildProcess;
922 struct rusage child_usage;
923
924 memset( &pe32, 0, sizeof(pe32) );
925
926 // Take a snapshot of all active processes...
927
928 hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
929
930 if ( INVALID_HANDLE_VALUE == hProcessSnap )
931 return DoGetRUsage( INVALID_HANDLE_VALUE, r_usage );
932
933 pe32.dwSize = sizeof( PROCESSENTRY32 );
934
935 // Walk the snapshot...
936
937 if ( !Process32First( hProcessSnap, &pe32 ) )
938 {
939 CloseHandle( hProcessSnap );
940 return DoGetRUsage( INVALID_HANDLE_VALUE, r_usage );
941 }
942
943 r_usage->ru_stime.tv_sec = r_usage->ru_stime.tv_usec = 0;
944 r_usage->ru_utime.tv_sec = r_usage->ru_utime.tv_usec = 0;
945
946 // Locate all children of the current process
947 // and accumulate their process times together...
948
949 do
950 {
951 if ( pe32.th32ParentProcessID != dwOurProcessId )
952 continue;
953
954 hChildProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID );
955 DoGetRUsage( hChildProcess, &child_usage );
956 CloseHandle( hChildProcess );
957
958 VERIFY( timeval_add( &child_usage.ru_stime, &r_usage->ru_stime ) == 0 );
959 VERIFY( timeval_add( &child_usage.ru_utime, &r_usage->ru_utime ) == 0 );
960 }
961 while ( Process32Next( hProcessSnap, &pe32 ) );
962
963 VERIFY( CloseHandle( hProcessSnap ) );
964 }
965
966 return 0;
967 }
968
969 #endif
970
971 //////////////////////////////////////////////////////////////////////////////////////////
972
973 #if !defined( HAVE_GETLOGIN_R )
974
getlogin_r(char * name,size_t namesize)975 DLL_EXPORT int getlogin_r ( char* name, size_t namesize )
976 {
977 DWORD dwSize = (DWORD)namesize;
978
979 if ( !name )
980 return EFAULT;
981
982 if ( namesize < 2 || namesize > ( LOGIN_NAME_MAX + 1 ) )
983 return EINVAL;
984
985 return ( GetUserName( name, &dwSize ) ? 0 : ERANGE );
986 }
987
988 #endif
989
990 //////////////////////////////////////////////////////////////////////////////////////////
991
992 #if !defined( HAVE_GETLOGIN )
993
getlogin(void)994 DLL_EXPORT char* getlogin ( void )
995 {
996 static char login_name [ LOGIN_NAME_MAX + 1 ];
997
998 int rc;
999
1000 if ( ( rc = getlogin_r ( login_name, sizeof(login_name) ) ) == 0 )
1001 return login_name;
1002
1003 errno = rc;
1004 return NULL;
1005 }
1006
1007 #endif
1008
1009 //////////////////////////////////////////////////////////////////////////////////////////
1010
1011 #if !defined( HAVE_REALPATH )
1012
realpath(const char * file_name,char * resolved_name)1013 DLL_EXPORT char* realpath ( const char* file_name, char* resolved_name )
1014 {
1015 char* retval;
1016
1017 if ( !file_name || !resolved_name )
1018 {
1019 errno = EINVAL;
1020 return NULL;
1021 }
1022
1023 // PROGRAMMING NOTE: unfortunately there's no possible way to implement an accurate
1024 // Win32 port of realpath in regard to the errno values returned whenever there's an
1025 // error. The errno values that are set whenever realpath fails are quite precise,
1026 // telling you exactly what went wrong (name too long, invalid directory component,
1027 // etc), whereas _fullpath only returns success/failure with absolutely no indication
1028 // as to WHY it failed. To further complicate matters, there's no real "generic" type
1029 // of errno value we can choose to return to the caller should _fullpath fail either,
1030 // so for this implementation we purposely return EIO (i/o error) if _fullpath fails
1031 // for any reason. That may perhaps be somewhat misleading (since the actual cause of
1032 // the failure was probably not because of an i/o error), but returning any of the
1033 // OTHER possible realpath errno values would be even MORE misleading in my opinion.
1034
1035 if ( !(retval = _fullpath( resolved_name, file_name, PATH_MAX ) ) )
1036 errno = EIO;
1037
1038 return retval;
1039 }
1040
1041 #endif
1042
1043 //////////////////////////////////////////////////////////////////////////////////////////
1044 // Returns outpath as a host filesystem compatible filename path.
1045 // This is a Cygwin-to-MSVC transitional period helper function.
1046 // On non-Windows platforms it simply copies inpath to outpath.
1047 // On Windows it converts inpath of the form "/cygdrive/x/foo.bar"
1048 // to outpath in the form "x:/foo.bar" for Windows compatibility.
1049
hostpath(BYTE * outpath,const BYTE * inpath,size_t buffsize)1050 DLL_EXPORT BYTE *hostpath( BYTE *outpath, const BYTE *inpath, size_t buffsize )
1051 {
1052 // The possibilities:
1053
1054 // a. Linux/Cygwin absolute:
1055 // /dir/foo.bar
1056
1057 // b. Linux/Cygwin relative:
1058 // ../dir/foo.bar
1059 // ./dir/foo.bar
1060 // ../../.././dir/foo.bar
1061 // (etc)
1062
1063 // c. Windows relative:
1064 // ./dir\foo.bar
1065 // ../dir\foo.bar
1066 // ..\dir\foo.bar
1067 // .\dir\foo.bar
1068 // ..\dir/foo.bar
1069 // .\dir/foo.bar
1070 // ../..\../.\dir/foo.bar
1071 // (etc)
1072
1073 // d. Windows absolute
1074 // x:/dir/foo.bar
1075 // x:\dir\foo.bar
1076 // x:/dir\foo.bar
1077 // x:\dir/foo.bar
1078
1079 // For case a we check for special Cygwin format "/cygdrive/x/..."
1080 // and convert it to "normalized" (forward-slash) case d format.
1081 // (Note that the slashes in this case MUST be forward slashes
1082 // or else the special Cygwin path format will not be detected!)
1083
1084 // Case b we treat the same as case c.
1085
1086 // For case c we simply convert all backslashes to forward slashes
1087 // since Windows supports both.
1088
1089 // For case d we do nothing since it is already a Windows path
1090 // (other than normalize all backward slashes to forward slashes
1091 // since Windows supports both)
1092
1093 // NOTE that we do NOT attempt to convert relative paths to absolute
1094 // paths! The caller is responsible for doing that themselves after
1095 // calling this function if so desired.
1096
1097 if (outpath && buffsize)
1098 *outpath = 0;
1099
1100 if (inpath && *inpath && outpath && buffsize > 1)
1101 {
1102 size_t inlen = strlen(inpath);
1103
1104 if (1
1105 && inlen >= 11
1106 && strncasecmp(inpath,"/cygdrive/",10) == 0
1107 && isalpha(inpath[10])
1108 )
1109 {
1110 *outpath++ = inpath[10];
1111 buffsize--;
1112 if (buffsize > 1)
1113 {
1114 *outpath++ = ':';
1115 buffsize--;
1116 }
1117 inpath += 11;
1118 }
1119
1120 while (*inpath && --buffsize)
1121 {
1122 BYTE c = *inpath++;
1123 if (c == '\\') c = '/';
1124 *outpath++ = c;
1125 }
1126 *outpath = 0;
1127 }
1128 return outpath;
1129 }
1130
1131 //////////////////////////////////////////////////////////////////////////////////////////
1132 // Poor man's "fcntl( fd, F_GETFL )"...
1133 // (only returns access-mode flags and not any others)
1134
get_file_accmode_flags(int fd)1135 DLL_EXPORT int get_file_accmode_flags( int fd )
1136 {
1137 // PROGRAMMING NOTE: we unfortunately CANNOT use Microsoft's "_fstat" here
1138 // since it seems to always return the actual file's ATTRIBUTE permissions
1139 // and not the ACCESS MODE permissions specified when the file was opened!
1140
1141 HANDLE hFile;
1142 BOOL bCanRead;
1143 BOOL bCanWrite;
1144 DWORD dwNumBytesToReadOrWrite;
1145 DWORD dwNumBytesReadOrWritten;
1146 char read_write_buffer;
1147
1148 // TECHNIQUE: check whether or not we can "read" and/or "write" to the file
1149 // and return appropriate access-mode flags accordingly. Note that we do not
1150 // actually read nor write from/to the file per se, since we specify ZERO BYTES
1151 // for our "number of bytes to read/write" argument. This is valid under Win32
1152 // and does not modify the file position and so is safe to do. All it does is
1153 // return the appropriate success/failure return code (e.g. ERROR_ACCESS_DENIED)
1154 // depending on whether the file was opened with the proper access permissions.
1155
1156 hFile = (HANDLE) _get_osfhandle( fd );
1157
1158 if ( (HANDLE) -1 == hFile )
1159 {
1160 errno = EBADF; // (probably not a valid opened file descriptor)
1161 return -1;
1162 }
1163
1164 dwNumBytesToReadOrWrite = 0; // ZERO!!! (we don't wish to modify the file!)
1165
1166 VERIFY( ( bCanRead = ReadFile ( hFile, &read_write_buffer, dwNumBytesToReadOrWrite, &dwNumBytesReadOrWritten, NULL ) )
1167 || ERROR_ACCESS_DENIED == GetLastError() );
1168
1169 VERIFY( ( bCanWrite = WriteFile ( hFile, &read_write_buffer, dwNumBytesToReadOrWrite, &dwNumBytesReadOrWritten, NULL ) )
1170 || ERROR_ACCESS_DENIED == GetLastError() );
1171
1172 // For reference, 'fcntl.h' defines the flags as follows:
1173 //
1174 // #define _O_RDONLY 0
1175 // #define _O_WRONLY 1
1176 // #define _O_RDWR 2
1177
1178 if ( bCanRead && bCanWrite ) return _O_RDWR;
1179 if ( bCanRead && !bCanWrite ) return _O_RDONLY;
1180 if ( !bCanRead && bCanWrite ) return _O_WRONLY;
1181
1182 ASSERT( FALSE ); // (HUH?! Can neither read NOR write to the file?!)
1183 errno = EBADF; // (maybe they closed it before we could test it??)
1184 return -1; // (oh well)
1185 }
1186
1187 //////////////////////////////////////////////////////////////////////////////////////////
1188 // Retrieve directory where process was loaded from...
1189 // (returns >0 == success, 0 == failure)
1190
get_process_directory(char * dirbuf,size_t bufsiz)1191 DLL_EXPORT int get_process_directory( char* dirbuf, size_t bufsiz )
1192 {
1193 char process_exec_dirbuf[MAX_PATH];
1194 char* p;
1195 DWORD dwDirBytes =
1196 GetModuleFileName(GetModuleHandle(NULL),process_exec_dirbuf,MAX_PATH);
1197 if (!dwDirBytes || dwDirBytes >= MAX_PATH)
1198 return 0;
1199 p = strrchr(process_exec_dirbuf,'\\'); if (p) *(p+1) = 0;
1200 strlcpy(dirbuf,process_exec_dirbuf,bufsiz);
1201 return strlen(dirbuf) ? 1 : 0;
1202 }
1203
1204 //////////////////////////////////////////////////////////////////////////////////////////
1205 // Expand environment variables... (e.g. %SystemRoot%, etc); 0==success
1206
expand_environ_vars(const char * inbuff,char * outbuff,DWORD outbufsiz)1207 DLL_EXPORT int expand_environ_vars( const char* inbuff, char* outbuff, DWORD outbufsiz )
1208 {
1209 // If the function succeeds, the return value is the number of TCHARs
1210 // stored in the destination buffer, including the terminating null character.
1211 // If the destination buffer is too small to hold the expanded string, the
1212 // return value is the required buffer size, in TCHARs. If the function fails,
1213 // the return value is zero.
1214
1215 DWORD dwOutLen = ExpandEnvironmentStrings( inbuff, outbuff, outbufsiz );
1216 return ( ( dwOutLen && dwOutLen < outbufsiz ) ? 0 : -1 );
1217 }
1218
1219 //////////////////////////////////////////////////////////////////////////////////////////
1220 // Initialize Hercules HOSTINFO structure
1221
w32_init_hostinfo(HOST_INFO * pHostInfo)1222 DLL_EXPORT void w32_init_hostinfo( HOST_INFO* pHostInfo )
1223 {
1224 CRITICAL_SECTION cs;
1225 OSVERSIONINFO vi;
1226 SYSTEM_INFO si;
1227 char* psz;
1228 DWORD dw;
1229
1230 dw = sizeof(pHostInfo->nodename)-1;
1231 GetComputerName( pHostInfo->nodename, &dw );
1232 pHostInfo->nodename[sizeof(pHostInfo->nodename)-1] = 0;
1233
1234 vi.dwOSVersionInfoSize = sizeof(vi);
1235
1236 VERIFY( GetVersionEx( &vi ) );
1237
1238 switch ( vi.dwPlatformId )
1239 {
1240 case VER_PLATFORM_WIN32_WINDOWS: psz = "9X"; break;
1241 case VER_PLATFORM_WIN32_NT: psz = "NT"; break;
1242 default: psz = "??"; break;
1243 }
1244
1245 #if defined(__MINGW32_VERSION)
1246 #define HWIN32_SYSNAME "MINGW32"
1247 #else
1248 #define HWIN32_SYSNAME "Windows"
1249 #endif
1250
1251 _snprintf(
1252 pHostInfo->sysname, sizeof(
1253 pHostInfo->sysname)-1, HWIN32_SYSNAME "_%s", psz );
1254 pHostInfo->sysname[ sizeof(
1255 pHostInfo->sysname)-1] = 0;
1256
1257 _snprintf(
1258 pHostInfo->release, sizeof(
1259 pHostInfo->release)-1, "%d", vi.dwMajorVersion );
1260 pHostInfo->release[ sizeof(
1261 pHostInfo->release)-1] = 0;
1262
1263 _snprintf(
1264 pHostInfo->version, sizeof(
1265 pHostInfo->version)-1, "%d", vi.dwMinorVersion );
1266 pHostInfo->version[ sizeof(
1267 pHostInfo->version)-1] = 0;
1268
1269 GetSystemInfo( &si );
1270
1271 switch ( si.wProcessorArchitecture )
1272 {
1273 case PROCESSOR_ARCHITECTURE_INTEL:
1274 {
1275 int n;
1276
1277 if ( si.wProcessorLevel < 3 ) n = 3;
1278 else if ( si.wProcessorLevel > 9 ) n = 6;
1279 else n = si.wProcessorLevel;
1280
1281 _snprintf(
1282 pHostInfo->machine, sizeof(
1283 pHostInfo->machine)-1, "i%d86", n );
1284 pHostInfo->machine[ sizeof(
1285 pHostInfo->machine)-1] = 0;
1286 }
1287 break;
1288
1289 // The following are missing from MinGW's supplied version of <winnt.h>
1290
1291 #define PROCESSOR_ARCHITECTURE_MSIL 8
1292 #define PROCESSOR_ARCHITECTURE_AMD64 9
1293 #define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
1294
1295 case PROCESSOR_ARCHITECTURE_IA64: strlcpy( pHostInfo->machine, "IA64" , sizeof(pHostInfo->machine) ); break;
1296 case PROCESSOR_ARCHITECTURE_AMD64: strlcpy( pHostInfo->machine, "AMD64" , sizeof(pHostInfo->machine) ); break;
1297 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: strlcpy( pHostInfo->machine, "IA32_ON_WIN64" , sizeof(pHostInfo->machine) ); break;
1298 case PROCESSOR_ARCHITECTURE_ALPHA: strlcpy( pHostInfo->machine, "ALPHA" , sizeof(pHostInfo->machine) ); break;
1299 case PROCESSOR_ARCHITECTURE_MIPS: strlcpy( pHostInfo->machine, "MIPS" , sizeof(pHostInfo->machine) ); break;
1300 default: strlcpy( pHostInfo->machine, "???" , sizeof(pHostInfo->machine) ); break;
1301 }
1302
1303 pHostInfo->num_procs = si.dwNumberOfProcessors;
1304
1305 InitializeCriticalSection( &cs );
1306
1307 if ( !TryEnterCriticalSection( &cs ) )
1308 pHostInfo->trycritsec_avail = 0;
1309 else
1310 {
1311 pHostInfo->trycritsec_avail = 1;
1312 LeaveCriticalSection( &cs );
1313 }
1314
1315 DeleteCriticalSection( &cs );
1316 }
1317
1318 //////////////////////////////////////////////////////////////////////////////////////////
1319 // The function that creates us is responsible for initializing the below values
1320 // (as well as de-initialzing them too!)
1321
1322 static DWORD dwThreadId = 0; // (Win32 thread-id of below thread)
1323 static HANDLE hThread = NULL; // (Win32 handle of below thread)
1324 static HANDLE hGotStdIn = NULL; // (signaled to get next char)
1325 static HANDLE hStdInAvailable = NULL; // (signaled when char avail)
1326 static HANDLE hStdIn = NULL; // (Win32 stdin handle)
1327 static char chStdIn = 0; // (the next char read from stdin)
1328
1329 // Win32 worker thread that reads from stdin. It needs to be a thread because the
1330 // "ReadFile" on stdin 'hangs' (blocks) until there's actually some data to read
1331 // or the handle is closed, whichever comes first. Note that we only read one char
1332 // at a time. This may perhaps be slightly inefficient but it makes for a simpler
1333 // implementation and besides, we don't really expect huge gobs of data coming in.
1334
ReadStdInW32Thread(LPVOID lpParameter)1335 static DWORD WINAPI ReadStdInW32Thread( LPVOID lpParameter )
1336 {
1337 DWORD dwBytesRead = 0;
1338
1339 UNREFERENCED( lpParameter );
1340
1341 SET_THREAD_NAME ("ReadStdInW32Thread");
1342
1343 for (;;)
1344 {
1345 WaitForSingleObject( hGotStdIn, INFINITE );
1346
1347 if ( !ReadFile( hStdIn, &chStdIn, 1, &dwBytesRead, NULL ) )
1348 {
1349 char szErrMsg[256];
1350 DWORD dwLastError = GetLastError();
1351
1352 if ( ERROR_BROKEN_PIPE == dwLastError || sysblk.shutdown )
1353 break; // (shutting down; time to exit)
1354
1355 w32_w32errmsg( dwLastError, szErrMsg, sizeof(szErrMsg) );
1356
1357 logmsg
1358 (
1359 _("HHCDG008W ReadFile(hStdIn) failed! dwLastError=%d (0x%08.8X): %s\n")
1360
1361 ,dwLastError
1362 ,dwLastError
1363 ,szErrMsg
1364 );
1365
1366 continue;
1367 }
1368
1369 ASSERT( 1 == dwBytesRead );
1370
1371 ResetEvent( hGotStdIn );
1372 SetEvent( hStdInAvailable );
1373 }
1374
1375 return 0;
1376 }
1377
1378 //////////////////////////////////////////////////////////////////////////////////////////
1379 // Function to read the next character from stdin. Similar to 'getch' but allows
1380 // one to specify a maximum timeout value and thus doesn't block forever. Returns
1381 // 0 or 1: 0 == timeout (zero characters read), 1 == success (one character read),
1382 // or -1 == error (pCharBuff NULL). The worker thread is created on the 1st call.
1383
1384 DLL_EXPORT
w32_get_stdin_char(char * pCharBuff,int wait_millisecs)1385 int w32_get_stdin_char( char* pCharBuff, int wait_millisecs )
1386 {
1387 if ( !pCharBuff )
1388 {
1389 errno = EINVAL;
1390 return -1;
1391 }
1392
1393 *pCharBuff = 0;
1394
1395 if ( !dwThreadId )
1396 {
1397 hStdIn = GetStdHandle( STD_INPUT_HANDLE );
1398 hStdInAvailable = CreateEvent(NULL,TRUE,FALSE,NULL);
1399 hGotStdIn = CreateEvent(NULL,TRUE,TRUE,NULL); // (initially signaled)
1400
1401 hThread = (HANDLE) _beginthreadex
1402 (
1403 NULL, // pointer to security attributes
1404 64*1024, // initial thread stack size in bytes
1405 ReadStdInW32Thread, // pointer to thread function
1406 NULL, // argument for new thread
1407 0, // creation flags
1408 &dwThreadId // pointer to receive thread ID
1409 );
1410
1411 ASSERT(1
1412 && hStdIn && INVALID_HANDLE_VALUE != hStdIn
1413 && hStdInAvailable && INVALID_HANDLE_VALUE != hStdInAvailable
1414 && hGotStdIn && INVALID_HANDLE_VALUE != hGotStdIn
1415 && hThread && INVALID_HANDLE_VALUE != hThread
1416 );
1417 }
1418
1419 if ( WAIT_TIMEOUT == WaitForSingleObject( hStdInAvailable, wait_millisecs ) )
1420 return 0;
1421
1422 *pCharBuff = chStdIn; // (save the next char right away)
1423 ResetEvent( hStdInAvailable ); // (reset OUR flag for next time)
1424 SetEvent( hGotStdIn ); // (allow thread to read next char)
1425 return 1;
1426 }
1427
1428 /****************************************************************************************\
1429 * *
1430 * (BEGIN) S O C K E T H A N D L I N G F U N C T I O N S (BEGIN) *
1431 * *
1432 \****************************************************************************************/
1433
1434 // ***** VERY IMPORTANT SPECIAL NOTE! *****
1435
1436 // Because "hmacros.h" #defines 'xxxx' to 'w32_xxxx' (to route the call to us),
1437 // we now need to #undef it here to allow us to call the actual 'xxxx' function
1438 // if we need to. All xxxx calls from here on will call the true Windows version.
1439 // To call the w32_xxxx function instead, simply call it directly yourself.
1440
1441 #undef socket // (so we can call the actual Windows version if we need to)
1442 #undef select // (so we can call the actual Windows version if we need to)
1443 #undef fdopen // (so we can call the actual Windows version if we need to)
1444 #undef fwrite // (so we can call the actual Windows version if we need to)
1445 #undef fprintf // (so we can call the actual Windows version if we need to)
1446 #undef fclose // (so we can call the actual Windows version if we need to)
1447
1448 //////////////////////////////////////////////////////////////////////////////////////////
1449 /*
1450 INITIALIZE / DE-INITIALIZE SOCKETS PACKAGE
1451
1452 The WSAStartup function must be the first Windows Sockets
1453 function called by an application or DLL. It allows an application
1454 or DLL to specify the version of Windows Sockets required
1455 and retrieve details of the specific Windows Sockets implementation.
1456 The application or DLL can only issue further Windows Sockets
1457 functions after successfully calling WSAStartup.
1458
1459 Once an application or DLL has made a successful WSAStartup call,
1460 it can proceed to make other Windows Sockets calls as needed.
1461 When it has finished using the services of the WS2_32.DLL, the
1462 application or DLL must call WSACleanup to allow the WS2_32.DLL
1463 to free any resources for the application.
1464
1465 *** IMPORTANT ***
1466
1467 An application must call one WSACleanup call for every successful
1468 WSAStartup call to allow third-party DLLs to make use of a WS2_32.DLL
1469 on behalf of an application. This means, for example, that if an
1470 application calls WSAStartup three times, it must call WSACleanup
1471 three times. The first two calls to WSACleanup do nothing except
1472 decrement an internal counter; the final WSACleanup call for the task
1473 does all necessary resource deallocation for the task.
1474
1475 */
socket_init(void)1476 DLL_EXPORT int socket_init ( void )
1477 {
1478 /*
1479 In order to support future Windows Sockets implementations
1480 and applications that can have functionality differences
1481 from the current version of Windows Sockets, a negotiation
1482 takes place in WSAStartup.
1483
1484 The caller of WSAStartup and the WS2_32.DLL indicate to each
1485 other the highest version that they can support, and each
1486 confirms that the other's highest version is acceptable.
1487
1488 Upon entry to WSAStartup, the WS2_32.DLL examines the version
1489 requested by the application. If this version is equal to or
1490 higher than the lowest version supported by the DLL, the call
1491 succeeds and the DLL returns in wHighVersion the highest
1492 version it supports and in wVersion the minimum of its high
1493 version and wVersionRequested.
1494
1495 The WS2_32.DLL then assumes that the application will use
1496 wVersion If the wVersion parameter of the WSADATA structure
1497 is unacceptable to the caller, it should call WSACleanup and
1498 either search for another WS2_32.DLL or fail to initialize.
1499 */
1500
1501 WSADATA sSocketPackageInfo;
1502 WORD wVersionRequested = MAKEWORD(1,1);
1503
1504 return
1505 (
1506 WSAStartup( wVersionRequested, &sSocketPackageInfo ) == 0 ?
1507 0 : -1
1508 );
1509 }
1510
1511 //////////////////////////////////////////////////////////////////////////////////////////
1512 // De-initialize Windows Sockets package...
1513
socket_deinit(void)1514 DLL_EXPORT int socket_deinit ( void )
1515 {
1516 // PROGRAMMING NOTE: regardless of the comments in the socket_init function above
1517 // regarding the need to always call WSACleanup for every WSAStartup call, it's not
1518 // really necessary in our particular case because we're not designed to continue
1519 // running after shutting down socket handling (which is really what the WSACleanup
1520 // function is designed for). That is to say, the WSACleanup function is designed
1521 // so a program can inform the operating system that it's finished using the socket
1522 // DLL (thus allowing it to free up all of the resources currently being used by
1523 // the process and allow the DLL to be unmapped from the process'es address space)
1524 // but not exit (i.e. continue running). In our case however, our entire process
1525 // is exiting (i.e. we're NOT going to continue running), and when a process exits,
1526 // all loaded DLLs are automatically notified by the operating system to allow them
1527 // to automatically free all resources for the process in question. Thus since we
1528 // are exiting we don't really need to call WSACleanup since whatever "cleanup" it
1529 // would do is going to get done *anyway* by virtue of our going away. Besides that,
1530 // WSACleanup appears to "hang" when it's called while socket resources are still
1531 // being used (which is true in our case since we're not designed (yet!) to cleanly
1532 // shutdown all of our socket-using threads before exiting). THUS (sorry to ramble)
1533 // we in fact probably SHOULDN'T be calling WSACleanup here (and besides, bypassing
1534 // it seems to resolve our hangs at shutdown whenever there's still a thread running
1535 // that doing sockets shit).
1536
1537 #if 0 // (see above)
1538 return
1539 (
1540 WSACleanup() == 0 ?
1541 0 : -1
1542 );
1543 #else
1544 return 0; // (not needed? see PROGRAMING NOTE above!)
1545 #endif
1546 }
1547
1548 //////////////////////////////////////////////////////////////////////////////////////////
1549 // Retrieve unique host id
1550
gethostid(void)1551 DLL_EXPORT long gethostid( void )
1552 {
1553 char szHostName[ WSADESCRIPTION_LEN ];
1554 struct hostent* pHostent = NULL;
1555 return (gethostname( szHostName, sizeof(szHostName) ) == 0
1556 && (pHostent = gethostbyname( szHostName )) != NULL) ?
1557 (long)(*(pHostent->h_addr)) : 0;
1558 }
1559
1560 //////////////////////////////////////////////////////////////////////////////////////////
1561
w32_socket(int af,int type,int protocol)1562 DLL_EXPORT int w32_socket( int af, int type, int protocol )
1563 {
1564 ///////////////////////////////////////////////////////////////////////////////
1565 //
1566 // PROGRAMMING NOTE
1567 //
1568 // We need to request that all sockets we create [via the 'socket()' API]
1569 // be created WITHOUT the "OVERLAPPED" attribute so that our 'fgets()', etc,
1570 // calls (which end up calling the "ReadFile()", etc, Win32 API) work as
1571 // expected.
1572 //
1573 // Note that the "overlapped" attribute for a socket is completely different
1574 // from its non-blocking vs. blocking mode. All sockets are created, by default,
1575 // as blocking mode sockets, but WITH the "overlapped" attribute set. Thus all
1576 // sockets are actually asynchonous by default. (The winsock DLL(s) handle the
1577 // blocking mode separately programmatically internally even though the socket
1578 // is actually an asynchronous Win32 "file").
1579 //
1580 // Thus we need to specifically request that our [blocking mode] sockets be
1581 // created WITHOUT the Win32 "OVERLAPPED" attribute (so that when we call the
1582 // C runtime read/write/etc functions, the C runtime's ReadFile/WriteFile calls
1583 // work (which they don't (they fail with error 87 ERROR_INVALID_PARAMETER)
1584 // when called on a Win32 "file" handle created with the OVERLAPPED attribute
1585 // but without an OVERLAPPED structure pased in the ReadFile/WriteFile call
1586 // (which the C runtime functions don't use)). You follow?).
1587 //
1588 // See KB (Knowledge Base) article 181611 for more information:
1589 //
1590 // "Socket overlapped I/O versus blocking/non-blocking mode"
1591 // (http://support.microsoft.com/?kbid=181611)
1592 //
1593 // ---------------------------------------------------------------------
1594 // "However, you can call the setsockopt API with SO_OPENTYPE option
1595 // on any socket handle -- including an INVALID_SOCKET -- to change
1596 // the overlapped attributes for all successive socket calls in the
1597 // same thread. The default SO_OPENTYPE option value is 0, which sets
1598 // the overlapped attribute. All non-zero option values make the socket
1599 // synchronous and make it so that you cannot use a completion function."
1600 // ---------------------------------------------------------------------
1601 //
1602 // The documentation for the "SOL_SOCKET" SO_OPENTYPE socket option contains
1603 // the folowing advice/warning however:
1604 //
1605 //
1606 // "Once set, subsequent sockets created will be non-overlapped.
1607 // This option should not be used; use WSASocket and leave the
1608 // WSA_FLAG_OVERLAPPED turned off."
1609 //
1610 //
1611 // So we'll use WSASocket instead as suggested.
1612 //
1613 ///////////////////////////////////////////////////////////////////////////////
1614
1615 // The last parameter is where one would normally specify the WSA_FLAG_OVERLAPPED
1616 // option, but we're specifying '0' because we want our sockets to be synchronous
1617 // and not asynchronous so the C runtime functions can successfully perform ReadFile
1618 // and WriteFile on them...
1619
1620 SOCKET sock = WSASocket( af, type, protocol, NULL, 0, 0 );
1621
1622 if ( INVALID_SOCKET == sock )
1623 {
1624 errno = WSAGetLastError();
1625 sock = (SOCKET) -1;
1626 }
1627
1628 return ( (int) sock );
1629 }
1630
1631 //////////////////////////////////////////////////////////////////////////////////////////
1632 // Determine whether a file descriptor is a socket or not...
1633 // (returns 1==true if it's a socket, 0==false otherwise)
1634
socket_is_socket(int sfd)1635 DLL_EXPORT int socket_is_socket( int sfd )
1636 {
1637 u_long dummy;
1638 return WSAHtonl( (SOCKET) sfd, 666, &dummy ) == 0 ? 1 : 0;
1639 }
1640
1641 //////////////////////////////////////////////////////////////////////////////////////////
1642 // Set the SO_KEEPALIVE option and timeout values for a
1643 // socket connection to detect when client disconnects */
1644
socket_keepalive(int sfd,int idle_time,int probe_interval,int probe_count)1645 DLL_EXPORT void socket_keepalive( int sfd, int idle_time, int probe_interval, int probe_count )
1646 {
1647 DWORD dwBytesReturned; // (not used)
1648
1649 struct tcp_keepalive ka;
1650
1651 ka.onoff = TRUE;
1652 ka.keepalivetime = idle_time * 1000;
1653 ka.keepaliveinterval = probe_interval * 1000;
1654 UNREFERENCED(probe_count);
1655
1656 // It either works or it doesn't <shrug>
1657
1658 // PROGRAMMING NOTE: the 'dwBytesReturned' value must apparently always be
1659 // specified in order for this call to work at all. If you don't specify it,
1660 // even though the call succeeds (does not return an error), the automatic
1661 // keep-alive polling does not occur!
1662
1663 if (0 != WSAIoctl
1664 (
1665 (SOCKET)sfd, // [in] Descriptor identifying a socket
1666 SIO_KEEPALIVE_VALS, // [in] Control code of operation to perform
1667 &ka, // [in] Pointer to the input buffer
1668 sizeof(ka), // [in] Size of the input buffer, in bytes
1669 NULL, // [out] Pointer to the output buffer
1670 0, // [in] Size of the output buffer, in bytes
1671 &dwBytesReturned, // [out] Pointer to actual number of bytes of output
1672 NULL, // [in] Pointer to a WSAOVERLAPPED structure
1673 // (ignored for nonoverlapped sockets)
1674 NULL // [in] Pointer to the completion routine called
1675 // when the operation has been completed
1676 // (ignored for nonoverlapped sockets)
1677 ))
1678 {
1679 DWORD dwLastError = WSAGetLastError();
1680 TRACE("*** WSAIoctl(SIO_KEEPALIVE_VALS) failed; rc %d: %s\n",
1681 dwLastError, w32_strerror(dwLastError) );
1682 ASSERT(1); // (in case we're debugging)
1683 }
1684 }
1685
1686 //////////////////////////////////////////////////////////////////////////////////////////
1687 // The inet_aton() function converts the specified string,
1688 // in the Internet standard dot notation, to a network address,
1689 // and stores the address in the structure provided.
1690 //
1691 // The inet_aton() function returns 1 if the address is successfully converted,
1692 // or 0 if the conversion failed.
1693
1694 #if !defined( HAVE_INET_ATON )
1695
inet_aton(const char * cp,struct in_addr * addr)1696 DLL_EXPORT int inet_aton( const char* cp, struct in_addr* addr )
1697 {
1698 // Return success as long as both args are not NULL *and*
1699 // the result is not INADDR_NONE (0xFFFFFFFF), -OR- if it
1700 // is [INADDR_NONE], [we return success] if that is the
1701 // actual expected value of the conversion...
1702
1703 return
1704 (
1705 (1
1706 && cp // (must not be NULL)
1707 && addr // (must not be NULL)
1708 && (0
1709 || INADDR_NONE != ( addr->s_addr = inet_addr( cp ) )
1710 || strcmp( cp, "255.255.255.255" ) == 0
1711 )
1712 )
1713 ? 1 : 0 // 1 == success, 0 == failure
1714 );
1715 }
1716
1717 #endif // !defined( HAVE_INET_ATON )
1718
1719 //////////////////////////////////////////////////////////////////////////////////////////
1720 // All internal calls to Windows's 'FD_ISSET' or 'FD_SET' macros MUST use the below
1721 // macros instead and NOT the #defined 'FD_ISSET' or 'FD_SET' macros! The #defined
1722 // 'FD_ISSET' and 'FD_SET' macros are coded (in hmacros.h) to route the calls to the
1723 // internal 'w32_FD_SET' and 'w32_FD_ISSET' functions further below!
1724
1725 #define ORIGINAL_FD_ISSET __WSAFDIsSet
1726
1727 #define ORIGINAL_FD_SET( fd, pSet ) \
1728 do \
1729 { \
1730 unsigned int i; \
1731 for (i=0; i < ((fd_set*)(pSet))->fd_count; i++) \
1732 if (((fd_set*)(pSet))->fd_array[i] == (fd)) \
1733 break; \
1734 if (i == ((fd_set*)(pSet))->fd_count \
1735 && ((fd_set*)(pSet))->fd_count < FD_SETSIZE) \
1736 { \
1737 ((fd_set*)(pSet))->fd_array[i] = (fd); \
1738 ((fd_set*)(pSet))->fd_count++; \
1739 } \
1740 } \
1741 while (0)
1742
1743 //////////////////////////////////////////////////////////////////////////////////////////
1744 // FD_SET: ( FD_SET(fd,pSet) )
1745 //
1746 // Will need to override and route to "w32_FD_SET"
1747 //
1748 // Do '_get_osfhandle'.
1749 //
1750 // If '_get_osfhandle' error, then it's either already a HANDLE (SOCKET probably),
1751 // or else a bona fide invalid file descriptor or invalid SOCKET handle, so do a
1752 // normal FD_SET.
1753 //
1754 // Otherwise ('_get_osfhandle' success), then it WAS a file descriptor
1755 // but we now have it's HANDLE, so do the FD_SET on the returned HANDLE.
1756 //
1757 // Thus we ensure all entries added to set are HANDLES
1758 // (or SOCKETS which are considered to be HANDLES too)
1759
w32_FD_SET(int fd,fd_set * pSet)1760 DLL_EXPORT void w32_FD_SET( int fd, fd_set* pSet )
1761 {
1762 SOCKET hSocket;
1763
1764 if (0
1765 || socket_is_socket( fd )
1766 || (SOCKET) -1 == ( hSocket = (SOCKET) _get_osfhandle( fd ) )
1767 )
1768 hSocket = (SOCKET) fd;
1769
1770 ORIGINAL_FD_SET( hSocket, pSet ); // (add HANDLE/SOCKET to specified set)
1771 }
1772
1773 //////////////////////////////////////////////////////////////////////////////////////////
1774 // FD_ISSET: ( FD_ISSET(fd,pSet) )
1775 //
1776 // Will need to override and route to "w32_FD_ISSET".
1777 //
1778 // (Note: all entries in sets should already be HANDLES
1779 // due to previously mentioned FD_SET override)
1780 //
1781 // If socket, do normal FD_ISSET.
1782 // Otherwise do our IsEventSet().
1783
w32_FD_ISSET(int fd,fd_set * pSet)1784 DLL_EXPORT int w32_FD_ISSET( int fd, fd_set* pSet )
1785 {
1786 int i;
1787 HANDLE hFile;
1788
1789 if ( socket_is_socket( fd ) ) // (is it already a SOCKET?)
1790 return ORIGINAL_FD_ISSET( (SOCKET)fd, pSet ); // (yes, do normal FD_ISSET)
1791
1792 hFile = (HANDLE) _get_osfhandle( fd );
1793
1794 for ( i=0; i < (int)pSet->fd_count; i++ )
1795 if ( pSet->fd_array[i] == (SOCKET) hFile ) // (is this the file?)
1796 return IsEventSet( hFile ); // (yes, return whether ready (signaled) or not)
1797
1798 return 0; // (file not a member of the specified set)
1799 }
1800 //////////////////////////////////////////////////////////////////////////////////////////
1801 // Win32 "socketpair()" and "pipe()" functionality...
1802
1803 #if !defined( HAVE_SOCKETPAIR )
1804
socketpair(int domain,int type,int protocol,int socket_vector[2])1805 DLL_EXPORT int socketpair( int domain, int type, int protocol, int socket_vector[2] )
1806 {
1807 // PROGRAMMING NOTE: we do NOT support type AF_UNIX socketpairs on Win32.
1808 // we *ONLY* support AF_INET, IPPROTO_IP, SOCK_STREAM.
1809
1810 SOCKET temp_listen_socket;
1811 struct sockaddr_in localhost_addr;
1812 int len = sizeof(localhost_addr);
1813
1814 /* FIXME ISW ? In some situations, it seems the sockaddr_in structure */
1815 /* returned by getsockname() isn't appropriate for use */
1816 /* by connect(). We therefore use another sockaddr_in for the */
1817 /* sole purpose of fetching the automatic port number issued */
1818 /* during the bind() operation. */
1819 /* NOTE : This is a workaround. The actual root cause for this */
1820 /* problem is presently unknown because it is hard to reproduce*/
1821
1822 struct sockaddr_in tempaddr;
1823 int talen = sizeof(tempaddr);
1824
1825 // Technique: create a pair of sockets bound to each other by first creating a
1826 // temporary listening socket bound to the localhost loopback address (127.0.0.1)
1827 // and then having the other socket connect to it...
1828
1829 // "Upon successful completion, 0 shall be returned; otherwise,
1830 // -1 shall be returned and errno set to indicate the error."
1831
1832 if ( AF_INET != domain ) { errno = WSAEAFNOSUPPORT; return -1; }
1833 if ( SOCK_STREAM != type ) { errno = WSAEPROTONOSUPPORT; return -1; }
1834 if ( IPPROTO_IP != protocol ) { errno = WSAEPROTOTYPE; return -1; }
1835
1836 socket_vector[0] = socket_vector[1] = INVALID_SOCKET;
1837
1838 if ( INVALID_SOCKET == (temp_listen_socket = socket( AF_INET, SOCK_STREAM, 0 )) )
1839 {
1840 errno = (int)WSAGetLastError();
1841 return -1;
1842 }
1843
1844 memset( &localhost_addr, 0, len );
1845 memset( &tempaddr, 0, talen );
1846
1847 localhost_addr.sin_family = AF_INET;
1848 localhost_addr.sin_port = htons( 0 );
1849 localhost_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
1850
1851 if (0
1852 || SOCKET_ERROR == bind( temp_listen_socket, (SOCKADDR*) &localhost_addr, len )
1853 || SOCKET_ERROR == listen( temp_listen_socket, 1 )
1854 || SOCKET_ERROR == getsockname( temp_listen_socket, (SOCKADDR*) &tempaddr, &talen )
1855 || INVALID_SOCKET == (SOCKET)( socket_vector[1] = socket( AF_INET, SOCK_STREAM, 0 ) )
1856 )
1857 {
1858 int nLastError = (int)WSAGetLastError();
1859 closesocket( temp_listen_socket );
1860 errno = nLastError;
1861 return -1;
1862 }
1863
1864 /* Get the temporary port number assigned automatically */
1865 /* by bind(127.0.0.1/0) */
1866
1867 localhost_addr.sin_port = tempaddr.sin_port;
1868
1869 if (0
1870 || SOCKET_ERROR == connect( socket_vector[1], (SOCKADDR*) &localhost_addr, len )
1871 || INVALID_SOCKET == (SOCKET)( socket_vector[0] = accept( temp_listen_socket, (SOCKADDR*) &localhost_addr, &len ) )
1872 )
1873 {
1874 int nLastError = (int)WSAGetLastError();
1875 closesocket( socket_vector[1] );
1876 socket_vector[1] = INVALID_SOCKET;
1877 closesocket( temp_listen_socket );
1878 errno = nLastError;
1879 return -1;
1880 }
1881
1882 closesocket( temp_listen_socket );
1883 return 0;
1884 }
1885
1886 #endif // !defined( HAVE_SOCKETPAIR )
1887
1888 //////////////////////////////////////////////////////////////////////////////////////////
1889 // Set socket to blocking or non-blocking mode...
1890
socket_set_blocking_mode(int sfd,int blocking_mode)1891 DLL_EXPORT int socket_set_blocking_mode( int sfd, int blocking_mode )
1892 {
1893 u_long non_blocking_option = !blocking_mode;
1894
1895 if ( SOCKET_ERROR != ioctlsocket( sfd, FIONBIO, &non_blocking_option) )
1896 return 0;
1897
1898 switch (WSAGetLastError())
1899 {
1900 case WSAENETDOWN: errno = ENETDOWN; break;
1901 case WSAENOTSOCK: errno = ENOTSOCK; break;
1902 case WSAEFAULT: errno = EFAULT; break;
1903 default: errno = ENOSYS; break;
1904 }
1905
1906 return -1;
1907 }
1908
1909 //////////////////////////////////////////////////////////////////////////////////////////
1910 // select:
1911 //
1912 // Will need to override and route to "w32_select"
1913 //
1914 // w32_select:
1915 //
1916 // Check if all entries (in all sets) are sockets or not
1917 //
1918 // (Note: all entries in sets should already be HANDLES
1919 // due to previously mentioned FD_SET override)
1920 //
1921 // If all sockets, then do normal 'select'.
1922 //
1923 // If all non-sockets, then do 'WaitForMultipleObjects' instead.
1924 //
1925 // if mixed, then EBADF (one or more bad file descriptors)
1926
1927 static void SelectSet // (helper function)
1928 (
1929 fd_set* pSet,
1930 BOOL* pbSocketFound,
1931 BOOL* pbNonSocketFound,
1932 DWORD* pdwHandles,
1933 HANDLE* parHandles
1934 );
1935
w32_select(int nfds,fd_set * pReadSet,fd_set * pWriteSet,fd_set * pExceptSet,const struct timeval * pTimeVal,const char * pszSourceFile,int nLineNumber)1936 DLL_EXPORT int w32_select
1937 (
1938 int nfds,
1939 fd_set* pReadSet,
1940 fd_set* pWriteSet,
1941 fd_set* pExceptSet,
1942 const struct timeval* pTimeVal,
1943 const char* pszSourceFile,
1944 int nLineNumber
1945 )
1946 {
1947 HANDLE arHandles[ 2 * FD_SETSIZE ]; // (max read + write set size)
1948 DWORD dwHandles = 0;
1949
1950 BOOL bSocketFound = FALSE;
1951 BOOL bNonSocketFound = FALSE;
1952
1953 BOOL bExceptSetSocketFound = FALSE;
1954 BOOL bExceptSetNonSocketFound = FALSE;
1955
1956 DWORD dwWaitMilliSeconds = 0;
1957 DWORD dwWaitRetCode = 0;
1958
1959 UNREFERENCED( nfds );
1960
1961 // Quick check for 'timer.c' call wherein all passed fd_set pointers are NULL...
1962
1963 if ( !pReadSet && !pWriteSet && !pExceptSet )
1964 {
1965 ASSERT( pTimeVal ); // (why else would we be called?!)
1966
1967 if ( !pTimeVal )
1968 {
1969 logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): NULL args\n",
1970 pszSourceFile, nLineNumber );
1971 errno = EINVAL;
1972 return -1;
1973 }
1974
1975 // Sleep for the specified time period...
1976
1977 if ( !pTimeVal->tv_sec && !pTimeVal->tv_usec )
1978 sched_yield();
1979 else
1980 {
1981 if ( pTimeVal->tv_sec )
1982 sleep( pTimeVal->tv_sec );
1983
1984 if ( pTimeVal->tv_usec )
1985 usleep( pTimeVal->tv_usec );
1986 }
1987
1988 return 0;
1989 }
1990
1991 // Check for mixed sets and build HANDLE array...
1992 // (Note: we don't support except sets for non-sockets)
1993
1994 SelectSet( pReadSet, &bSocketFound, &bNonSocketFound, &dwHandles, arHandles );
1995 SelectSet( pWriteSet, &bSocketFound, &bNonSocketFound, &dwHandles, arHandles );
1996 SelectSet( pExceptSet, &bExceptSetSocketFound, &bExceptSetNonSocketFound, NULL, NULL );
1997
1998 if (0
1999 || ( bSocketFound && ( bNonSocketFound || bExceptSetNonSocketFound ) )
2000 || ( bNonSocketFound && ( bSocketFound || bExceptSetSocketFound ) )
2001 )
2002 {
2003 logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): mixed set(s)\n",
2004 pszSourceFile, nLineNumber );
2005 errno = EBADF;
2006 return -1;
2007 }
2008
2009 if ( bExceptSetNonSocketFound )
2010 {
2011 logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): non-socket except set\n",
2012 pszSourceFile, nLineNumber );
2013 errno = EBADF;
2014 return -1;
2015 }
2016
2017 // If all SOCKETs, do a normal 'select'...
2018
2019 if ( bSocketFound )
2020 return select( nfds, pReadSet, pWriteSet, pExceptSet, pTimeVal );
2021
2022 // Otherwise they're all HANDLEs, so do a WaitForMultipleObjects...
2023
2024 if ( !pTimeVal )
2025 dwWaitMilliSeconds = INFINITE;
2026 else
2027 {
2028 dwWaitMilliSeconds = ( pTimeVal->tv_sec * 1000 );
2029 dwWaitMilliSeconds += ( ( pTimeVal->tv_usec + 500 ) / 1000 );
2030 }
2031
2032 if ( !dwHandles )
2033 {
2034 // Just sleep for the specified interval...
2035 Sleep( dwWaitMilliSeconds );
2036 return 0; // (timeout)
2037 }
2038
2039 dwWaitRetCode = WaitForMultipleObjects( dwHandles, arHandles, FALSE, dwWaitMilliSeconds );
2040
2041 if ( WAIT_TIMEOUT == dwWaitRetCode )
2042 return 0;
2043
2044 // NOTE: we don't support returning the actual total number of handles
2045 // that are ready; instead, we return 1 as long as ANY handle is ready...
2046
2047 if ( dwWaitRetCode >= WAIT_OBJECT_0 && dwWaitRetCode < ( WAIT_OBJECT_0 + dwHandles ) )
2048 return 1;
2049
2050 // Something went wrong...
2051
2052 ASSERT( FALSE ); // (in case this is a debug build)
2053 errno = ENOSYS; // (system call failure)
2054 return -1;
2055 }
2056
2057 //////////////////////////////////////////////////////////////////////////////////////////
2058 // internal helper function to pre-process a 'select' set...
2059
SelectSet(fd_set * pSet,BOOL * pbSocketFound,BOOL * pbNonSocketFound,DWORD * pdwHandles,HANDLE * parHandles)2060 static void SelectSet
2061 (
2062 fd_set* pSet,
2063 BOOL* pbSocketFound,
2064 BOOL* pbNonSocketFound,
2065 DWORD* pdwHandles,
2066 HANDLE* parHandles
2067 )
2068 {
2069 unsigned int i;
2070
2071 if ( !pSet ) return;
2072
2073 for (i=0; i < pSet->fd_count && i < FD_SETSIZE; i++)
2074 {
2075 if ( socket_is_socket( pSet->fd_array[i] ) )
2076 {
2077 *pbSocketFound = TRUE;
2078 continue;
2079 }
2080
2081 *pbNonSocketFound = TRUE;
2082
2083 // If parHandles is NULL, then we're
2084 // only interested in the BOOLean flags...
2085
2086 if ( !parHandles ) continue;
2087 ASSERT( *pdwHandles < ( 2 * FD_SETSIZE ) );
2088 *( parHandles + *pdwHandles ) = (HANDLE) pSet->fd_array[i];
2089 *pdwHandles++;
2090 }
2091 }
2092
2093 //////////////////////////////////////////////////////////////////////////////////////////
2094
2095 struct MODE_TRANS
2096 {
2097 const char* old_mode;
2098 const char* new_mode;
2099 int new_flags;
2100 };
2101
2102 typedef struct MODE_TRANS MODE_TRANS;
2103
w32_fdopen(int their_fd,const char * their_mode)2104 DLL_EXPORT FILE* w32_fdopen( int their_fd, const char* their_mode )
2105 {
2106 int new_fd, new_flags = 0;
2107 const char* new_mode = NULL;
2108 MODE_TRANS* pModeTransTab;
2109 MODE_TRANS mode_trans_tab[] =
2110 {
2111 { "r", "rbc", _O_RDONLY | _O_BINARY },
2112 { "r+", "r+bc", _O_RDWR | _O_BINARY },
2113 { "r+b", "r+bc", _O_RDWR | _O_BINARY },
2114 { "rb+", "r+bc", _O_RDWR | _O_BINARY },
2115
2116 { "w", "wbc", _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY },
2117 { "w+", "w+bc", _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY },
2118 { "w+b", "w+bc", _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY },
2119 { "wb+", "w+bc", _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY },
2120
2121 { "a", "abc", _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY },
2122 { "a+", "a+bc", _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY },
2123 { "a+b", "a+bc", _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY },
2124 { "ab+", "a+bc", _O_RDWR | _O_CREAT | _O_APPEND | _O_BINARY },
2125
2126 { NULL, NULL, 0 }
2127 };
2128
2129 ASSERT( their_mode );
2130
2131 // (we're only interested in socket calls)
2132
2133 if ( !socket_is_socket( their_fd ) )
2134 return _fdopen( their_fd, their_mode );
2135
2136 // The passed "file descriptor" is actually a SOCKET handle...
2137
2138 // Translate their original mode to our new mode
2139 // and determine what flags we should use in our
2140 // call to _open_osfhandle()...
2141
2142 if ( their_mode )
2143 for (pModeTransTab = mode_trans_tab; pModeTransTab->old_mode; pModeTransTab++)
2144 if ( strcmp( their_mode, pModeTransTab->old_mode ) == 0 )
2145 {
2146 new_mode = pModeTransTab->new_mode;
2147 new_flags = pModeTransTab->new_flags;
2148 break;
2149 }
2150
2151 if ( !new_mode )
2152 {
2153 errno = EINVAL;
2154 return NULL;
2155 }
2156
2157 // Allocate a CRT file descriptor integer for this SOCKET...
2158
2159 if ( ( new_fd = _open_osfhandle( their_fd, new_flags ) ) < 0 )
2160 return NULL; // (errno already set)
2161
2162 // Now we should be able to do the actual fdopen...
2163
2164 return _fdopen( new_fd, new_mode );
2165 }
2166
2167 //////////////////////////////////////////////////////////////////////////////////////////
2168 // fwrite
2169
w32_fwrite(const void * buff,size_t size,size_t count,FILE * stream)2170 DLL_EXPORT size_t w32_fwrite ( const void* buff, size_t size, size_t count, FILE* stream )
2171 {
2172 int rc;
2173 SOCKET sock;
2174
2175 ASSERT( buff && (size * count) && stream );
2176
2177 {
2178 int sd = fileno( stream );
2179 if ( !socket_is_socket( sd ) )
2180 return fwrite( buff, size, count, stream );
2181 sock = (SOCKET) _get_osfhandle( sd );
2182 }
2183
2184 if ( ( rc = send( sock, buff, (int)(size * count), 0 ) ) == SOCKET_ERROR )
2185 {
2186 errno = WSAGetLastError();
2187 return -1;
2188 }
2189 return ( rc / size );
2190 }
2191
2192 //////////////////////////////////////////////////////////////////////////////////////////
2193 // fprintf
2194
w32_fprintf(FILE * stream,const char * format,...)2195 DLL_EXPORT int w32_fprintf( FILE* stream, const char* format, ... )
2196 {
2197 char* buff = NULL;
2198 int bytes = 0, rc;
2199 va_list vl;
2200 SOCKET sock;
2201
2202 ASSERT( stream && format );
2203
2204 va_start( vl, format );
2205
2206 {
2207 int sd = fileno( stream );
2208 if ( !socket_is_socket( sd ) )
2209 return vfprintf( stream, format, vl );
2210 sock = (SOCKET) _get_osfhandle( sd );
2211 }
2212
2213 do
2214 {
2215 free( buff );
2216
2217 if ( !( buff = malloc( bytes += 1000 ) ) )
2218 {
2219 errno = ENOMEM;
2220 return -1;
2221 }
2222 }
2223 while ( ( rc = vsnprintf( buff, bytes, format, vl ) ) < 0 );
2224
2225 rc = send( sock, buff, bytes = rc, 0 );
2226
2227 free( buff );
2228
2229 if ( SOCKET_ERROR == rc )
2230 {
2231 errno = WSAGetLastError();
2232 return -1;
2233 }
2234 return rc;
2235 }
2236
2237 //////////////////////////////////////////////////////////////////////////////////////////
2238 // fclose
2239
w32_fclose(FILE * stream)2240 DLL_EXPORT int w32_fclose ( FILE* stream )
2241 {
2242 int sd, rc, err;
2243 SOCKET sock;
2244
2245 ASSERT( stream );
2246
2247 sd = fileno( stream );
2248
2249 if ( !socket_is_socket( sd ) )
2250 return fclose( stream );
2251
2252 // (SOCKETs get special handling)
2253
2254 sock = (SOCKET) _get_osfhandle( sd );
2255
2256 // Flush the data, close the socket, then deallocate
2257 // the crt's file descriptor for it by calling fclose.
2258
2259 // Note that the fclose will fail since the closesocket
2260 // has already closed the o/s handle, but we don't care;
2261 // all we care about is the crt deallocating its file
2262 // descriptor for it...
2263
2264 fflush( stream ); // (flush buffers)
2265 shutdown( sock, SD_BOTH); // (try to be graceful)
2266 rc = closesocket( sock ); // (close socket)
2267 err = WSAGetLastError(); // (save retcode)
2268 fclose( stream ); // (ignore likely error)
2269
2270 if ( SOCKET_ERROR == rc ) // (closesocket error?)
2271 {
2272 errno = err; // (yes, return error)
2273 return EOF; // (failed)
2274 }
2275 return 0; // (success)
2276 }
2277
2278 /****************************************************************************************\
2279 (END) (Socket Handling Functions) (END)
2280 \****************************************************************************************/
2281
2282 // Create a child process with redirected standard file HANDLEs...
2283 //
2284 // For more information, see KB article 190351 "HOWTO: Spawn Console Processes
2285 // with Redirected Standard Handles" http://support.microsoft.com/?kbid=190351
2286
2287 #define PIPEBUFSIZE (1024) // SHOULD be big enough!!
2288 #define HOLDBUFSIZE (PIPEBUFSIZE*2) // twice pipe buffer size
2289 #define PIPE_THREAD_STACKSIZE (64*1024) // 64K should be plenty!!
2290
2291 #define MSG_TRUNCATED_MSG "...(truncated)\n"
2292
2293 char* buffer_overflow_msg = NULL; // used to trim received message
2294 size_t buffer_overflow_msg_len = 0; // length of above truncation msg
2295
2296 //////////////////////////////////////////////////////////////////////////////////////////
2297 // Fork control...
2298
2299 typedef struct _PIPED_PROCESS_CTL
2300 {
2301 char* pszBuffer; // ptr to current logmsgs buffer
2302 size_t nAllocSize; // allocated size of logmsgs buffer
2303 size_t nStrLen; // amount used - 1 (because of NULL)
2304 CRITICAL_SECTION csLock; // lock for accessing above buffer
2305 }
2306 PIPED_PROCESS_CTL;
2307
2308 typedef struct _PIPED_THREAD_CTL
2309 {
2310 HANDLE hStdXXX; // stdout or stderr handle
2311 PIPED_PROCESS_CTL* pPipedProcessCtl; // ptr to process control
2312 }
2313 PIPED_THREAD_CTL;
2314
2315 //////////////////////////////////////////////////////////////////////////////////////////
2316 // "Poor man's" fork...
2317
2318 UINT WINAPI w32_read_piped_process_stdxxx_output_thread ( void* pThreadParm ); // (fwd ref)
2319
w32_poor_mans_fork(char * pszCommandLine,int * pnWriteToChildStdinFD)2320 DLL_EXPORT pid_t w32_poor_mans_fork ( char* pszCommandLine, int* pnWriteToChildStdinFD )
2321 {
2322 HANDLE hChildReadFromStdin; // child's stdin pipe HANDLE (inherited from us)
2323 HANDLE hChildWriteToStdout; // child's stdout pipe HANDLE (inherited from us)
2324 HANDLE hChildWriteToStderr; // child's stderr pipe HANDLE (inherited from us)
2325
2326 HANDLE hOurWriteToStdin; // our HANDLE to write-end of child's stdin pipe
2327 HANDLE hOurReadFromStdout; // our HANDLE to read-end of child's stdout pipe
2328 HANDLE hOurReadFromStderr; // our HANDLE to read-end of child's stderr pipe
2329
2330 HANDLE hOurProcess; // (temporary for creating pipes)
2331 HANDLE hPipeReadHandle; // (temporary for creating pipes)
2332 HANDLE hPipeWriteHandle; // (temporary for creating pipes)
2333
2334 HANDLE hWorkerThread; // (worker thread to monitor child's pipe)
2335 DWORD dwThreadId; // (worker thread to monitor child's pipe)
2336
2337 STARTUPINFO siStartInfo; // (info passed to CreateProcess)
2338 PROCESS_INFORMATION piProcInfo; // (info returned by CreateProcess)
2339 SECURITY_ATTRIBUTES saAttr; // (suckurity? we dunt need no stinkin suckurity!)
2340
2341 char* pszNewCommandLine; // (because we build pvt copy for CreateProcess)
2342 BOOL bSuccess; // (work)
2343 int rc; // (work)
2344 size_t len; // (work)
2345
2346 PIPED_PROCESS_CTL* pPipedProcessCtl = NULL;
2347 PIPED_THREAD_CTL* pPipedStdOutThreadCtl = NULL;
2348 PIPED_THREAD_CTL* pPipedStdErrThreadCtl = NULL;
2349
2350 //////////////////////////////////////////////////
2351 // Initialize fields...
2352
2353 buffer_overflow_msg = MSG_TRUNCATED_MSG;
2354 buffer_overflow_msg_len = strlen( buffer_overflow_msg );
2355 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2356 saAttr.lpSecurityDescriptor = NULL; // (we dunt need no stinkin suckurity!)
2357 saAttr.bInheritHandle = TRUE; // (allows our inheritable HANDLEs
2358 // to be inherited by child)
2359 hOurProcess = GetCurrentProcess(); // (for creating pipes)
2360
2361 //////////////////////////////////////////////////
2362 // Only create a stdin pipe if caller will be providing the child's stdin data...
2363
2364 if (!pnWriteToChildStdinFD) // (will caller be providing child's stdin?)
2365 {
2366 // PROGRAMMING NOTE: KB article 190351 "HOWTO: Spawn Console Processes with
2367 // Redirected Standard Handles" http://support.microsoft.com/?kbid=190351
2368 // is WRONG! (or at the very least quite misleading!)
2369
2370 // It states that for those stdio handles you do NOT wish to redirect, you
2371 // should use "GetStdHandle(STD_xxx_HANDLE)", but that ONLY works when you
2372 // have a console to begin with! (which Hercules would NOT have when started
2373 // via HercGUI for example (since it specifies "DETACHED_PROCESS" (i.e. no
2374 // console) whenever it starts it via its own CreateProcess call).
2375
2376 // If you wish to only redirect *some* (but NOT *all*) stdio handles in your
2377 // CreateProcess call, the ONLY way to properly do so (regardless of whether
2378 // you have a console or not) is by specifying NULL. Specifying NULL for your
2379 // stdio handle tells CreateProcess to use the default value for that HANDLE.
2380
2381 hChildReadFromStdin = NULL; // (no stdin redirection; use default)
2382 }
2383 else
2384 {
2385 // Create Stdin pipe for sending data to child...
2386
2387 VERIFY(CreatePipe(&hChildReadFromStdin, &hPipeWriteHandle, &saAttr, PIPEBUFSIZE));
2388
2389 // Create non-inheritable duplcate of pipe handle for our own private use...
2390
2391 VERIFY(DuplicateHandle
2392 (
2393 hOurProcess, hPipeWriteHandle, // (handle to be duplicated)
2394 hOurProcess, &hOurWriteToStdin, // (non-inheritable duplicate)
2395 0,
2396 FALSE, // (prevents child from inheriting it)
2397 DUPLICATE_SAME_ACCESS
2398 ));
2399 VERIFY(CloseHandle(hPipeWriteHandle)); // (MUST close so child won't hang!)
2400 }
2401
2402 //////////////////////////////////////////////////
2403 // Pipe child's Stdout output back to us...
2404
2405 VERIFY(CreatePipe(&hPipeReadHandle, &hChildWriteToStdout, &saAttr, PIPEBUFSIZE));
2406
2407 // Create non-inheritable duplcate of pipe handle for our own private use...
2408
2409 VERIFY(DuplicateHandle
2410 (
2411 hOurProcess, hPipeReadHandle, // (handle to be duplicated)
2412 hOurProcess, &hOurReadFromStdout, // (non-inheritable duplicate)
2413 0,
2414 FALSE, // (prevents child from inheriting it)
2415 DUPLICATE_SAME_ACCESS
2416 ));
2417 VERIFY(CloseHandle(hPipeReadHandle)); // (MUST close so child won't hang!)
2418
2419 //////////////////////////////////////////////////
2420 // Pipe child's Stderr output back to us...
2421
2422 VERIFY(CreatePipe(&hPipeReadHandle, &hChildWriteToStderr, &saAttr, PIPEBUFSIZE));
2423
2424 // Create non-inheritable duplcate of pipe handle for our own private use...
2425
2426 VERIFY(DuplicateHandle
2427 (
2428 hOurProcess, hPipeReadHandle, // (handle to be duplicated)
2429 hOurProcess, &hOurReadFromStderr, // (non-inheritable duplicate)
2430 0,
2431 FALSE, // (prevents child from inheriting it)
2432 DUPLICATE_SAME_ACCESS
2433 ));
2434 VERIFY(CloseHandle(hPipeReadHandle)); // (MUST close so child won't hang!)
2435
2436 //////////////////////////////////////////////////
2437 // Prepare for creation of child process...
2438
2439 ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
2440 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO ));
2441
2442 siStartInfo.cb = sizeof(STARTUPINFO); // (size of structure)
2443 siStartInfo.dwFlags = STARTF_USESTDHANDLES; // (use redirected std HANDLEs)
2444 siStartInfo.hStdInput = hChildReadFromStdin; // (use redirected std HANDLEs)
2445 siStartInfo.hStdOutput = hChildWriteToStdout; // (use redirected std HANDLEs)
2446 siStartInfo.hStdError = hChildWriteToStderr; // (use redirected std HANDLEs)
2447
2448 // Build the command-line for the system to create the child process with...
2449
2450 len = strlen(pszCommandLine) + 1;
2451 pszNewCommandLine = malloc( len );
2452 strlcpy( pszNewCommandLine, pszCommandLine, len );
2453
2454 //////////////////////////////////////////////////
2455 // Now actually create the child process...
2456 //////////////////////////////////////////////////
2457
2458 bSuccess = CreateProcess
2459 (
2460 NULL, // name of executable module = from command-line
2461 pszNewCommandLine, // command line with arguments
2462
2463 NULL, // process security attributes = use defaults
2464 NULL, // primary thread security attributes = use defaults
2465
2466 TRUE, // HANDLE inheritance flag = allow
2467 // (required when STARTF_USESTDHANDLES flag is used)
2468
2469 0, // NOTE! >>>---> // UNDOCUMENTED SECRET! MUST BE ZERO! Can't be "CREATE_NO_WINDOW"
2470 // nor "DETACHED_PROCESS", etc, or else it sometimes doesn't work
2471 // or else a console window appears! ("ipconfig" being one such
2472 // example). THIS IS NOT DOCUMENTED *ANYWHERE* IN ANY MICROSOFT
2473 // DOCUMENTATION THAT I COULD FIND! I only stumbled across it by
2474 // sheer good fortune in a news group post after some intensive
2475 // Googling and have experimentally verified it works as desired.
2476
2477 NULL, // environment block ptr = make a copy from parent's
2478 NULL, // initial working directory = same as parent's
2479
2480 &siStartInfo, // input STARTUPINFO pointer
2481 &piProcInfo // output PROCESS_INFORMATION
2482 );
2483
2484 rc = GetLastError(); // (save return code)
2485
2486 // Close the HANDLEs we don't need...
2487
2488 if (pnWriteToChildStdinFD)
2489 VERIFY(CloseHandle(hChildReadFromStdin)); // (MUST close so child won't hang!)
2490 VERIFY(CloseHandle(hChildWriteToStdout)); // (MUST close so child won't hang!)
2491 VERIFY(CloseHandle(hChildWriteToStderr)); // (MUST close so child won't hang!)
2492
2493 CloseHandle(piProcInfo.hThread); // (we don't need this one)
2494
2495 free(pszNewCommandLine); // (not needed anymore)
2496
2497 // Check results...
2498
2499 if (!bSuccess)
2500 {
2501 TRACE("*** CreateProcess() failed! rc = %d : %s\n",
2502 rc,w32_strerror(rc));
2503
2504 if (pnWriteToChildStdinFD)
2505 VERIFY(CloseHandle(hOurWriteToStdin));
2506 VERIFY(CloseHandle(hOurReadFromStdout));
2507 VERIFY(CloseHandle(hOurReadFromStderr));
2508
2509 errno = rc;
2510 return -1;
2511 }
2512
2513 // Allocate/intialize control blocks for piped process/thread control...
2514
2515 // If we were passed a pnWriteToChildStdinFD pointer, then the caller
2516 // is in charge of the process and will handle message capturing/logging
2517 // (such as is done with the print-to-pipe facility).
2518
2519 // Otherwise (pnWriteToChildStdinFD is NULL) the caller wishes for us
2520 // to capture the piped process's o/p, so we pass a PIPED_PROCESS_CTL
2521 // structure to the stdout/stderr monitoring threads. This structure
2522 // contains a pointer to a buffer where they can accumulate messages.
2523
2524 // Then once the process exits WE will then issue the "logmsg". This
2525 // is necessary in order to "capture" the process's o/p since the logmsg
2526 // capture facility is designed to capture o/p for a specific thread,
2527 // where that thread is US! (else if we let the monitoring thread issue
2528 // the logmsg's, they'll never get captured since they don't have the
2529 // same thread-id as the thread that started the capture, which was us!
2530 // (actually it was the caller, but we're the same thread as they are!)).
2531
2532 pPipedStdOutThreadCtl = malloc( sizeof(PIPED_THREAD_CTL) );
2533 pPipedStdErrThreadCtl = malloc( sizeof(PIPED_THREAD_CTL) );
2534
2535 pPipedStdOutThreadCtl->hStdXXX = hOurReadFromStdout;
2536 pPipedStdErrThreadCtl->hStdXXX = hOurReadFromStderr;
2537
2538 if ( !pnWriteToChildStdinFD )
2539 {
2540 pPipedProcessCtl = malloc( sizeof(PIPED_PROCESS_CTL) );
2541
2542 pPipedStdOutThreadCtl->pPipedProcessCtl = pPipedProcessCtl;
2543 pPipedStdErrThreadCtl->pPipedProcessCtl = pPipedProcessCtl;
2544
2545 InitializeCriticalSection( &pPipedProcessCtl->csLock );
2546 pPipedProcessCtl->nAllocSize = 1; // (purposely small for debugging)
2547 pPipedProcessCtl->pszBuffer = malloc( 1 ); // (purposely small for debugging)
2548 *pPipedProcessCtl->pszBuffer = 0; // (null terminate string buffer)
2549 pPipedProcessCtl->nStrLen = 0; // (no msgs yet)
2550 }
2551 else
2552 {
2553 pPipedStdOutThreadCtl->pPipedProcessCtl = NULL;
2554 pPipedStdErrThreadCtl->pPipedProcessCtl = NULL;
2555 }
2556
2557 //////////////////////////////////////////////////
2558 // Create o/p pipe monitoring worker threads...
2559 //////////////////////////////////////////////////
2560 // Stdout...
2561
2562 hWorkerThread = (HANDLE) _beginthreadex
2563 (
2564 NULL, // pointer to security attributes = use defaults
2565 PIPE_THREAD_STACKSIZE, // initial thread stack size
2566 w32_read_piped_process_stdxxx_output_thread,
2567 pPipedStdOutThreadCtl, // thread argument
2568 0, // special creation flags = none needed
2569 &dwThreadId // pointer to receive thread ID
2570 );
2571 rc = GetLastError(); // (save return code)
2572
2573 if (!hWorkerThread || INVALID_HANDLE_VALUE == hWorkerThread)
2574 {
2575 TRACE("*** _beginthreadex() failed! rc = %d : %s\n",
2576 rc,w32_strerror(rc));
2577
2578 if (pnWriteToChildStdinFD)
2579 VERIFY(CloseHandle(hOurWriteToStdin));
2580 VERIFY(CloseHandle(hOurReadFromStdout));
2581 VERIFY(CloseHandle(hOurReadFromStderr));
2582
2583 if ( !pnWriteToChildStdinFD )
2584 {
2585 DeleteCriticalSection( &pPipedProcessCtl->csLock );
2586 free( pPipedProcessCtl->pszBuffer );
2587 free( pPipedProcessCtl );
2588 }
2589 free( pPipedStdOutThreadCtl );
2590 free( pPipedStdErrThreadCtl );
2591
2592 errno = rc;
2593 return -1;
2594 }
2595 else
2596 VERIFY(CloseHandle(hWorkerThread)); // (not needed anymore)
2597
2598 SET_THREAD_NAME_ID(dwThreadId,"w32_read_piped_process_stdOUT_output_thread");
2599
2600 //////////////////////////////////////////////////
2601 // Stderr...
2602
2603 hWorkerThread = (HANDLE) _beginthreadex
2604 (
2605 NULL, // pointer to security attributes = use defaults
2606 PIPE_THREAD_STACKSIZE, // initial thread stack size
2607 w32_read_piped_process_stdxxx_output_thread,
2608 pPipedStdErrThreadCtl, // thread argument
2609 0, // special creation flags = none needed
2610 &dwThreadId // pointer to receive thread ID
2611 );
2612 rc = GetLastError(); // (save return code)
2613
2614 if (!hWorkerThread || INVALID_HANDLE_VALUE == hWorkerThread)
2615 {
2616 TRACE("*** _beginthreadex() failed! rc = %d : %s\n",
2617 rc,w32_strerror(rc));
2618
2619 if (pnWriteToChildStdinFD)
2620 VERIFY(CloseHandle(hOurWriteToStdin));
2621 VERIFY(CloseHandle(hOurReadFromStdout));
2622 VERIFY(CloseHandle(hOurReadFromStderr));
2623
2624 if ( !pnWriteToChildStdinFD )
2625 {
2626 DeleteCriticalSection( &pPipedProcessCtl->csLock );
2627 free( pPipedProcessCtl->pszBuffer );
2628 free( pPipedProcessCtl );
2629 }
2630 free( pPipedStdOutThreadCtl );
2631 free( pPipedStdErrThreadCtl );
2632
2633 errno = rc;
2634 return -1;
2635 }
2636 else
2637 VERIFY(CloseHandle(hWorkerThread)); // (not needed anymore)
2638
2639 SET_THREAD_NAME_ID(dwThreadId,"w32_read_piped_process_stdERR_output_thread");
2640
2641 // Piped process capture handling...
2642
2643 if ( !pnWriteToChildStdinFD )
2644 {
2645 // We're in control of the process...
2646 // Wait for it to exit...
2647
2648 WaitForSingleObject( piProcInfo.hProcess, INFINITE );
2649 CloseHandle( piProcInfo.hProcess );
2650
2651 // Now print ALL captured messages AT ONCE (if any)...
2652
2653 while (pPipedProcessCtl->nStrLen && isspace( pPipedProcessCtl->pszBuffer[ pPipedProcessCtl->nStrLen - 1 ] ))
2654 pPipedProcessCtl->nStrLen--;
2655 if (pPipedProcessCtl->nStrLen)
2656 {
2657 pPipedProcessCtl->pszBuffer[ pPipedProcessCtl->nStrLen ] = 0; // (null terminate)
2658 logmsg( "%s", pPipedProcessCtl->pszBuffer );
2659 }
2660
2661 // Free resources...
2662
2663 DeleteCriticalSection( &pPipedProcessCtl->csLock );
2664 free( pPipedProcessCtl->pszBuffer );
2665 free( pPipedProcessCtl );
2666 }
2667 else
2668 {
2669 // Caller is in control of the process...
2670
2671 CloseHandle( piProcInfo.hProcess );
2672
2673 // Return a C run-time file descriptor
2674 // for the write-to-child-stdin HANDLE...
2675
2676 *pnWriteToChildStdinFD = _open_osfhandle( (intptr_t) hOurWriteToStdin, 0 );
2677 }
2678
2679 // Success!
2680
2681 return piProcInfo.dwProcessId; // (return process-id to caller)
2682 }
2683
2684 //////////////////////////////////////////////////////////////////////////////////////////
2685 // Thread to read message data from the child process's stdxxx o/p pipe...
2686
2687 void w32_parse_piped_process_stdxxx_data ( PIPED_PROCESS_CTL* pPipedProcessCtl, char* holdbuff, int* pnHoldAmount );
2688
w32_read_piped_process_stdxxx_output_thread(void * pThreadParm)2689 UINT WINAPI w32_read_piped_process_stdxxx_output_thread ( void* pThreadParm )
2690 {
2691 PIPED_THREAD_CTL* pPipedStdXXXThreadCtl = NULL;
2692 PIPED_PROCESS_CTL* pPipedProcessCtl = NULL;
2693
2694 HANDLE hOurReadFromStdxxx = NULL;
2695 DWORD nAmountRead = 0;
2696 int nHoldAmount = 0;
2697 BOOL oflow = FALSE;
2698 unsigned nRetcode = 0;
2699
2700 char readbuff [ PIPEBUFSIZE ];
2701 char holdbuff [ HOLDBUFSIZE ];
2702
2703 // Extract parms
2704
2705 pPipedStdXXXThreadCtl = (PIPED_THREAD_CTL*) pThreadParm;
2706
2707 pPipedProcessCtl = pPipedStdXXXThreadCtl->pPipedProcessCtl;
2708 hOurReadFromStdxxx = pPipedStdXXXThreadCtl->hStdXXX;
2709
2710 free( pPipedStdXXXThreadCtl ); // (prevent memory leak)
2711
2712 // Begin work...
2713
2714 for (;;)
2715 {
2716 if (!ReadFile(hOurReadFromStdxxx, readbuff, PIPEBUFSIZE-1, &nAmountRead, NULL))
2717 {
2718 if (ERROR_BROKEN_PIPE == (nRetcode = GetLastError()))
2719 nRetcode = 0;
2720 // (else keep value returned from GetLastError())
2721 break;
2722 }
2723 *(readbuff+nAmountRead) = 0;
2724
2725 if (!nAmountRead) break; // (pipe closed (i.e. broken pipe); time to exit)
2726
2727 if ((nHoldAmount + nAmountRead) >= (HOLDBUFSIZE-1))
2728 {
2729 // OVERFLOW! append "truncated" string and force end-of-msg...
2730
2731 oflow = TRUE;
2732 memcpy( holdbuff + nHoldAmount, readbuff, HOLDBUFSIZE - nHoldAmount);
2733 strcpy( readbuff, buffer_overflow_msg);
2734 nAmountRead = (DWORD)buffer_overflow_msg_len;
2735 nHoldAmount = HOLDBUFSIZE - nAmountRead - 1;
2736 }
2737
2738 // Append new data to end of hold buffer...
2739
2740 memcpy(holdbuff+nHoldAmount,readbuff,nAmountRead);
2741 nHoldAmount += nAmountRead;
2742 *(holdbuff+nHoldAmount) = 0;
2743
2744 // Pass all existing data to parsing function...
2745
2746 w32_parse_piped_process_stdxxx_data( pPipedProcessCtl, holdbuff, &nHoldAmount );
2747
2748 if (oflow) ASSERT(!nHoldAmount); oflow = FALSE;
2749 }
2750
2751 // Finish up...
2752
2753 CloseHandle( hOurReadFromStdxxx ); // (prevent HANDLE leak)
2754
2755 return nRetcode;
2756 }
2757
2758 //////////////////////////////////////////////////////////////////////////////////////////
2759 // Parse piped child's stdout/stderr o/p data into individual newline delimited
2760 // messages for displaying on the Hercules hardware console...
2761
w32_parse_piped_process_stdxxx_data(PIPED_PROCESS_CTL * pPipedProcessCtl,char * holdbuff,int * pnHoldAmount)2762 void w32_parse_piped_process_stdxxx_data ( PIPED_PROCESS_CTL* pPipedProcessCtl, char* holdbuff, int* pnHoldAmount )
2763 {
2764 // This function executes in the context of the worker thread that calls it.
2765
2766 char* pbeg; // ptr to start of message
2767 char* pend; // find end of message (MUST NOT BE MODIFIED!)
2768 char* pmsgend; // work ptr to end of message
2769 // 'pend' variable MUST NOT BE MODIFIED
2770 int nlen; // work length of one message
2771 int ntotlen; // accumulated length of all parsed messages
2772
2773 // A worker thread that monitors a child's Stdout o/p has received a message
2774 // and is calling this function to determine what, if anything, to do with it.
2775
2776 // (Note: the worker thread that calls us ensures holdbuff is null terminated)
2777
2778 pbeg = holdbuff; // ptr to start of message
2779 pend = strchr(pbeg,'\n'); // find end of message (MUST NOT BE MODIFIED!)
2780 if (!pend) return; // we don't we have a complete message yet
2781 ntotlen = 0; // accumulated length of all parsed messages
2782
2783 // Parse the message...
2784
2785 do
2786 {
2787 nlen = (pend-pbeg); // get length of THIS message
2788 ntotlen += nlen + 1; // keep track of all that we see
2789
2790 // Remove trailing newline character and any other trailing blanks...
2791
2792 // (Note: we MUST NOT MODIFY the 'pend' variable. It should always
2793 // point to where the newline character was found so we can start
2794 // looking for the next message (if there is one) where this message
2795 // ended).
2796
2797 *pend = 0; // (change newline character to null)
2798 pmsgend = pend; // (start removing blanks from here)
2799
2800 while (--pmsgend >= pbeg && isspace(*pmsgend)) {*pmsgend = 0; --nlen;}
2801
2802 // If we were passed a PIPED_PROCESS_CTL pointer, then the root thread
2803 // wants us to just capture the o/p and IT will issue the logmsg within
2804 // its own thread. Otherwise root thread isn't interested in capturing
2805 // and thus we must issue the individual logmsg's ourselves...
2806
2807 if (!pPipedProcessCtl)
2808 {
2809 logmsg("%s\n",pbeg); // send all child's msgs to Herc console
2810 }
2811 else
2812 {
2813 size_t nNewStrLen, nAllocSizeNeeded; // (work)
2814
2815 EnterCriticalSection( &pPipedProcessCtl->csLock );
2816
2817 nNewStrLen = strlen( pbeg );
2818 nAllocSizeNeeded = ((((pPipedProcessCtl->nStrLen + nNewStrLen + 2) / 4096) + 1) * 4096);
2819
2820 if ( nAllocSizeNeeded > pPipedProcessCtl->nAllocSize )
2821 {
2822 pPipedProcessCtl->nAllocSize = nAllocSizeNeeded;
2823 pPipedProcessCtl->pszBuffer = realloc( pPipedProcessCtl->pszBuffer, nAllocSizeNeeded );
2824 ASSERT( pPipedProcessCtl->pszBuffer );
2825 }
2826
2827 if (nNewStrLen)
2828 {
2829 memcpy( pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen, pbeg, nNewStrLen );
2830 pPipedProcessCtl->nStrLen += nNewStrLen;
2831 }
2832
2833 *(pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen) = '\n';
2834 pPipedProcessCtl->nStrLen++;
2835 *(pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen) = '\0';
2836
2837 ASSERT( pPipedProcessCtl->nStrLen <= pPipedProcessCtl->nAllocSize );
2838
2839 LeaveCriticalSection( &pPipedProcessCtl->csLock );
2840 }
2841
2842 // 'pend' should still point to the end of this message (where newline was)
2843
2844 pbeg = (pend + 1); // point to beg of next message (if any)
2845
2846 if (pbeg >= (holdbuff + *pnHoldAmount)) // past end of data?
2847 {
2848 pbeg = pend; // re-point back to our null
2849 ASSERT(*pbeg == 0); // sanity check
2850 break; // we're done with this batch
2851 }
2852
2853 pend = strchr(pbeg,'\n'); // is there another message?
2854 }
2855 while (pend); // while messages remain...
2856
2857 if (ntotlen > *pnHoldAmount) // make sure we didn't process too much
2858 {
2859 TRACE("*** ParseStdxxxMsg logic error! ***\n");
2860 ASSERT(FALSE); // oops!
2861 }
2862
2863 // 'Remove' the messages that we parsed from the caller's hold buffer by
2864 // sliding the remainder to the left (i.e. left justifying the remainder
2865 // in their hold buffer) and then telling them how much data now remains
2866 // in their hold buffer.
2867
2868 // IMPORTANT PROGRAMMING NOTE! We must use memmove here and not strcpy!
2869 // strcpy doesn't work correctly for overlapping source and destination.
2870 // If there's 100 bytes remaining and we just want to slide it left by 1
2871 // byte (just as an illustrative example), strcpy screws up. This is more
2872 // than likely because strcpy is trying to be as efficient as possible and
2873 // is grabbing multiple bytes at a time from the source string and plonking
2874 // them down into the destination string, thus wiping out part of our source
2875 // string. Thus, we MUST use memmove here and NOT strcpy.
2876
2877 if ((*pnHoldAmount = (int)strlen(pbeg)) > 0) // new amount of data remaining
2878 memmove(holdbuff,pbeg,*pnHoldAmount); // slide left justify remainder
2879 }
2880
2881 //////////////////////////////////////////////////////////////////////////////////////////
2882 // The following is documented in Microsoft's Visual Studio developer documentation...
2883
2884 #define MS_VC_EXCEPTION 0x406D1388 // (special value)
2885
2886 typedef struct tagTHREADNAME_INFO
2887 {
2888 DWORD dwType; // must be 0x1000
2889 LPCSTR pszName; // pointer to name (in same addr space)
2890 DWORD dwThreadID; // thread ID (-1 caller thread)
2891 DWORD dwFlags; // reserved for future use, must be zero
2892 }
2893 THREADNAME_INFO;
2894
w32_set_thread_name(TID tid,char * name)2895 DLL_EXPORT void w32_set_thread_name( TID tid, char* name )
2896 {
2897 THREADNAME_INFO info;
2898
2899 if (!name) return; // (ignore premature calls)
2900
2901 info.dwType = 0x1000;
2902 info.pszName = name; // (should really be LPCTSTR)
2903 info.dwThreadID = tid; // (-1 == current thread, else tid)
2904 info.dwFlags = 0;
2905
2906 __try
2907 {
2908 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (const ULONG_PTR*)&info );
2909 }
2910 __except ( EXCEPTION_CONTINUE_EXECUTION )
2911 {
2912 /* (do nothing) */
2913 }
2914 }
2915
2916 //////////////////////////////////////////////////////////////////////////////////////////
2917 // Hercules file open
2918 // w32_hopen is called instead of hopen in MSVC environment (see hercwind.h)
2919 // Its purpose is to prevent a file from being opened for output by two
2920 // Hercules instances at the same time.
2921 // _SH_DENYRW prevents all access to the file from other processes;
2922 // _SH_DENYWR permits other processes to read the file but not to write;
2923 // _SH_SECURE opens the file in _SH_DENYRW mode if oflag specifies write
2924 // access, or _SH_DENYWR mode if oflag specifies read-only.
w32_hopen(const char * path,int oflag,...)2925 DLL_EXPORT int w32_hopen( const char* path, int oflag, ... )
2926 {
2927 int shflag = (oflag & _O_RDWR) ? _SH_DENYRW : _SH_DENYWR;
2928 int pmode = 0;
2929 if (oflag & _O_CREAT)
2930 {
2931 va_list vargs;
2932 va_start( vargs, oflag );
2933 pmode = va_arg( vargs, int );
2934 }
2935 return _sopen( path, oflag, shflag, pmode );
2936 }
2937
2938 //////////////////////////////////////////////////////////////////////////////////////////
2939
2940 #endif // defined( _MSVC_ )
2941