/*++ Copyright (c) 1991-1993 Microsoft Corporation Module Name: TOD.c Abstract: This file contains the RpcXlate code to handle the NetRemote APIs that can't be handled by simple calls to RxRemoteApi. Author: John Rogers (JohnRo) 02-Apr-1991 Environment: Portable to any flat, 32-bit environment. (Uses Win32 typedefs.) Requires ANSI C extensions: slash-slash comments, long external names. This code assumes that time_t is expressed in seconds since 1970 (GMT). ANSI C does not require this, although POSIX (IEEE 1003.1) does. Revision History: 02-Apr-1991 JohnRo Created. 13-Apr-1991 JohnRo Moved API handlers into per-group header files (e.g. RxServer.h). Quiet debug output by default. Reduced recompile hits from header files. 03-May-1991 JohnRo Changed to use both 16-bit data desc and SMB data desc. Use LPTSTR. Call RxpTransactSmb with UNC server name. 06-May-1991 JohnRo Use RxpComputeRequestBufferSize(). Use correct print strings for server name and descriptors. 15-May-1991 JohnRo Added conversion mode handling. 19-May-1991 JohnRo Make LINT-suggested changes. Got rid of tabs (again). 17-Jul-1991 JohnRo Extracted RxpDebug.h from Rxp.h. 25-Sep-1991 JohnRo Handle RapConvertSingleEntry's new return code. 21-Nov-1991 JohnRo Removed NT dependencies to reduce recompiles. 07-Feb-1992 JohnRo Use NetApiBufferAllocate() instead of private version. 15-Apr-1992 JohnRo FORMAT_POINTER is obsolete. 18-Aug-1992 JohnRo RAID 2920: Support UTC timezone in net code. Use PREFIX_ equates. 01-Oct-1992 JohnRo RAID 3556: Added NetpSystemTimeToGmtTime() for DosPrint APIs. 10-Jun-1993 JohnRo RAID 13081: NetRemoteTOD should return timezone info in right units. --*/ // These must be included first: #include // IN, LPTSTR, etc. #include // These may be included in any order: #include #include // NetApiBufferFree(). #include // NO_ERROR, ERROR_ and NERR_ equates. #include // Real API prototypes and #defines. #include // NetpKdPrint(()), FORMAT_ equates, etc. #include // PREFIX_ equates. #include // 16-bit and 32-bit descriptor strings. #include // RxRemoteApi(). #include // IF_DEBUG(). #include // My prototype. #include // gmtime(), struct tm, time_t. #include // NetpGmtTimeToLocalTime(), NetpLocalTimeZoneOffset(). NET_API_STATUS RxNetRemoteTOD ( IN LPTSTR UncServerName, OUT LPBYTE *BufPtr ) /*++ Routine Description: RxNetRemoteTOD performs the same function as NetRemoteTOD, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetRemoteTOD, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetRemoteTOD.) --*/ { NET_API_STATUS ApiStatus; time_t GmtTime; // seconds since 1970 (GMT). struct tm * pGmtTm; // broken down GMT time (static obj). PTIME_OF_DAY_INFO pGmtTod = NULL; // TOD on remote sys, GMT timezone. LONG LocalTimeZoneOffsetSecs; // offset (+ for West of GMT, etc). TIME_OF_DAY_INFO LocalTod; // TOD on remote sys, local timezone. LONG timezone; NetpAssert(UncServerName != NULL); IF_DEBUG(REMUTL) { NetpKdPrint(( PREFIX_NETAPI "RxNetRemoteTOD: starting, server='" FORMAT_LPTSTR "'.\n", UncServerName)); } // // REM32_time_of_day_info, also used by XACTSRV, translates the // 16-bit local time returned from the server to GMT. Unfortunately // it uses the timezone of the local machine rather than the timezone // returned from the server. So, we have our own define here, which // uses 'J'instead of 'G' so that no translation takes place. Then // we do our own translation below. This makes us work with // Windows 95 servers. #define REM32_time_of_day_info_2 "JDDDDDXDDDDD" // // Get TOD structure (with local time values) from other system. // Note that the "tod_elapsedt" field will be converted from local // timezone to GMT by RxRemoteApi. // ApiStatus = RxRemoteApi( API_NetRemoteTOD, // API number (LPTSTR) UncServerName, REMSmb_NetRemoteTOD_P, // parm desc REM16_time_of_day_info, // DataDesc16 REM32_time_of_day_info_2, // DataDesc32 REMSmb_time_of_day_info, // DataDescSmb NULL, // no AuxDesc16 NULL, // no AuxDesc32 NULL, // no AuxDescSmb 0, // flags: not a null session API // rest of API's arguments, in 32-bit LM2.x format: (LPVOID) & LocalTod, // pbBuffer sizeof(LocalTod) ); // cbBuffer IF_DEBUG(REMUTL) { NetpKdPrint(( PREFIX_NETAPI "RxNetRemoteTOD: after RxRemoteApi, " "ApiStatus=" FORMAT_API_STATUS ".\n", ApiStatus)); } if (ApiStatus != NO_ERROR) { goto Cleanup; } // // Get info on the timezone itself. If target machine doesn't know, then // we have to fall back on the age-old policy: assume it is running in // same timezone that we are. // if (LocalTod.tod_timezone == -1) { // // First, get number of seconds from UTC. (Positive values for // west of Greenwich, negative values for east of Greenwich.) // Then, convert to minutes. LocalTimeZoneOffsetSecs = NetpLocalTimeZoneOffset(); timezone = LocalTimeZoneOffsetSecs / 60; } else { timezone = LocalTod.tod_timezone; } // // Get GmtTime (time in seconds since 1970, GMT) for convenience. // NetpAssert( sizeof(DWORD) == sizeof(time_t) ); GmtTime = (time_t) LocalTod.tod_elapsedt + timezone * 60; IF_DEBUG(REMUTL) { NetpKdPrint(( PREFIX_NETAPI "RxNetRemoteTOD: before convert, buffer:\n")); NetpDbgDisplayTod( "before GMT conv", & LocalTod ); NetpDbgDisplayTimestamp( "secs since 1970 (GMT)", (DWORD) GmtTime ); } NetpAssert( GmtTime != 0 ); NetpAssert( GmtTime != (time_t) (-1) ); // // Alloc area for converted time of day info. // API's caller will free this with NetApiBufferFree(). // ApiStatus = NetApiBufferAllocate( sizeof(TIME_OF_DAY_INFO), (LPVOID *) (LPVOID) & pGmtTod ); if (ApiStatus != NO_ERROR) { NetpAssert( pGmtTod == NULL ); goto Cleanup; } NetpAssert( pGmtTod != NULL ); // // Convert LocalTod fields to UTC timezone and set pGmtTod fields. // This depends on the POSIX semantics of gmtime(). // pGmtTm = gmtime( (time_t *) &(GmtTime) ); if (pGmtTm == NULL) { // UTC not available? How can this happen? NetpKdPrint(( PREFIX_NETAPI "RxNetRemoteTOD: gmtime() failed!.\n" )); ApiStatus = NERR_InternalError; goto Cleanup; } pGmtTod->tod_elapsedt = (DWORD) GmtTime; pGmtTod->tod_msecs = LocalTod.tod_msecs; pGmtTod->tod_hours = pGmtTm->tm_hour; pGmtTod->tod_mins = pGmtTm->tm_min; if (pGmtTm->tm_sec <= 59) { // Normal. pGmtTod->tod_secs = pGmtTm->tm_sec; } else { // Leap second. Lie and say that it's not. This will avoid possible // range problems in apps that only expect 0..59, as the // TIME_OF_DAY_INFO struct is documented in LM 2.x. pGmtTod->tod_secs = 59; } pGmtTod->tod_hunds = LocalTod.tod_hunds; pGmtTod->tod_tinterval = LocalTod.tod_tinterval; pGmtTod->tod_day = pGmtTm->tm_mday; pGmtTod->tod_month = pGmtTm->tm_mon + 1; // month (0..11) to (1..12) pGmtTod->tod_year = pGmtTm->tm_year + 1900; pGmtTod->tod_weekday = pGmtTm->tm_wday; pGmtTod->tod_timezone = timezone; IF_DEBUG(REMUTL) { NetpKdPrint(( PREFIX_NETAPI "RxNetRemoteTOD: after convert, buffer:\n")); NetpDbgDisplayTod( "after GMT conv", pGmtTod ); } Cleanup: if (ApiStatus == NO_ERROR) { *BufPtr = (LPBYTE) (LPVOID) pGmtTod; } else if (pGmtTod != NULL) { (VOID) NetApiBufferFree( pGmtTod ); } return (ApiStatus); } // RxNetRemoteTOD