Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2725 lines
78 KiB

  1. //****************************************************************************
  2. //
  3. // Microsoft Windows NT RIP
  4. //
  5. // Copyright 1995-96
  6. //
  7. //
  8. // Revision History
  9. //
  10. //
  11. // 2/26/95 Gurdeep Singh Pall Picked up from JBallard's team
  12. //
  13. // 7/09/99 Raghu Gatta - RIP Listener is now RIPv2 compliant
  14. //
  15. // Description: Main RIP Service Functions
  16. //
  17. //****************************************************************************
  18. #include "pchrip.h"
  19. #pragma hdrstop
  20. //-----------------------------------------------------------------------
  21. // global definitions
  22. //-----------------------------------------------------------------------
  23. RIP_PARAMETERS g_params;
  24. RIP_GLOBALS g_ripcfg;
  25. #ifdef ROUTE_FILTERS
  26. PRIP_FILTERS g_prfAnnounceFilters = NULL;
  27. PRIP_FILTERS g_prfAcceptFilters = NULL;
  28. CRITICAL_SECTION g_csAccFilters;
  29. CRITICAL_SECTION g_csAnnFilters;
  30. #endif
  31. CRITICAL_SECTION g_csRoutes;
  32. CRITICAL_SECTION g_csParameters;
  33. CRITICAL_SECTION g_csAddrtables;
  34. #ifndef CHICAGO
  35. SERVICE_STATUS_HANDLE g_hService;
  36. #endif
  37. HANDLE g_stopEvent;
  38. SOCKET g_stopSocket;
  39. DWORD g_stopReason = (DWORD) -1;
  40. HANDLE g_triggerEvent;
  41. HANDLE g_updateDoneEvent;
  42. HANDLE g_changeNotifyDoneEvent;
  43. DWORD g_dwTraceID = (DWORD)-1;
  44. DWORD g_dwCurrentState;
  45. DWORD g_dwCheckPoint;
  46. DWORD g_dwWaitHint;
  47. #ifndef CHICAGO
  48. HMODULE g_hmodule;
  49. #endif
  50. //-----------------------------------------------------------------------
  51. // Function: NetclassMask
  52. //
  53. // returns the mask used to extract the network address from an
  54. // Internet address
  55. //-----------------------------------------------------------------------
  56. DWORD NetclassMask(DWORD dwAddress) {
  57. // net masks are returned in network byte order
  58. if (CLASSA_ADDR(dwAddress)) {
  59. return CLASSA_MASK;
  60. }
  61. else
  62. if (CLASSB_ADDR(dwAddress)) {
  63. return CLASSB_MASK;
  64. }
  65. else
  66. if (CLASSC_ADDR(dwAddress)) {
  67. return CLASSC_MASK;
  68. }
  69. else {
  70. return 0;
  71. }
  72. }
  73. //-----------------------------------------------------------------------
  74. // Function: SubnetMask
  75. //
  76. // Given an IP address, return the sub-network mask. This function
  77. // assumes the address table is already locked.
  78. //-----------------------------------------------------------------------
  79. DWORD SubnetMask(DWORD dwAddress) {
  80. DWORD dwNetmask;
  81. LPRIP_ADDRESS lpaddr, lpend;
  82. // subnet mask should be zero for default routes
  83. if (dwAddress == 0) { return 0; }
  84. // if its a broadcast address return all ones
  85. if (dwAddress == INADDR_BROADCAST) { return INADDR_BROADCAST; }
  86. //dwNetmask = NetclassMask(dwAddress);
  87. dwNetmask = NETCLASS_MASK(dwAddress);
  88. // if the network part is zero, return the network mask
  89. if ((dwAddress & ~dwNetmask) == 0) {
  90. return dwNetmask;
  91. }
  92. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  93. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  94. // if the address is found, return the subnet mask
  95. if ((dwAddress & dwNetmask) ==
  96. (lpaddr->dwAddress & NetclassMask(lpaddr->dwAddress))) {
  97. return lpaddr->dwNetmask;
  98. }
  99. }
  100. // address not found, return the network class mask
  101. return dwNetmask;
  102. }
  103. //-----------------------------------------------------------------------
  104. // Function: IsBroadcastAddress
  105. //
  106. // Returns TRUE if the given IP address is an all-ones bcast
  107. // or a class A, B, or C net broadcast. IP address is assumed to be
  108. // in network order (which is the reverse of Intel byte ordering.)
  109. //-----------------------------------------------------------------------
  110. BOOL IsBroadcastAddress(DWORD dwAddress) {
  111. if ((dwAddress == INADDR_BROADCAST) ||
  112. (CLASSA_ADDR(dwAddress) && ((dwAddress & ~CLASSA_MASK) ==
  113. ~CLASSA_MASK)) ||
  114. (CLASSB_ADDR(dwAddress) && ((dwAddress & ~CLASSB_MASK) ==
  115. ~CLASSB_MASK)) ||
  116. (CLASSC_ADDR(dwAddress) && ((dwAddress & ~CLASSC_MASK) ==
  117. ~CLASSC_MASK))) {
  118. return TRUE;
  119. }
  120. return FALSE;
  121. }
  122. //-----------------------------------------------------------------------
  123. // Function: IsLocalAddr
  124. //
  125. // Returns TRUE if the given IP address belongs to one of the interfaces
  126. // on the local host. Assumes that the IP address is in network order
  127. // and that the address table is already locked.
  128. //-----------------------------------------------------------------------
  129. BOOL IsLocalAddr(DWORD dwAddress) {
  130. LPRIP_ADDRESS lpaddr, lpend;
  131. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  132. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  133. if (dwAddress == lpaddr->dwAddress) {
  134. return TRUE;
  135. }
  136. }
  137. return FALSE;
  138. }
  139. BOOL IsDisabledLocalAddress(DWORD dwAddress) {
  140. LPRIP_ADDRESS lpaddr, lpend;
  141. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  142. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  143. if ((lpaddr->dwFlag & ADDRFLAG_DISABLED) != 0 &&
  144. (dwAddress == lpaddr->dwAddress)) {
  145. return TRUE;
  146. }
  147. }
  148. return FALSE;
  149. }
  150. //-----------------------------------------------------------------------
  151. // Function: IsHostAddress
  152. //
  153. // Returns TRUE if the given IP address has a non-zero host part.
  154. // Assumes that the IP address is in network order and that
  155. // the address table is already locked.
  156. //-----------------------------------------------------------------------
  157. BOOL IsHostAddress(DWORD dwAddress) {
  158. DWORD dwNetmask;
  159. // find most specific netmask we have for the address
  160. dwNetmask = SubnetMask(dwAddress);
  161. // if host part is non-zero, assume it is a host address
  162. if ((dwAddress & (~dwNetmask)) != 0) {
  163. return TRUE;
  164. }
  165. return FALSE;
  166. }
  167. //-----------------------------------------------------------------------
  168. // Function: ProcessRIPEntry
  169. //
  170. // This function examines a single entry in a RIP packet and
  171. // adds it to the hash table if necessary.
  172. //-----------------------------------------------------------------------
  173. DWORD ProcessRIPEntry(LPRIP_ADDRESS lpaddr, IN_ADDR srcaddr,
  174. LPRIP_ENTRY rip_entry, BYTE chVersion) {
  175. IN_ADDR addr;
  176. BOOL bIsHostAddr;
  177. CHAR szAddress[32] = {0};
  178. CHAR szSrcaddr[32] = {0};
  179. CHAR szMetric[12];
  180. LPSTR ppszArgs[3] = { szAddress, szSrcaddr, szMetric };
  181. LPHASH_TABLE_ENTRY rt_entry;
  182. DWORD rt_metric, rip_metric;
  183. DWORD dwHost, dwDefault, dwRouteTimeout;
  184. DWORD dwOverwriteStatic, dwGarbageTimeout;
  185. DWORD dwInd = 0;
  186. DWORD dwNetwork, dwNetmask, dwNetclassmask;
  187. CHAR *pszTemp;
  188. addr.s_addr = rip_entry->dwAddress;
  189. pszTemp = inet_ntoa(addr);
  190. if (pszTemp != NULL) {
  191. strcpy(szAddress, pszTemp);
  192. }
  193. pszTemp = inet_ntoa(srcaddr);
  194. if (pszTemp != NULL) {
  195. strcpy(szSrcaddr, pszTemp);
  196. }
  197. // ignore metrics greater than infinity
  198. if (ntohl(rip_entry->dwMetric) > METRIC_INFINITE) {
  199. dbgprintf("metric > %d, ignoring route to %s with next hop of %s",
  200. METRIC_INFINITE, szAddress, szSrcaddr);
  201. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  202. return 0;
  203. }
  204. // ignore class D and E addresses
  205. if (CLASSD_ADDR(rip_entry->dwAddress) ||
  206. CLASSE_ADDR(rip_entry->dwAddress)) {
  207. dbgprintf("class D or E addresses are invalid, "
  208. "ignoring route to %s with next hop of %s",
  209. szAddress, szSrcaddr);
  210. RipLogWarning(RIPLOG_CLASS_INVALID, 2, ppszArgs, 0);
  211. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  212. return 0;
  213. }
  214. // ignore loopback routes
  215. if (IP_LOOPBACK_ADDR(rip_entry->dwAddress)) {
  216. dbgprintf("loopback addresses are invalid, "
  217. "ignoring route to %s with next hop of %s",
  218. szAddress, szSrcaddr);
  219. RipLogWarning(RIPLOG_LOOPBACK_INVALID, 2, ppszArgs, 0);
  220. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  221. return 0;
  222. }
  223. dwNetwork = rip_entry->dwAddress;
  224. //
  225. // calculate mask for all RIP versions
  226. //
  227. if (rip_entry->dwSubnetmask == 0) {
  228. // get the best subnetmask possible
  229. dwNetmask = SubnetMask(dwNetwork);
  230. // determine NetclassMask
  231. if (dwNetwork == 0) {
  232. dwNetclassmask = 0;
  233. }
  234. else if (dwNetwork == INADDR_BROADCAST) {
  235. dwNetclassmask = INADDR_BROADCAST;
  236. }
  237. else {
  238. dwNetclassmask = NETCLASS_MASK(rip_entry->dwAddress);
  239. }
  240. }
  241. else {
  242. dwNetmask = rip_entry->dwSubnetmask;
  243. //
  244. // double-check the netclass mask, to accomodate supernets
  245. //
  246. dwNetclassmask = NETCLASS_MASK(dwNetwork);
  247. if (dwNetclassmask > dwNetmask) {
  248. dwNetclassmask = dwNetmask;
  249. }
  250. }
  251. //
  252. // make sure route is not to a broadcast address;
  253. // double-check to make sure this isn't a host route,
  254. // which will look like a broadcast address since ~dwNetmask
  255. // will be 0 and thus (dwNetwork & ~dwNetmask) == ~dwNetmask
  256. //
  257. if ((dwNetwork & ~dwNetclassmask) == ~dwNetclassmask ||
  258. (~dwNetmask && (dwNetwork & ~dwNetmask) == ~dwNetmask)) {
  259. dbgprintf("broadcast addresses are invalid, "
  260. "ignoring route to %s with next hop of %s",
  261. szAddress, szSrcaddr);
  262. RipLogWarning(RIPLOG_BROADCAST_INVALID, 2, ppszArgs, 0);
  263. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  264. return 0;
  265. }
  266. #ifdef ROUTE_FILTERS
  267. //
  268. // run the route thru' the accept filters
  269. //
  270. if ( g_prfAcceptFilters != NULL )
  271. {
  272. for ( dwInd = 0; dwInd < g_prfAcceptFilters-> dwCount; dwInd++ )
  273. {
  274. if ( g_prfAcceptFilters-> pdwFilter[ dwInd ] ==
  275. rip_entry-> dwAddress )
  276. {
  277. dbgprintf("Dropped route %s with next hop %s because"
  278. "of accept filter",
  279. szAddress, szSrcaddr);
  280. return 0;
  281. }
  282. }
  283. }
  284. #endif
  285. RIP_LOCK_PARAMS();
  286. dwHost = g_params.dwAcceptHost;
  287. dwDefault = g_params.dwAcceptDefault;
  288. dwRouteTimeout = g_params.dwRouteTimeout;
  289. dwGarbageTimeout = g_params.dwGarbageTimeout;
  290. dwOverwriteStatic = g_params.dwOverwriteStaticRoutes;
  291. RIP_UNLOCK_PARAMS();
  292. // ignore host routes unless configured otherwise
  293. if (bIsHostAddr = ((dwNetwork & ~dwNetmask) != 0)) {
  294. if (dwHost == 0) {
  295. dbgprintf("IPRIP is configured to discard host routes, "
  296. "ignoring route to %s with next hop of %s",
  297. szAddress, szSrcaddr);
  298. RipLogInformation(RIPLOG_HOST_INVALID, 2, ppszArgs, 0);
  299. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  300. return 0;
  301. }
  302. }
  303. // ignore default routes unless configured otherwise
  304. if (rip_entry->dwAddress == 0) {
  305. if (dwDefault == 0) {
  306. dbgprintf("IPRIP is configured to discard default routes, "
  307. "ignoring route to %s with next hop of %s",
  308. szAddress, szSrcaddr);
  309. RipLogInformation(RIPLOG_DEFAULT_INVALID, 2, ppszArgs, 0);
  310. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  311. return 0;
  312. }
  313. }
  314. rip_metric = ntohl(rip_entry->dwMetric);
  315. // do not add a new entry if its metric would be infinite
  316. if ((rip_metric + 1) >= METRIC_INFINITE &&
  317. !RouteTableEntryExists(lpaddr->dwIndex, rip_entry->dwAddress)) {
  318. dbgprintf("metric == %d, ignoring new route to %s with next hop of %s",
  319. METRIC_INFINITE, szAddress, szSrcaddr);
  320. return 0;
  321. }
  322. // find the entry, or create one if necessary
  323. rt_entry = GetRouteTableEntry(lpaddr->dwIndex, rip_entry->dwAddress,
  324. dwNetmask);
  325. if (rt_entry == NULL) {
  326. dbgprintf("could not allocate memory for new entry");
  327. RipLogError(RIPLOG_RT_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY);
  328. return ERROR_NOT_ENOUGH_MEMORY;
  329. }
  330. // if this was a static route and RIP is not allowed
  331. // to overwrite static routes, return; exception is default routes,
  332. // which we overwrite if we are configured to accept default routes,
  333. // even if there is an existing static default route
  334. //
  335. if (rt_entry->dwFlag != NEW_ENTRY &&
  336. (rt_entry->dwProtocol == IRE_PROTO_LOCAL ||
  337. rt_entry->dwProtocol == IRE_PROTO_NETMGMT) &&
  338. rt_entry->dwDestaddr != 0) {
  339. if (dwOverwriteStatic == 0) {
  340. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  341. return 0;
  342. }
  343. }
  344. rt_metric = rt_entry->dwMetric;
  345. rip_metric = min(METRIC_INFINITE, rip_metric + 1);
  346. _ltoa(rip_metric, szMetric, 10);
  347. if (rt_entry->dwFlag == NEW_ENTRY) {
  348. dbgprintf("New route entry, destination == %s, "
  349. "next hop == %s, metric == %s",
  350. szAddress, szSrcaddr, szMetric);
  351. RipLogInformation(RIPLOG_NEW_LEARNT_ROUTE, 3, ppszArgs, 0);
  352. rt_entry->dwIndex = lpaddr->dwIndex;
  353. rt_entry->dwFlag = (TIMEOUT_TIMER | ROUTE_CHANGE);
  354. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  355. rt_entry->dwDestaddr = rip_entry->dwAddress;
  356. rt_entry->dwNexthop = srcaddr.s_addr;
  357. rt_entry->dwProtocol = IRE_PROTO_RIP;
  358. rt_entry->dwMetric = rip_metric;
  359. if (bIsHostAddr) {
  360. rt_entry->dwFlag |= ROUTE_HOST;
  361. rt_entry->dwNetmask = HOSTADDR_MASK;
  362. }
  363. else {
  364. rt_entry->dwNetmask = dwNetmask;
  365. }
  366. }
  367. else
  368. if (rt_entry->dwNexthop == srcaddr.s_addr) {
  369. // this is from the next hop gateway for the existing entry
  370. // this may have been a local route before; now it is a RIP route
  371. rt_entry->dwProtocol = IRE_PROTO_RIP;
  372. rt_entry->dwIndex = lpaddr->dwIndex;
  373. // reset its timer if it is not pending garbage-collection
  374. if (rt_metric != METRIC_INFINITE &&
  375. (rt_entry->dwFlag & GARBAGE_TIMER) == 0) {
  376. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  377. }
  378. // if the metric changed, or the metric has gone to METRIC_INFINITE,
  379. // update the route
  380. if (rt_metric != rip_metric ||
  381. (rt_metric == METRIC_INFINITE &&
  382. (rt_entry->dwFlag & GARBAGE_TIMER) == 0)) {
  383. dbgprintf("Metric change, destination == %s, "
  384. "next hop == %s, metric == %s",
  385. szAddress, szSrcaddr, szMetric);
  386. RipLogInformation(RIPLOG_METRIC_CHANGE, 3, ppszArgs, 0);
  387. // is the route going away?
  388. if (rip_metric == METRIC_INFINITE &&
  389. (rt_entry->dwFlag & GARBAGE_TIMER) == 0) {
  390. dbgprintf("METRIC IS UNREACHABLE");
  391. // we do not know about it
  392. rt_entry->dwFlag &= ~TIMEOUT_TIMER;
  393. rt_entry->dwFlag |= (GARBAGE_TIMER | ROUTE_CHANGE);
  394. if (bIsHostAddr) {
  395. rt_entry->dwFlag |= ROUTE_HOST;
  396. }
  397. rt_entry->lTimeout = (LONG)dwGarbageTimeout;
  398. rt_entry->dwMetric = METRIC_INFINITE;
  399. }
  400. else {
  401. // route isn't going away, metric just changed
  402. rt_entry->dwFlag &= ~GARBAGE_TIMER;
  403. rt_entry->dwFlag |= (TIMEOUT_TIMER | ROUTE_CHANGE);
  404. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  405. rt_entry->dwDestaddr = rip_entry->dwAddress;
  406. if (bIsHostAddr) {
  407. rt_entry->dwFlag |= ROUTE_HOST;
  408. rt_entry->dwNetmask = HOSTADDR_MASK;
  409. }
  410. else {
  411. rt_entry->dwNetmask = dwNetmask;
  412. }
  413. rt_entry->dwNexthop = srcaddr.s_addr;
  414. rt_entry->dwMetric = rip_metric;
  415. }
  416. }
  417. }
  418. else
  419. if (rip_metric < rt_metric) {
  420. // not from original next hop for this route,
  421. // but this is a better route
  422. dbgprintf("New preferred route, destination == %s, "
  423. "next hop == %s, metric == %s",
  424. szAddress, szSrcaddr, szMetric);
  425. RipLogInformation(RIPLOG_ROUTE_REPLACED, 3, ppszArgs, 0);
  426. // if this route is pending garbage-collection,
  427. // remove the old entry before accepting a new next hop
  428. if (rt_entry->dwProtocol == IRE_PROTO_RIP &&
  429. (rt_entry->dwFlag & GARBAGE_TIMER) != 0) {
  430. UpdateSystemRouteTable(rt_entry, FALSE);
  431. }
  432. // this may have been a local route before; now it is a RIP route
  433. rt_entry->dwProtocol = IRE_PROTO_RIP;
  434. rt_entry->dwFlag &= ~GARBAGE_TIMER;
  435. rt_entry->dwFlag |= (TIMEOUT_TIMER | ROUTE_CHANGE);
  436. rt_entry->dwIndex = lpaddr->dwIndex;
  437. rt_entry->lTimeout = (LONG)dwRouteTimeout;
  438. rt_entry->dwDestaddr = rip_entry->dwAddress;
  439. if (bIsHostAddr) {
  440. rt_entry->dwFlag |= ROUTE_HOST;
  441. rt_entry->dwNetmask = HOSTADDR_MASK;
  442. }
  443. else {
  444. rt_entry->dwNetmask = dwNetmask;
  445. }
  446. rt_entry->dwNexthop = srcaddr.s_addr;
  447. rt_entry->dwMetric = rip_metric;
  448. }
  449. // we always update the route in the system table
  450. rt_entry->dwFlag |= ROUTE_UPDATE;
  451. InterlockedExchange(&g_ripcfg.dwRouteChanged, 1);
  452. #if 0
  453. DbgPrintf(
  454. "RIP entry : Protocol %x, Index %x, dest addr %x, dest mask %x\n",
  455. rt_entry->dwProtocol, rt_entry->dwIndex, rt_entry->dwDestaddr, rt_entry->dwNetmask
  456. );
  457. DbgPrintf(
  458. "Next Hop %x, Metric %x\n\n", rt_entry->dwNexthop, rt_entry->dwMetric
  459. );
  460. #endif
  461. return 0;
  462. }
  463. //-----------------------------------------------------------------------
  464. // Function: ProcessRIPQuery
  465. //
  466. // fills in a RIP packet entry with information from our routing table,
  467. // if we have a matching entry in our table.
  468. //-----------------------------------------------------------------------
  469. DWORD ProcessRIPQuery(LPRIP_ADDRESS lpaddr, LPRIP_ENTRY rip_entry) {
  470. LPHASH_TABLE_ENTRY rt_entry;
  471. #ifdef ROUTE_FILTERS
  472. DWORD dwInd = 0;
  473. //
  474. // run the route thru' the announce filters
  475. //
  476. if ( g_prfAnnounceFilters != NULL )
  477. {
  478. for ( dwInd = 0; dwInd < g_prfAnnounceFilters-> dwCount; dwInd++ )
  479. {
  480. if ( g_prfAnnounceFilters-> pdwFilter[ dwInd ] ==
  481. rip_entry-> dwAddress )
  482. {
  483. dbgprintf(
  484. "setting metric for route %s to infinite in RIP query",
  485. inet_ntoa(
  486. *( (struct in_addr*) &(rip_entry-> dwAddress ) )
  487. )
  488. );
  489. rip_entry-> dwMetric = htonl(METRIC_INFINITE);
  490. return 0;
  491. }
  492. }
  493. }
  494. #endif
  495. // RFC 1058 page 25
  496. // If routing table entry exists then pick up the metric.
  497. // Otherwise return a metric of METRIC_INFINITE.
  498. if (RouteTableEntryExists(lpaddr->dwIndex, rip_entry->dwAddress) &&
  499. (rt_entry = GetRouteTableEntry(lpaddr->dwIndex,
  500. rip_entry->dwAddress,
  501. rip_entry->dwSubnetmask)) != NULL) {
  502. rip_entry->dwMetric = htonl(rt_entry->dwMetric);
  503. }
  504. else {
  505. rip_entry->dwMetric = htonl(METRIC_INFINITE);
  506. }
  507. return 0;
  508. }
  509. //-----------------------------------------------------------------------
  510. // Function: ServiceMain
  511. //
  512. // This is the entry point of the service, and the function which
  513. // handles all network input processing.
  514. //-----------------------------------------------------------------------
  515. VOID FAR PASCAL ServiceMain(IN DWORD dwNumServicesArgs,
  516. IN LPSTR *lpServiceArgVectors) {
  517. HANDLE hThread;
  518. WSADATA wsaData;
  519. HANDLE DoneEvents[2];
  520. DWORD dwErr, dwOption, dwThread;
  521. SERVICE_STATUS status = {SERVICE_WIN32, SERVICE_STOPPED,
  522. SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0};
  523. #ifndef CHICAGO
  524. CHAR achModule[MAX_PATH];
  525. #else
  526. time_t tLastReload, tCurrTime;
  527. struct timeval tvReloadIntr;
  528. tvReloadIntr.tv_sec = IP_ADDRESS_RELOAD_INTR;
  529. tvReloadIntr.tv_usec = 0;
  530. time( &tLastReload );
  531. time( &tCurrTime );
  532. #endif
  533. // register with tracing DLL so errors can be reported below.
  534. g_dwTraceID = TraceRegister(RIP_SERVICE);
  535. if (g_dwTraceID == INVALID_TRACEID)
  536. {
  537. g_params.dwLoggingLevel = LOGLEVEL_ERROR;
  538. RipLogError(RIPLOG_SERVICE_INIT_FAILED, 0, NULL, GetLastError());
  539. return;
  540. }
  541. #ifndef CHICAGO
  542. // register the service and get a service status handle
  543. g_hService = RegisterServiceCtrlHandler(RIP_SERVICE,
  544. serviceHandlerFunction);
  545. if (g_hService == 0) {
  546. dbgprintf("IPRIP could not register as a service, error code %d",
  547. GetLastError());
  548. RipLogError(RIPLOG_REGISTER_FAILED, 0, NULL, GetLastError());
  549. return;
  550. }
  551. #endif
  552. dbgprintf("IPRIP is starting up...");
  553. // Prepare a status structure to pass to the service controller
  554. InterlockedExchange(&g_dwWaitHint, 60000);
  555. InterlockedExchange(&g_dwCheckPoint, 100);
  556. InterlockedExchange(&g_dwCurrentState, SERVICE_START_PENDING);
  557. status.dwControlsAccepted = 0;
  558. status.dwWaitHint = g_dwWaitHint;
  559. status.dwWin32ExitCode = NO_ERROR;
  560. status.dwCheckPoint = g_dwCheckPoint;
  561. status.dwServiceSpecificExitCode = 0;
  562. status.dwServiceType = SERVICE_WIN32;
  563. status.dwCurrentState = g_dwCurrentState;
  564. #ifndef CHICAGO
  565. if (!SetServiceStatus(g_hService, &status)) {
  566. dbgprintf("IPRIP could not report its status, error code %d",
  567. GetLastError());
  568. RipLogError(RIPLOG_SETSTATUS_FAILED, 0, NULL, GetLastError());
  569. return;
  570. }
  571. #endif
  572. RIP_CREATE_PARAMS_LOCK();
  573. RIP_CREATE_ADDRTABLE_LOCK();
  574. RIP_CREATE_ROUTETABLE_LOCK();
  575. #ifdef ROUTE_FILTERS
  576. RIP_CREATE_ANNOUNCE_FILTERS_LOCK();
  577. RIP_CREATE_ACCEPT_FILTERS_LOCK();
  578. #endif
  579. // first of all, start Winsock
  580. if (WSAStartup(MAKEWORD(1, 1), &wsaData)) {
  581. dbgprintf("error %d initializing Windows Sockets.", WSAGetLastError());
  582. RipLogError(RIPLOG_WSOCKINIT_FAILED, 0, NULL, WSAGetLastError());
  583. RIPServiceStop(); return;
  584. }
  585. // load operating parameters from the registry
  586. dwErr = LoadParameters();
  587. if (dwErr != 0) {
  588. dbgprintf("could not load registry parameters, error code %d", dwErr);
  589. RipLogError(RIPLOG_REGINIT_FAILED, 0, NULL, dwErr);
  590. RIPServiceStop(); return;
  591. }
  592. dwErr = InitializeRouteTable();
  593. if (dwErr != 0) {
  594. dbgprintf("could not initialize routing table, error code %d", dwErr);
  595. RipLogError(RIPLOG_RTAB_INIT_FAILED, 0, NULL, dwErr);
  596. RIPServiceStop(); return;
  597. }
  598. dwErr = InitializeStatsTable();
  599. if (dwErr != 0) {
  600. dbgprintf("could not initialize statistics, error code %d", dwErr);
  601. RipLogError(RIPLOG_STAT_INIT_FAILED, 0, NULL, dwErr);
  602. RIPServiceStop(); return;
  603. }
  604. // no other threads running, so no need for synchronization
  605. dwErr = InitializeAddressTable(TRUE);
  606. if (dwErr != 0) {
  607. dbgprintf("could not initialize sockets, error code %d", dwErr);
  608. RipLogError(RIPLOG_IFINIT_FAILED, 0, NULL, dwErr);
  609. RIPServiceStop(); return;
  610. }
  611. // load the IP local routes table
  612. // create socket which will be closed to interrupt select
  613. g_stopSocket = socket(AF_INET, SOCK_DGRAM, 0);
  614. // Create service stop event
  615. g_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  616. // Create triggered update request event
  617. g_triggerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  618. // create events on which we wait for the other threads
  619. DoneEvents[0] =
  620. g_updateDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  621. DoneEvents[1] =
  622. g_changeNotifyDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  623. #ifndef CHICAGO
  624. // In order to avoid having the DLL unloaded from underneath our threads,
  625. // we increment the DLL refcount as each thread is created.
  626. //
  627. // retrieve the module-name for this DLL.
  628. GetModuleFileName(g_hmodule, achModule, MAX_PATH);
  629. #endif
  630. // Create the thread which handles timed operations
  631. hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)UpdateThread,
  632. NULL, 0, &dwThread);
  633. if (hThread == NULL) {
  634. dbgprintf("could not create route update thread, error code %lu",
  635. GetLastError());
  636. RipLogError(RIPLOG_CREATETHREAD_FAILED, 0, NULL, GetLastError());
  637. closesocket(g_stopSocket);
  638. RIPServiceStop(); return;
  639. }
  640. CloseHandle(hThread);
  641. #ifndef CHICAGO
  642. // Increment the DLL refcount for the above thread
  643. LoadLibrary(achModule);
  644. #endif
  645. // Create the thread which waits for address changes
  646. hThread =
  647. CreateThread(NULL, 0,
  648. (LPTHREAD_START_ROUTINE)AddressChangeNotificationThread,
  649. (LPVOID)NULL, 0, &dwThread);
  650. if (hThread == NULL ) {
  651. dbgprintf("could not create address change notification thread, "
  652. "error code = %lu", GetLastError());
  653. RipLogError(RIPLOG_CREATETHREAD_FAILED, 0, NULL, GetLastError());
  654. SetEvent(g_stopEvent);
  655. WaitForSingleObject(g_updateDoneEvent, INFINITE);
  656. closesocket(g_stopSocket);
  657. RIPServiceStop(); return;
  658. }
  659. CloseHandle (hThread);
  660. #ifndef CHICAGO
  661. // Increment the DLL refcount for the above thread
  662. LoadLibrary(achModule);
  663. #endif
  664. // broadcast the initial requests for full routing information
  665. // from all the neighboring routers
  666. BroadcastRouteTableRequests();
  667. // Everything initialized fine:
  668. // Prepare a status structure to pass to the service controller
  669. InterlockedExchange(&g_dwWaitHint, 0);
  670. InterlockedExchange(&g_dwCheckPoint, 0);
  671. InterlockedExchange(&g_dwCurrentState, SERVICE_RUNNING);
  672. status.dwWaitHint = g_dwWaitHint;
  673. status.dwCheckPoint = g_dwCheckPoint;
  674. status.dwCurrentState = g_dwCurrentState;
  675. status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
  676. #ifndef CHICAGO
  677. SetServiceStatus(g_hService, &status);
  678. #endif
  679. RipLogInformation(RIPLOG_SERVICE_STARTED, 0, NULL, 0);
  680. // enter the main input processing loop
  681. while (TRUE) {
  682. INT length, size;
  683. IN_ADDR addr;
  684. DWORD dwSilentRIP;
  685. SOCKADDR_IN srcaddr;
  686. INT numReady;
  687. fd_set readfds;
  688. BOOL bLocalAddr;
  689. BOOL bPacketValid;
  690. BYTE buffer[RIP_MESSAGE_SIZE];
  691. LPRIP_HEADER lpheader;
  692. LPRIP_ADDRESS lpaddr, lpend;
  693. DWORD dwResult, dwUpdateFreq, dwTrigger;
  694. FD_ZERO(&readfds);
  695. RIP_LOCK_ADDRTABLE();
  696. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  697. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  698. if (lpaddr->sock != INVALID_SOCKET) {
  699. FD_SET(lpaddr->sock, &readfds);
  700. }
  701. }
  702. RIP_UNLOCK_ADDRTABLE();
  703. FD_SET(g_stopSocket, &readfds);
  704. // this is where we wait for something to come down the wire
  705. #ifndef CHICAGO
  706. numReady = select(0, &readfds, NULL, NULL, NULL);
  707. #else
  708. //
  709. // hack for Win95 since there is no mechanism to wait
  710. // for DHCP address change notification.
  711. // set an interval after which the IP addresses will
  712. // be reloaded by the IPRIP.
  713. //
  714. time( &tCurrTime );
  715. if ( ( tCurrTime - tLastReload ) > IP_ADDRESS_RELOAD_INTR )
  716. {
  717. numReady = 0;
  718. }
  719. else
  720. {
  721. numReady = select( 0, &readfds, NULL, NULL,
  722. (struct timeval FAR *) &tvReloadIntr);
  723. }
  724. #endif
  725. if (
  726. (numReady == SOCKET_ERROR &&
  727. WSAGetLastError() == WSAENOTSOCK)
  728. #ifdef CHICAGO
  729. || ( numReady == 0 )
  730. #endif
  731. ) {
  732. // socket g_stopSocket was closed, find out why
  733. if (g_stopReason == STOP_REASON_QUIT) {
  734. dbgprintf("service received stop request, shutting down");
  735. SetEvent(g_stopEvent);
  736. WaitForMultipleObjects(2, DoneEvents, TRUE, INFINITE);
  737. RIPServiceStop(); return;
  738. }
  739. else
  740. if (
  741. (g_stopReason == STOP_REASON_ADDRCHANGE)
  742. #ifdef CHICAGO
  743. || ( numReady == 0 )
  744. #endif
  745. ) {
  746. dbgprintf("service detected IP address change, reconfiguring");
  747. RipLogInformation(RIPLOG_ADDRESS_CHANGE, 0, NULL, 0);
  748. RIP_LOCK_ADDRTABLE();
  749. dwErr = InitializeAddressTable(FALSE);
  750. RIP_UNLOCK_ADDRTABLE();
  751. if (dwErr != 0 ||
  752. (dwErr = BroadcastRouteTableRequests()) != 0) {
  753. // re-init failed, log error and quit
  754. RipLogError(RIPLOG_REINIT_FAILED, 0, NULL, dwErr);
  755. SetEvent(g_stopEvent);
  756. WaitForMultipleObjects(2, DoneEvents, TRUE, INFINITE);
  757. RIPServiceStop(); return;
  758. }
  759. #ifndef CHICAGO
  760. // create socket which will be closed to interrupt select
  761. g_stopSocket = socket(AF_INET, SOCK_DGRAM, 0);
  762. #else
  763. time( &tLastReload );
  764. #endif
  765. continue;
  766. }
  767. }
  768. // neither stop request nor reconfig request, so some data
  769. // must have arrived. lock address table and go through
  770. // the sockets to see which ones are ready for reading
  771. RIP_LOCK_ADDRTABLE();
  772. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  773. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  774. if (lpaddr->sock != INVALID_SOCKET &&
  775. FD_ISSET(lpaddr->sock, &readfds)) {
  776. // read the incoming message
  777. size = sizeof(srcaddr);
  778. length = recvfrom(lpaddr->sock, buffer, RIP_MESSAGE_SIZE, 0,
  779. (SOCKADDR *)&srcaddr, &size);
  780. if (length == 0 || length == SOCKET_ERROR) {
  781. addr.s_addr = lpaddr->dwAddress;
  782. dbgprintf("error receiving data on local address %s, "
  783. "error code %d", inet_ntoa(addr),
  784. WSAGetLastError());
  785. InterlockedIncrement(&lpaddr->lpstats->dwReceiveFailures);
  786. if (WSAGetLastError() == WSAEMSGSIZE) {
  787. RipLogInformation(RIPLOG_RECVSIZE_TOO_GREAT, 0, NULL, 0);
  788. }
  789. else {
  790. RipLogInformation(RIPLOG_RECVFROM_FAILED, 0,
  791. NULL, WSAGetLastError());
  792. }
  793. continue;
  794. }
  795. #if 0
  796. DbgPrintf( "\n\n\nData received from %s on socket %d\n", inet_ntoa( srcaddr.sin_addr ), lpaddr-> sock );
  797. DbgPrintf( "socket bound to %s\n\n", inet_ntoa( *( (struct in_addr *) &(lpaddr-> dwAddress) ) ) );
  798. #endif
  799. // data received, so place a template over it
  800. lpheader = (LPRIP_HEADER)buffer;
  801. // validate the packet
  802. if (lpheader->chVersion == 0) {
  803. dbgprintf("version in RIP header is 0, "
  804. "discarding packet");
  805. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  806. RipLogInformation(RIPLOG_VERSION_ZERO, 0, NULL, 0);
  807. continue;
  808. }
  809. else
  810. if (lpheader->chVersion == 1 && lpheader->wReserved != 0) {
  811. dbgprintf("reserved field in RIPv1 header is non-zero, "
  812. "discarding packet");
  813. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  814. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  815. continue;
  816. }
  817. else
  818. if (lpheader->chVersion == 2 && lpheader->wReserved != 0) {
  819. dbgprintf("reserved field in RIPv2 header is non-zero, "
  820. "discarding packet");
  821. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  822. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  823. continue;
  824. }
  825. if (lpheader->chCommand == RIP_REQUEST) {
  826. ProcessRIPRequest(lpaddr, &srcaddr, buffer, length);
  827. }
  828. else
  829. if (lpheader->chCommand == RIP_RESPONSE) {
  830. ProcessRIPResponse(lpaddr, &srcaddr, buffer, length);
  831. // tell the update thread to process the changes just made
  832. // to the table;
  833. // this could include adding routes to the IP table
  834. // and/or sending out triggered updates
  835. if (g_ripcfg.dwRouteChanged != 0) {
  836. SetEvent(g_triggerEvent);
  837. }
  838. }
  839. }
  840. }
  841. RIP_UNLOCK_ADDRTABLE();
  842. }
  843. }
  844. //-----------------------------------------------------------------------
  845. // Function: ProcessRIPRequest
  846. //
  847. // Handles processing of requests. Validates packets, and sends
  848. // responses.
  849. //-----------------------------------------------------------------------
  850. VOID ProcessRIPRequest(LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpsrcaddr,
  851. BYTE buffer[], int length) {
  852. INT iErr;
  853. IN_ADDR addr;
  854. BYTE chVersion;
  855. BOOL bValidated;
  856. DWORD dwSilentRIP;
  857. CHAR szAddress[32];
  858. LPRIP_HEADER lpheader;
  859. LPRIP_ENTRY lpentry, lpbufend;
  860. CHAR *pszTemp;
  861. RIP_LOCK_PARAMS();
  862. dwSilentRIP = g_params.dwSilentRIP;
  863. RIP_UNLOCK_PARAMS();
  864. // if this is a regular request and RIP is silent, do nothing
  865. if (dwSilentRIP != 0) { // && lpsrcaddr->sin_port == htons(RIP_PORT)) {
  866. return;
  867. }
  868. // ignore requests from our own interfaces
  869. if (IsLocalAddr(lpsrcaddr->sin_addr.s_addr)) {
  870. return;
  871. }
  872. InterlockedIncrement(&lpaddr->lpstats->dwRequestsReceived);
  873. // place a template over the first entry
  874. lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  875. lpbufend = (LPRIP_ENTRY)(buffer + length);
  876. lpheader = (LPRIP_HEADER)buffer;
  877. chVersion = lpheader->chVersion;
  878. // print a message
  879. addr.s_addr = lpaddr->dwAddress;
  880. pszTemp = inet_ntoa(addr);
  881. if (pszTemp != NULL) {
  882. strcpy(szAddress, pszTemp);
  883. }
  884. dbgprintf("received RIP v%d request from %s on address %s",
  885. chVersion, inet_ntoa(lpsrcaddr->sin_addr), szAddress);
  886. // if this is a request for the entire routing table, send it
  887. if (length == (sizeof(RIP_HEADER) + sizeof(RIP_ENTRY)) &&
  888. lpentry->wAddrFamily == 0 &&
  889. lpentry->dwMetric == htonl(METRIC_INFINITE)) {
  890. // transmit the entire routing table, subject
  891. // to split-horizon and poisoned reverse processing
  892. TransmitRouteTableContents(lpaddr, lpsrcaddr, FALSE);
  893. return;
  894. }
  895. #ifdef ROUTE_FILTERS
  896. RIP_LOCK_ANNOUNCE_FILTERS();
  897. #endif
  898. // this is a request for specific entries,
  899. // validate the entries first
  900. bValidated = TRUE;
  901. for ( ; (lpentry + 1) <= lpbufend; lpentry++) {
  902. // validate the entry first
  903. if (chVersion == 1 && (lpentry->wReserved != 0 ||
  904. lpentry->dwReserved1 != 0 ||
  905. lpentry->dwReserved2 != 0)) {
  906. bValidated = FALSE;
  907. break;
  908. }
  909. // now process it
  910. ProcessRIPQuery(lpaddr, lpentry);
  911. }
  912. #ifdef ROUTE_FILTERS
  913. RIP_UNLOCK_ANNOUNCE_FILTERS();
  914. #endif
  915. // if packet was validated and fields filled in, send it back
  916. if (bValidated) {
  917. // update the command field
  918. lpheader->chCommand = RIP_RESPONSE;
  919. iErr = sendto(lpaddr->sock, buffer, length, 0,
  920. (LPSOCKADDR)lpsrcaddr, sizeof(SOCKADDR_IN));
  921. if (iErr == SOCKET_ERROR) {
  922. dbgprintf("error sending response to %s from local interface %s",
  923. inet_ntoa(lpsrcaddr->sin_addr), szAddress);
  924. InterlockedIncrement(&lpaddr->lpstats->dwSendFailures);
  925. RipLogInformation(RIPLOG_SENDTO_FAILED, 0, NULL, WSAGetLastError());
  926. }
  927. else {
  928. InterlockedIncrement(&lpaddr->lpstats->dwResponsesSent);
  929. }
  930. }
  931. }
  932. //-----------------------------------------------------------------------
  933. // Function: ProcessRIPResponse
  934. //
  935. // Handles processing of response packets. Validates packets,
  936. // and updates the tables if necessary.
  937. //-----------------------------------------------------------------------
  938. VOID ProcessRIPResponse(LPRIP_ADDRESS lpaddr, LPSOCKADDR_IN lpsrcaddr,
  939. BYTE buffer[], int length) {
  940. IN_ADDR addr;
  941. BYTE chVersion;
  942. CHAR szAddress[32];
  943. LPRIP_HEADER lpheader;
  944. LPRIP_ENTRY lpentry, lpbufend;
  945. LPRIP_AUTHENT_ENTRY lpaentry;
  946. CHAR *pszTemp;
  947. // ignore responses from ports other than 520
  948. if (lpsrcaddr->sin_port != htons(RIP_PORT)) {
  949. dbgprintf("response is from invalid port (%d), discarding");
  950. InterlockedIncrement(&lpaddr->lpstats->dwBadPacketsReceived);
  951. RipLogWarning(RIPLOG_INVALIDPORT, 0, NULL, 0);
  952. return;
  953. }
  954. // ignore responses from our own interfaces
  955. if (IsLocalAddr(lpsrcaddr->sin_addr.s_addr)) {
  956. return;
  957. }
  958. InterlockedIncrement(&lpaddr->lpstats->dwResponsesReceived);
  959. // place templates over the buffer
  960. lpentry = (LPRIP_ENTRY)(buffer + sizeof(RIP_HEADER));
  961. lpbufend = (LPRIP_ENTRY)(buffer + length);
  962. lpheader = (LPRIP_HEADER)buffer;
  963. chVersion = lpheader->chVersion;
  964. lpaentry = (LPRIP_AUTHENT_ENTRY) lpentry;
  965. // seems OK, print a message
  966. addr.s_addr = lpaddr->dwAddress;
  967. pszTemp = inet_ntoa(addr);
  968. if (pszTemp != NULL) {
  969. strcpy(szAddress, pszTemp);
  970. }
  971. dbgprintf("received RIP v%d response from %s on address %s",
  972. chVersion, inet_ntoa(lpsrcaddr->sin_addr), szAddress);
  973. #ifdef ROUTE_FILTERS
  974. RIP_LOCK_ACCEPT_FILTERS();
  975. #endif
  976. //
  977. // take care of RIPv2 auth entry
  978. // - ignoring auth entry till we decide on a way to allow this
  979. // to be configurable
  980. //
  981. if (chVersion == 2) {
  982. // if its an auth entry, ignore and continue
  983. if (ntohs(lpaentry->wAddrFamily) == ADDRFAMILY_AUTHENT) {
  984. lpentry++;
  985. }
  986. }
  987. //
  988. // validate each entry, then process it
  989. //
  990. for ( ; (lpentry + 1) <= lpbufend; lpentry++) {
  991. //
  992. // for non RIPv2 reserved fields must be checked
  993. //
  994. if (chVersion == 1) {
  995. //
  996. // check route entry fields
  997. //
  998. if (ntohs(lpentry->wAddrFamily) != AF_INET ||
  999. lpentry->wReserved != 0 ||
  1000. lpentry->dwReserved1 != 0 ||
  1001. lpentry->dwReserved2 != 0) {
  1002. //
  1003. // update stats on ignored entries
  1004. //
  1005. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  1006. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  1007. continue;
  1008. }
  1009. // entry looks OK, so process it
  1010. ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
  1011. }
  1012. else
  1013. if (chVersion == 2) {
  1014. //
  1015. // check route entry fields
  1016. //
  1017. if (ntohs(lpentry->wAddrFamily) != AF_INET) {
  1018. //
  1019. // update stats on ignored entries
  1020. //
  1021. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  1022. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  1023. continue;
  1024. }
  1025. // entry looks OK, so process it
  1026. ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
  1027. }
  1028. else {
  1029. // following routing\ip\rip semantics
  1030. //
  1031. // this packet's version is greater than 2, so we ignore
  1032. // the contents of the reserved fields
  1033. //
  1034. //
  1035. // check route entry fields
  1036. //
  1037. if (ntohs(lpentry->wAddrFamily) != AF_INET) {
  1038. //
  1039. // update stats on ignored entries
  1040. //
  1041. InterlockedIncrement(&lpaddr->lpstats->dwBadRouteResponseEntries);
  1042. RipLogInformation(RIPLOG_FORMAT_ERROR, 0, NULL, 0);
  1043. continue;
  1044. }
  1045. //
  1046. // entry is alright, clear reserved fields and process
  1047. //
  1048. lpentry->wRoutetag = 0;
  1049. lpentry->dwSubnetmask = 0;
  1050. lpentry->dwNexthop = 0;
  1051. // entry looks OK, so process it
  1052. ProcessRIPEntry(lpaddr, lpsrcaddr->sin_addr, lpentry, chVersion);
  1053. }
  1054. }
  1055. #ifdef ROUTE_FILTERS
  1056. RIP_UNLOCK_ACCEPT_FILTERS();
  1057. #endif
  1058. }
  1059. //-----------------------------------------------------------------------
  1060. // Function: AddressChangeNotificationThread
  1061. //
  1062. // Used to wait on a DHCP triggered event that tells whenever there is
  1063. // a config change. At that point we go re-read the IP config information
  1064. // and build the interface table again.
  1065. //
  1066. // This thread also waits on the shutdown event to clean up route tables.
  1067. //-----------------------------------------------------------------------
  1068. DWORD AddressChangeNotificationThread(LPVOID param) {
  1069. DWORD dwErr;
  1070. HANDLE hEvents[2];
  1071. HANDLE hDHCPEvent;
  1072. #if (WINVER >= 0x500)
  1073. hDHCPEvent = DhcpOpenGlobalEvent();
  1074. #else
  1075. SECURITY_ATTRIBUTES saAttr;
  1076. SECURITY_DESCRIPTOR sdDesc;
  1077. //
  1078. // Try to create this event in case DHCP service or DHCP API
  1079. // has not created it; use the security attributes struct
  1080. // because DHCP will, and omitting this code will cause DHCP
  1081. // to fail to open the event if the interfaces are statically
  1082. // configured (in which case the DHCP client would not be running)
  1083. saAttr.nLength = sizeof(saAttr);
  1084. saAttr.bInheritHandle = FALSE;
  1085. InitializeSecurityDescriptor(&sdDesc, SECURITY_DESCRIPTOR_REVISION);
  1086. if (SetSecurityDescriptorDacl(&sdDesc, TRUE, NULL, FALSE)) {
  1087. saAttr.lpSecurityDescriptor = &sdDesc;
  1088. }
  1089. else {
  1090. saAttr.lpSecurityDescriptor = NULL;
  1091. }
  1092. hDHCPEvent = CreateEvent(&saAttr, TRUE, FALSE, DHCP_ADDR_CHANGE_EVENT);
  1093. #endif
  1094. // if we can't open this handle then we simple quit this thread
  1095. // this does mean that we will not be able to pick up
  1096. // any new changes to the config.
  1097. if (hDHCPEvent == NULL) {
  1098. dbgprintf("could not create address change notification event, "
  1099. "error code %d", GetLastError());
  1100. RipLogError(RIPLOG_CREATEEVENT_FAILED, 0, NULL, GetLastError());
  1101. SetEvent(g_changeNotifyDoneEvent);
  1102. #ifndef CHICAGO
  1103. FreeLibraryAndExitThread(g_hmodule, 0);
  1104. #endif
  1105. return 0;
  1106. }
  1107. hEvents[0] = hDHCPEvent;
  1108. hEvents[1] = g_stopEvent;
  1109. // loop waiting for an address to change or for the service to stop
  1110. for ( ; ; ) {
  1111. dwErr = WaitForMultipleObjects(2, (LPHANDLE)hEvents,
  1112. FALSE, INFINITE);
  1113. if (dwErr == WAIT_OBJECT_0) {
  1114. // IP config changed - re-read the config info
  1115. dbgprintf("IP address table changed, signalling input thread");
  1116. // set the reason for interruption
  1117. InterlockedExchange(&g_stopReason, STOP_REASON_ADDRCHANGE);
  1118. // close the socket to tell main thread it should stop
  1119. closesocket(g_stopSocket);
  1120. }
  1121. else
  1122. if (dwErr == WAIT_OBJECT_0 + 1) {
  1123. break;
  1124. }
  1125. }
  1126. dbgprintf("address change notification thread is stopping.");
  1127. CloseHandle(hDHCPEvent);
  1128. SetEvent(g_changeNotifyDoneEvent);
  1129. #ifndef CHICAGO
  1130. FreeLibraryAndExitThread(g_hmodule, 0);
  1131. #endif
  1132. return 0;
  1133. }
  1134. //-----------------------------------------------------------------------
  1135. // Function: serviceHandlerFunction()
  1136. //
  1137. // Handles all service controller requests.
  1138. //-----------------------------------------------------------------------
  1139. VOID serviceHandlerFunction(DWORD dwControl) {
  1140. SERVICE_STATUS status;
  1141. dbgprintf("Service received control request %d", dwControl);
  1142. switch (dwControl) {
  1143. case SERVICE_CONTROL_INTERROGATE:
  1144. case SERVICE_CONTROL_PAUSE:
  1145. case SERVICE_CONTROL_CONTINUE:
  1146. // increment checkpoint if necessary
  1147. if (g_dwCheckPoint != 0) {
  1148. InterlockedExchange(&g_dwCheckPoint, g_dwCheckPoint + 100);
  1149. }
  1150. status.dwWaitHint = g_dwWaitHint;
  1151. status.dwWin32ExitCode = NO_ERROR;
  1152. status.dwServiceType = SERVICE_WIN32;
  1153. status.dwServiceSpecificExitCode = 0;
  1154. status.dwCheckPoint = g_dwCheckPoint;
  1155. status.dwCurrentState = g_dwCurrentState;
  1156. status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  1157. SERVICE_ACCEPT_SHUTDOWN;
  1158. #ifndef CHICAGO
  1159. SetServiceStatus (g_hService, &status);
  1160. #endif
  1161. break;
  1162. case SERVICE_CONTROL_STOP:
  1163. case SERVICE_CONTROL_SHUTDOWN:
  1164. InterlockedExchange(&g_stopReason, STOP_REASON_QUIT);
  1165. closesocket(g_stopSocket);
  1166. SetEvent(g_stopEvent); // start cleanup
  1167. InterlockedExchange(&g_dwWaitHint, 120000);
  1168. InterlockedExchange(&g_dwCheckPoint, 100);
  1169. InterlockedExchange(&g_dwCurrentState, SERVICE_STOP_PENDING);
  1170. status.dwWaitHint = g_dwWaitHint;
  1171. status.dwWin32ExitCode = NO_ERROR;
  1172. status.dwCheckPoint = g_dwCheckPoint;
  1173. status.dwServiceType = SERVICE_WIN32;
  1174. status.dwServiceSpecificExitCode = 0;
  1175. status.dwCurrentState = g_dwCurrentState;
  1176. status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  1177. #ifndef CHICAGO
  1178. SetServiceStatus(g_hService, &status);
  1179. #endif
  1180. break;
  1181. }
  1182. }
  1183. //-----------------------------------------------------------------------
  1184. // Function: RIPServiceStop
  1185. //
  1186. // Handles freeing of resources, closing handles and sockets,
  1187. // and sending final status message to the service controller.
  1188. //-----------------------------------------------------------------------
  1189. void RIPServiceStop() {
  1190. LPRIP_ADDRESS lpaddr, lpend;
  1191. SERVICE_STATUS stopstatus = {SERVICE_WIN32, SERVICE_STOPPED, 0,
  1192. NO_ERROR, 0, 0, 0};
  1193. CleanupRouteTable();
  1194. CleanupStatsTable();
  1195. lpend = g_ripcfg.lpAddrTable + g_ripcfg.dwAddrCount;
  1196. for (lpaddr = g_ripcfg.lpAddrTable; lpaddr < lpend; lpaddr++) {
  1197. if (lpaddr->sock != INVALID_SOCKET) { closesocket(lpaddr->sock); }
  1198. }
  1199. WSACleanup();
  1200. if (g_triggerEvent != NULL) {
  1201. CloseHandle(g_triggerEvent); g_triggerEvent = NULL;
  1202. }
  1203. if (g_updateDoneEvent != NULL) {
  1204. CloseHandle(g_updateDoneEvent); g_updateDoneEvent = NULL;
  1205. }
  1206. if (g_changeNotifyDoneEvent != NULL) {
  1207. CloseHandle(g_changeNotifyDoneEvent); g_changeNotifyDoneEvent = NULL;
  1208. }
  1209. if (g_ripcfg.hTCPDriver != NULL) {
  1210. CloseHandle(g_ripcfg.hTCPDriver); g_ripcfg.hTCPDriver = NULL;
  1211. }
  1212. if (g_stopEvent != NULL) {
  1213. CloseHandle(g_stopEvent); g_stopEvent = NULL;
  1214. }
  1215. // need to log this before we destroy the locks
  1216. RipLogInformation(RIPLOG_SERVICE_STOPPED, 0, NULL, 0);
  1217. RIP_DESTROY_PARAMS_LOCK();
  1218. RIP_DESTROY_ADDRTABLE_LOCK();
  1219. RIP_DESTROY_ROUTETABLE_LOCK();
  1220. #ifdef ROUTE_FILTERS
  1221. RIP_DESTROY_ANNOUNCE_FILTERS_LOCK();
  1222. RIP_DESTROY_ACCEPT_FILTERS_LOCK();
  1223. #endif
  1224. dbgprintf("Main thread stopping.");
  1225. TraceDeregister(g_dwTraceID);
  1226. g_dwTraceID = (DWORD)-1;
  1227. #ifndef CHICAGO
  1228. SetServiceStatus(g_hService, &stopstatus);
  1229. #endif
  1230. }
  1231. #ifdef ROUTE_FILTERS
  1232. PRIP_FILTERS
  1233. LoadFilters(
  1234. IN HKEY hKeyParams,
  1235. IN LPSTR lpszKeyName
  1236. )
  1237. {
  1238. LPSTR pszFilter = NULL;
  1239. LPSTR pszIndex = NULL;
  1240. DWORD dwSize = 0, dwErr = NO_ERROR, dwType = 0, dwCount = 0, dwInd = 0;
  1241. PRIP_FILTERS prfFilter = NULL;
  1242. //
  1243. // route filters (added as a hotfix).
  1244. //
  1245. //
  1246. // Routes included in a RIP annoucement can be filtered.
  1247. //
  1248. // Route filters are configured by setting the value "AnnounceRouteFilters"
  1249. // or "AcceptRouteFilters"
  1250. // under the Parameters key. These are reg_multi_sz (or whatever it is
  1251. // formally called). Multiple filters can be set in each multistring.
  1252. // Each entry represents a network that will be filtered out when RIP
  1253. // announces/accepts routes.
  1254. //
  1255. do
  1256. {
  1257. dwSize = 0;
  1258. dwErr = RegQueryValueExA(
  1259. hKeyParams, lpszKeyName, NULL,
  1260. &dwType, (LPBYTE) NULL, &dwSize
  1261. );
  1262. if ( dwErr != ERROR_SUCCESS ||
  1263. dwType != REG_MULTI_SZ ||
  1264. dwSize <= 1 )
  1265. {
  1266. //
  1267. // either there is no key by this name or it is the
  1268. // wrong type. Nothing else to be done at this point
  1269. //
  1270. break;
  1271. }
  1272. //
  1273. // Appears to be a valid key with some data in it.
  1274. //
  1275. pszFilter = HeapAlloc(
  1276. GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize + 1
  1277. );
  1278. if ( pszFilter == NULL )
  1279. {
  1280. dbgprintf(
  1281. "Failed to allocate filter string : size = %d", dwSize
  1282. );
  1283. RipLogError(
  1284. RIPLOG_FILTER_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY
  1285. );
  1286. break;
  1287. }
  1288. //
  1289. // retrieve key contents
  1290. //
  1291. dwErr = RegQueryValueExA(
  1292. hKeyParams, lpszKeyName, NULL,
  1293. &dwType, (LPBYTE) pszFilter, &dwSize
  1294. );
  1295. if ( dwErr != NO_ERROR || dwType != REG_MULTI_SZ || dwSize <= 1 )
  1296. {
  1297. dbgprintf(
  1298. "Failed to retrieve %s filters : error = %d", lpszKeyName,
  1299. dwErr
  1300. );
  1301. break;
  1302. }
  1303. //
  1304. // Convert the filter multi string to ip addresses
  1305. //
  1306. //
  1307. // count the number of filters
  1308. //
  1309. pszIndex = pszFilter;
  1310. while ( *pszIndex != '\0' )
  1311. {
  1312. dwCount++;
  1313. pszIndex += strlen( pszIndex ) + 1;
  1314. }
  1315. if ( dwCount == 0 )
  1316. {
  1317. dbgprintf( "No filters found" );
  1318. break;
  1319. }
  1320. //
  1321. // allocate filter structure
  1322. //
  1323. prfFilter = HeapAlloc(
  1324. GetProcessHeap(), HEAP_ZERO_MEMORY,
  1325. sizeof( RIP_FILTERS ) + ( dwCount - 1) * sizeof(
  1326. DWORD )
  1327. );
  1328. if ( prfFilter == NULL )
  1329. {
  1330. dbgprintf(
  1331. "Failed to allocate filter table : size = %d", dwSize
  1332. );
  1333. RipLogError(
  1334. RIPLOG_FILTER_ALLOC_FAILED, 0, NULL, ERROR_NOT_ENOUGH_MEMORY
  1335. );
  1336. break;
  1337. }
  1338. //
  1339. // fill it up
  1340. //
  1341. prfFilter-> dwCount = dwCount;
  1342. pszIndex = pszFilter;
  1343. for ( dwInd = 0; dwInd < dwCount; dwInd++ )
  1344. {
  1345. prfFilter-> pdwFilter[ dwInd ] = inet_addr( pszIndex );
  1346. pszIndex += strlen( pszIndex ) + 1;
  1347. }
  1348. } while ( FALSE );
  1349. if ( pszFilter != NULL )
  1350. {
  1351. HeapFree( GetProcessHeap(), 0, pszFilter );
  1352. }
  1353. if ( prfFilter != NULL )
  1354. {
  1355. //
  1356. // Print the list of configured filters
  1357. //
  1358. dbgprintf( "Number of filters : %d", prfFilter-> dwCount );
  1359. for ( dwInd = 0; dwInd < prfFilter-> dwCount; dwInd++ )
  1360. {
  1361. dbgprintf(
  1362. "Filter #%d : %x (%s)", dwInd,
  1363. prfFilter-> pdwFilter[ dwInd ],
  1364. inet_ntoa( *( (struct in_addr*)
  1365. &(prfFilter-> pdwFilter[ dwInd ] ) ) )
  1366. );
  1367. }
  1368. }
  1369. return prfFilter;
  1370. }
  1371. #endif
  1372. //-----------------------------------------------------------------------
  1373. //
  1374. //--------------------------- WINNT Specific ----------------------------
  1375. //
  1376. //-----------------------------------------------------------------------
  1377. #ifndef CHICAGO
  1378. //-----------------------------------------------------------------------
  1379. // Function: DllMain
  1380. //
  1381. // DLL entry-point; saves the module handle for later use.
  1382. //-----------------------------------------------------------------------
  1383. BOOL APIENTRY
  1384. DllMain(
  1385. HMODULE hmodule,
  1386. DWORD dwReason,
  1387. VOID* pReserved
  1388. ) {
  1389. if (dwReason == DLL_PROCESS_ATTACH) { g_hmodule = hmodule; }
  1390. return TRUE;
  1391. }
  1392. //-----------------------------------------------------------------------
  1393. // Function: LoadParameters
  1394. //
  1395. // Reads various configuration flags from the registry.
  1396. //-----------------------------------------------------------------------
  1397. DWORD LoadParameters() {
  1398. DWORD valuesize;
  1399. DWORD dwErr, dwType, dwIndex, dwValue;
  1400. HKEY hkeyParams;
  1401. DWORD dwRouteTimeout, dwGarbageTimeout;
  1402. DWORD dwLoggingLevel, dwUpdateFrequency;
  1403. DWORD dwMaxTriggerFrequency, dwOverwriteStaticRoutes;
  1404. DWORD dwSize = MAX_PATH;
  1405. HKEY hkey = NULL;
  1406. WCHAR Buffer[MAX_PATH+1];
  1407. RegCloseKey( hkey );
  1408. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_RIP_PARAMS, &hkeyParams);
  1409. if (dwErr != ERROR_SUCCESS) {
  1410. return GetLastError();
  1411. }
  1412. #ifdef ROUTE_FILTERS
  1413. RIP_LOCK_ANNOUNCE_FILTERS();
  1414. if ( g_prfAnnounceFilters != NULL ) {
  1415. HeapFree( GetProcessHeap(), 0, g_prfAnnounceFilters );
  1416. }
  1417. g_prfAnnounceFilters = LoadFilters( hkeyParams, REGVAL_ANNOUCE_FILTERS );
  1418. RIP_UNLOCK_ANNOUNCE_FILTERS();
  1419. RIP_LOCK_ACCEPT_FILTERS();
  1420. if ( g_prfAcceptFilters != NULL ) {
  1421. HeapFree( GetProcessHeap(), 0, g_prfAcceptFilters );
  1422. }
  1423. g_prfAcceptFilters = LoadFilters( hkeyParams, REGVAL_ACCEPT_FILTERS );
  1424. RIP_UNLOCK_ACCEPT_FILTERS();
  1425. #endif
  1426. RIP_LOCK_PARAMS();
  1427. // always run in SilentRIP mode.
  1428. {
  1429. g_params.dwSilentRIP = 1;
  1430. }
  1431. // read the value for accepting host routes
  1432. valuesize = sizeof(DWORD);
  1433. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ACCEPT_HOST, NULL,
  1434. &dwType, (LPBYTE)&dwValue, &valuesize);
  1435. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1436. g_params.dwAcceptHost = dwValue;
  1437. }
  1438. else {
  1439. g_params.dwAcceptHost = DEF_ACCEPT_HOST;
  1440. }
  1441. // read the value for announcing host routes
  1442. valuesize = sizeof(DWORD);
  1443. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ANNOUNCE_HOST, NULL,
  1444. &dwType, (LPBYTE)&dwValue, &valuesize);
  1445. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1446. g_params.dwAnnounceHost = dwValue;
  1447. }
  1448. else {
  1449. g_params.dwAnnounceHost = DEF_ANNOUNCE_HOST;
  1450. }
  1451. // read the value for accepting default routes
  1452. valuesize = sizeof(DWORD);
  1453. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ACCEPT_DEFAULT, NULL,
  1454. &dwType, (LPBYTE)&dwValue, &valuesize);
  1455. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1456. g_params.dwAcceptDefault = dwValue;
  1457. }
  1458. else {
  1459. g_params.dwAcceptDefault = DEF_ACCEPT_DEFAULT;
  1460. }
  1461. // read the value for announcing default routes
  1462. valuesize = sizeof(DWORD);
  1463. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ANNOUNCE_DEFAULT, NULL,
  1464. &dwType, (LPBYTE)&dwValue, &valuesize);
  1465. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1466. g_params.dwAnnounceDefault = dwValue;
  1467. }
  1468. else {
  1469. g_params.dwAnnounceDefault = DEF_ANNOUNCE_DEFAULT;
  1470. }
  1471. // read value for split-horizon processing
  1472. valuesize = sizeof(DWORD);
  1473. dwErr = RegQueryValueEx(hkeyParams, REGVAL_SPLITHORIZON, NULL,
  1474. &dwType, (LPBYTE)&dwValue, &valuesize);
  1475. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1476. g_params.dwSplitHorizon = dwValue;
  1477. }
  1478. else {
  1479. g_params.dwSplitHorizon = DEF_SPLITHORIZON;
  1480. }
  1481. // read value for poisoned-reverse processing
  1482. valuesize = sizeof(DWORD);
  1483. dwErr = RegQueryValueEx(hkeyParams, REGVAL_POISONREVERSE, NULL,
  1484. &dwType, (LPBYTE)&dwValue, &valuesize);
  1485. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1486. g_params.dwPoisonReverse = dwValue;
  1487. }
  1488. else {
  1489. g_params.dwPoisonReverse = DEF_POISONREVERSE;
  1490. }
  1491. // read value for triggered update sending
  1492. valuesize = sizeof(DWORD);
  1493. dwErr = RegQueryValueEx(hkeyParams, REGVAL_TRIGGEREDUPDATES, NULL,
  1494. &dwType, (LPBYTE)&dwValue, &valuesize);
  1495. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1496. g_params.dwTriggeredUpdates = dwValue;
  1497. }
  1498. else {
  1499. g_params.dwTriggeredUpdates = DEF_TRIGGEREDUPDATES;
  1500. }
  1501. // read value for triggered update frequency
  1502. valuesize = sizeof(DWORD);
  1503. dwErr = RegQueryValueEx(hkeyParams, REGVAL_TRIGGERFREQUENCY, NULL,
  1504. &dwType, (LPBYTE)&dwValue, &valuesize);
  1505. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1506. dwMaxTriggerFrequency = dwValue * 1000;
  1507. }
  1508. else {
  1509. dwMaxTriggerFrequency = DEF_TRIGGERFREQUENCY;
  1510. }
  1511. // read value for route timeouts
  1512. valuesize = sizeof(DWORD);
  1513. dwErr = RegQueryValueEx(hkeyParams, REGVAL_ROUTETIMEOUT, NULL,
  1514. &dwType, (LPBYTE)&dwValue, &valuesize);
  1515. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1516. dwRouteTimeout = dwValue * 1000;
  1517. }
  1518. else {
  1519. dwRouteTimeout = DEF_ROUTETIMEOUT;
  1520. }
  1521. // read values for update frequency
  1522. valuesize = sizeof(DWORD);
  1523. dwErr = RegQueryValueEx(hkeyParams, REGVAL_UPDATEFREQUENCY, NULL,
  1524. &dwType, (LPBYTE)&dwValue, &valuesize);
  1525. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1526. dwUpdateFrequency = dwValue * 1000;
  1527. }
  1528. else {
  1529. dwUpdateFrequency = DEF_UPDATEFREQUENCY;
  1530. }
  1531. // read values for garbage timeouts
  1532. valuesize = sizeof(DWORD);
  1533. dwErr = RegQueryValueEx(hkeyParams, REGVAL_GARBAGETIMEOUT, NULL,
  1534. &dwType, (LPBYTE)&dwValue, &valuesize);
  1535. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1536. dwGarbageTimeout = dwValue * 1000;
  1537. }
  1538. else {
  1539. dwGarbageTimeout = DEF_GARBAGETIMEOUT;
  1540. }
  1541. // read values for logging level
  1542. valuesize = sizeof(DWORD);
  1543. dwErr = RegQueryValueEx(hkeyParams, REGVAL_OVERWRITESTATIC, NULL,
  1544. &dwType, (LPBYTE)&dwValue, &valuesize);
  1545. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1546. dwOverwriteStaticRoutes = dwValue;
  1547. }
  1548. else {
  1549. dwOverwriteStaticRoutes = DEF_OVERWRITESTATIC;
  1550. }
  1551. // read values for logging level
  1552. valuesize = sizeof(DWORD);
  1553. dwErr = RegQueryValueEx(hkeyParams, REGVAL_LOGGINGLEVEL, NULL,
  1554. &dwType, (LPBYTE)&dwValue, &valuesize);
  1555. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1556. dwLoggingLevel = dwValue;
  1557. }
  1558. else {
  1559. dwLoggingLevel = DEF_LOGGINGLEVEL;
  1560. }
  1561. // read value for MaxTimedOpsInterval
  1562. valuesize = sizeof(DWORD);
  1563. dwErr = RegQueryValueEx(hkeyParams, REGVAL_MAXTIMEDOPSINTERVAL, NULL,
  1564. &dwType, (LPBYTE)&dwValue, &valuesize);
  1565. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue) {
  1566. g_params.dwMaxTimedOpsInterval = dwValue * 1000;
  1567. }
  1568. else {
  1569. g_params.dwMaxTimedOpsInterval = DEF_MAXTIMEDOPSINTERVAL;
  1570. }
  1571. RegCloseKey(hkeyParams);
  1572. // adjust values if out of acceptable range
  1573. if (dwRouteTimeout > MAX_ROUTETIMEOUT) {
  1574. dwRouteTimeout = MAX_ROUTETIMEOUT;
  1575. }
  1576. else
  1577. if (dwRouteTimeout < MIN_ROUTETIMEOUT) {
  1578. dwRouteTimeout = MIN_ROUTETIMEOUT;
  1579. }
  1580. if (dwGarbageTimeout > MAX_GARBAGETIMEOUT) {
  1581. dwGarbageTimeout = MAX_GARBAGETIMEOUT;
  1582. }
  1583. else
  1584. if (dwGarbageTimeout < MIN_GARBAGETIMEOUT) {
  1585. dwGarbageTimeout = MIN_GARBAGETIMEOUT;
  1586. }
  1587. if (dwUpdateFrequency > MAX_UPDATEFREQUENCY) {
  1588. dwUpdateFrequency = MAX_UPDATEFREQUENCY;
  1589. }
  1590. else
  1591. if (dwUpdateFrequency < MIN_UPDATEFREQUENCY) {
  1592. dwUpdateFrequency = MIN_UPDATEFREQUENCY;
  1593. }
  1594. if (dwMaxTriggerFrequency > MAX_TRIGGERFREQUENCY) {
  1595. dwMaxTriggerFrequency = MAX_TRIGGERFREQUENCY;
  1596. }
  1597. else
  1598. if (dwMaxTriggerFrequency < MIN_TRIGGERFREQUENCY) {
  1599. dwMaxTriggerFrequency = MIN_TRIGGERFREQUENCY;
  1600. }
  1601. g_params.dwRouteTimeout = dwRouteTimeout;
  1602. g_params.dwGarbageTimeout = dwGarbageTimeout;
  1603. g_params.dwUpdateFrequency = dwUpdateFrequency;
  1604. g_params.dwMaxTriggerFrequency = dwMaxTriggerFrequency;
  1605. g_params.dwLoggingLevel = dwLoggingLevel;
  1606. g_params.dwOverwriteStaticRoutes = dwOverwriteStaticRoutes;
  1607. dbgprintf("%s == %d", REGVAL_LOGGINGLEVEL, dwLoggingLevel);
  1608. dbgprintf("%s == %d", REGVAL_ROUTETIMEOUT, dwRouteTimeout / 1000);
  1609. dbgprintf("%s == %d", REGVAL_GARBAGETIMEOUT, dwGarbageTimeout / 1000);
  1610. dbgprintf("%s == %d", REGVAL_UPDATEFREQUENCY, dwUpdateFrequency / 1000);
  1611. dbgprintf("%s == %d", REGVAL_ACCEPT_HOST, g_params.dwAcceptHost);
  1612. dbgprintf("%s == %d", REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost);
  1613. dbgprintf("%s == %d", REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault);
  1614. dbgprintf("%s == %d", REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault);
  1615. dbgprintf("%s == %d", REGVAL_SPLITHORIZON, g_params.dwSplitHorizon);
  1616. dbgprintf("%s == %d", REGVAL_POISONREVERSE, g_params.dwPoisonReverse);
  1617. dbgprintf("%s == %d", REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates);
  1618. dbgprintf("%s == %d", REGVAL_OVERWRITESTATIC, dwOverwriteStaticRoutes);
  1619. dbgprintf("%s == %d", REGVAL_TRIGGERFREQUENCY,
  1620. g_params.dwMaxTriggerFrequency / 1000);
  1621. if (g_params.dwSilentRIP != 0) {
  1622. dbgprintf("IPRIP is configured to be silent.");
  1623. }
  1624. else {
  1625. dbgprintf("IPRIP is configured to be active.");
  1626. }
  1627. if (dwLoggingLevel >= LOGLEVEL_INFORMATION) {
  1628. // log the parameters IPRIP is using
  1629. //
  1630. CHAR szBuffer[2048], *lplpszArgs[] = { szBuffer };
  1631. sprintf(szBuffer,
  1632. "\r\n%s: %d"
  1633. "\r\n%s: %d"
  1634. "\r\n%s: %d"
  1635. "\r\n%s: %d"
  1636. "\r\n%s: %d"
  1637. "\r\n%s: %d"
  1638. "\r\n%s: %d"
  1639. "\r\n%s: %d"
  1640. "\r\n%s: %d"
  1641. "\r\n%s: %d"
  1642. "\r\n%s: %d"
  1643. "\r\n%s: %d"
  1644. "\r\n%s: %d"
  1645. "\r\n%s: %d",
  1646. REGVAL_LOGGINGLEVEL, dwLoggingLevel,
  1647. REGVAL_ROUTETIMEOUT, dwRouteTimeout / 1000,
  1648. REGVAL_GARBAGETIMEOUT, dwGarbageTimeout / 1000,
  1649. REGVAL_UPDATEFREQUENCY, dwUpdateFrequency / 1000,
  1650. REGVAL_ACCEPT_HOST, g_params.dwAcceptHost,
  1651. REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost,
  1652. REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault,
  1653. REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault,
  1654. REGVAL_SPLITHORIZON, g_params.dwSplitHorizon,
  1655. REGVAL_POISONREVERSE, g_params.dwPoisonReverse,
  1656. REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates,
  1657. REGVAL_OVERWRITESTATIC, dwOverwriteStaticRoutes,
  1658. REGVAL_TRIGGERFREQUENCY, g_params.dwMaxTriggerFrequency / 1000,
  1659. REGVAL_SILENTRIP, g_params.dwSilentRIP);
  1660. RipLogInformation(RIPLOG_REGISTRY_PARAMETERS, 1, lplpszArgs, 0);
  1661. }
  1662. RIP_UNLOCK_PARAMS();
  1663. return 0;
  1664. }
  1665. #else
  1666. //-----------------------------------------------------------------------
  1667. //
  1668. //--------------------------- Windows 95 Specific -----------------------
  1669. //
  1670. //-----------------------------------------------------------------------
  1671. //
  1672. // named event
  1673. //
  1674. #define RIP_LISTENER_EVENT TEXT( "RIP.Listener.Event" )
  1675. HINSTANCE hInst; // current instance
  1676. HWND hWnd; // Main window handle.
  1677. //
  1678. // resource strings
  1679. //
  1680. char szAppName[64]; // The name of this application
  1681. char szTitle[32]; // The title bar text
  1682. char szHelpStr[32]; // Help flag "Help"
  1683. char szQuestStr[32]; // Abriev. Help Flag "?"
  1684. char szCloseStr[32]; // Close flag "close"
  1685. char szDestroyStr[32]; // Destroy flag "destroy"
  1686. char szHelpText1[256]; // Help String
  1687. char szHelpText2[64]; // Help String
  1688. char szHelpText3[128]; // Help String
  1689. //
  1690. // local function prototypes
  1691. //
  1692. BOOL
  1693. InitApplication(
  1694. HINSTANCE hInstance
  1695. );
  1696. BOOL
  1697. InitInstance(
  1698. HINSTANCE hInstance,
  1699. int nCmdShow
  1700. );
  1701. BOOL
  1702. GetStrings(
  1703. HINSTANCE hInstance
  1704. );
  1705. LRESULT CALLBACK WndProc(
  1706. HWND hWnd, // window handle
  1707. UINT message, // type of message
  1708. WPARAM uParam, // additional information
  1709. LPARAM lParam // additional information
  1710. );
  1711. //-----------------------------------------------------------------------
  1712. // Function: GetStrings
  1713. //
  1714. // Retrieve resource strings
  1715. //-----------------------------------------------------------------------
  1716. BOOL GetStrings(HINSTANCE hInstance)
  1717. {
  1718. if (LoadString(hInstance, IDS_TITLE_BAR, szTitle, sizeof(szTitle)) == 0)
  1719. {
  1720. goto ErrorExit;
  1721. }
  1722. if (LoadString(hInstance, IDS_APP_NAME, szAppName, sizeof(szAppName)) == 0)
  1723. {
  1724. goto ErrorExit;
  1725. }
  1726. if (LoadString(hInstance, IDS_HELP_TEXT1, szHelpText1, sizeof(szHelpText1)) == 0)
  1727. {
  1728. goto ErrorExit;
  1729. }
  1730. if (LoadString(hInstance, IDS_HELP_TEXT2, szHelpText2, sizeof(szHelpText2)) == 0)
  1731. {
  1732. goto ErrorExit;
  1733. }
  1734. return TRUE;
  1735. ErrorExit:
  1736. return FALSE;
  1737. }
  1738. //-----------------------------------------------------------------------
  1739. // Functions : InitInstance
  1740. //
  1741. // save instance handle and create main window.
  1742. //-----------------------------------------------------------------------
  1743. BOOL
  1744. InitInstance(
  1745. HINSTANCE hInstance,
  1746. int nCmdShow
  1747. )
  1748. {
  1749. //
  1750. // Save the instance handle in static variable, which will be used in
  1751. // many subsequence calls from this application to Windows.
  1752. //
  1753. // Store instance handle in our global variable
  1754. //
  1755. hInst = hInstance;
  1756. //
  1757. // Create a main window for this application instance.
  1758. //
  1759. hWnd = CreateWindow(
  1760. szAppName,
  1761. szTitle,
  1762. WS_EX_TRANSPARENT, // Window style.
  1763. 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, // Use default positioning CW_USEDEAULT
  1764. NULL, // Overlapped windows have no parent.
  1765. NULL, // Use the window class menu.
  1766. hInstance, // This instance owns this window.
  1767. NULL // We don't use any data in our WM_CREATE
  1768. );
  1769. //
  1770. // If window could not be created, return "failure"
  1771. //
  1772. if (!hWnd)
  1773. {
  1774. dbgprintf( "Failed to create window" );
  1775. return (FALSE);
  1776. }
  1777. //
  1778. // Make the window visible; update its client area; and return "success"
  1779. //
  1780. ShowWindow(hWnd, nCmdShow); // Show the window
  1781. UpdateWindow(hWnd); // Sends WM_PAINT message
  1782. return (TRUE); // We succeeded...
  1783. }
  1784. //-----------------------------------------------------------------------------
  1785. // Function : InitApplication
  1786. //
  1787. // initialize window data and register window class
  1788. //-----------------------------------------------------------------------------
  1789. BOOL InitApplication(HINSTANCE hInstance)
  1790. {
  1791. WNDCLASS wc;
  1792. DWORD LastError;
  1793. //
  1794. // Fill in window class structure with parameters that
  1795. // describe the main window.
  1796. //
  1797. wc.style = CS_HREDRAW | CS_VREDRAW;// Class style(s).
  1798. wc.lpfnWndProc = (WNDPROC)WndProc; // Window Procedure
  1799. wc.cbClsExtra = 0; // No per-class extra data.
  1800. wc.cbWndExtra = 0; // No per-window extra data.
  1801. wc.hInstance = hInstance; // Owner of this class
  1802. wc.hIcon = NULL;
  1803. wc.hCursor = NULL;
  1804. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);// Default color
  1805. wc.lpszMenuName = szAppName; // Menu name from .RC
  1806. wc.lpszClassName = szAppName; // Name to register as
  1807. //
  1808. // Register the window class and return success/failure code.
  1809. //
  1810. if ( !RegisterClass(&wc) )
  1811. {
  1812. dbgprintf( "Failed to register class" );
  1813. return FALSE;
  1814. }
  1815. else
  1816. {
  1817. return TRUE;
  1818. }
  1819. }
  1820. //-----------------------------------------------------------------------------
  1821. // Function : WndProc
  1822. //
  1823. // process messages
  1824. //-----------------------------------------------------------------------------
  1825. LRESULT CALLBACK WndProc(
  1826. HWND hWnd, // window handle
  1827. UINT message, // type of message
  1828. WPARAM uParam, // additional information
  1829. LPARAM lParam // additional information
  1830. )
  1831. {
  1832. switch (message)
  1833. {
  1834. case WM_ENDSESSION:
  1835. case WM_QUERYENDSESSION:
  1836. if (lParam == 0)
  1837. {
  1838. dbgprintf ( "IPRIP : Received shutdown message\n" );
  1839. }
  1840. if (lParam == 1 ) //EWX_REALLYLOGOFF
  1841. {
  1842. dbgprintf ( "IPRIP : Received logoff message\n" );
  1843. }
  1844. return(1);
  1845. case WM_DESTROY: // message: window being destroyed
  1846. PostQuitMessage(0);
  1847. return(0);
  1848. default: // Pass it on if unproccessed
  1849. return (DefWindowProc(hWnd, message, uParam, lParam));
  1850. }
  1851. }
  1852. //-----------------------------------------------------------------------
  1853. // Function: LoadParameters
  1854. //
  1855. // Reads various configuration flags from the registry.
  1856. //-----------------------------------------------------------------------
  1857. DWORD LoadParameters()
  1858. {
  1859. RIP_LOCK_PARAMS();
  1860. g_params.dwSilentRIP = 1;
  1861. g_params.dwAcceptHost = DEF_ACCEPT_HOST;
  1862. g_params.dwAnnounceHost = DEF_ANNOUNCE_HOST;
  1863. g_params.dwAcceptDefault = DEF_ACCEPT_DEFAULT;
  1864. g_params.dwAnnounceDefault = DEF_ANNOUNCE_DEFAULT;
  1865. g_params.dwSplitHorizon = DEF_SPLITHORIZON;
  1866. g_params.dwPoisonReverse = DEF_POISONREVERSE;
  1867. g_params.dwTriggeredUpdates = DEF_TRIGGEREDUPDATES;
  1868. g_params.dwMaxTriggerFrequency = DEF_TRIGGERFREQUENCY;
  1869. g_params.dwRouteTimeout = DEF_ROUTETIMEOUT;
  1870. g_params.dwUpdateFrequency = DEF_UPDATEFREQUENCY;
  1871. g_params.dwGarbageTimeout = DEF_GARBAGETIMEOUT;
  1872. g_params.dwOverwriteStaticRoutes = DEF_OVERWRITESTATIC;
  1873. g_params.dwLoggingLevel = DEF_LOGGINGLEVEL;
  1874. dbgprintf("%s == %d", REGVAL_LOGGINGLEVEL, g_params.dwLoggingLevel);
  1875. dbgprintf("%s == %d", REGVAL_ROUTETIMEOUT, g_params.dwRouteTimeout / 1000);
  1876. dbgprintf("%s == %d", REGVAL_GARBAGETIMEOUT, g_params.dwGarbageTimeout / 1000);
  1877. dbgprintf("%s == %d", REGVAL_UPDATEFREQUENCY, g_params.dwUpdateFrequency / 1000);
  1878. dbgprintf("%s == %d", REGVAL_ACCEPT_HOST, g_params.dwAcceptHost);
  1879. dbgprintf("%s == %d", REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost);
  1880. dbgprintf("%s == %d", REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault);
  1881. dbgprintf("%s == %d", REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault);
  1882. dbgprintf("%s == %d", REGVAL_SPLITHORIZON, g_params.dwSplitHorizon);
  1883. dbgprintf("%s == %d", REGVAL_POISONREVERSE, g_params.dwPoisonReverse);
  1884. dbgprintf("%s == %d", REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates);
  1885. dbgprintf("%s == %d", REGVAL_OVERWRITESTATIC, g_params.dwOverwriteStaticRoutes);
  1886. dbgprintf("%s == %d", REGVAL_TRIGGERFREQUENCY,
  1887. g_params.dwMaxTriggerFrequency / 1000);
  1888. if (g_params.dwSilentRIP != 0)
  1889. {
  1890. dbgprintf("IPRIP is configured to be silent.");
  1891. }
  1892. else
  1893. {
  1894. dbgprintf("IPRIP is configured to be active.");
  1895. }
  1896. if (g_params.dwLoggingLevel >= LOGLEVEL_INFORMATION)
  1897. {
  1898. //
  1899. // log the parameters IPRIP is using
  1900. //
  1901. CHAR szBuffer[2048], *lplpszArgs[] = { szBuffer };
  1902. sprintf(szBuffer,
  1903. "\r\n%s: %d"
  1904. "\r\n%s: %d"
  1905. "\r\n%s: %d"
  1906. "\r\n%s: %d"
  1907. "\r\n%s: %d"
  1908. "\r\n%s: %d"
  1909. "\r\n%s: %d"
  1910. "\r\n%s: %d"
  1911. "\r\n%s: %d"
  1912. "\r\n%s: %d"
  1913. "\r\n%s: %d"
  1914. "\r\n%s: %d"
  1915. "\r\n%s: %d"
  1916. "\r\n%s: %d",
  1917. REGVAL_LOGGINGLEVEL, g_params.dwLoggingLevel,
  1918. REGVAL_ROUTETIMEOUT, g_params.dwRouteTimeout / 1000,
  1919. REGVAL_GARBAGETIMEOUT, g_params.dwGarbageTimeout / 1000,
  1920. REGVAL_UPDATEFREQUENCY, g_params.dwUpdateFrequency / 1000,
  1921. REGVAL_ACCEPT_HOST, g_params.dwAcceptHost,
  1922. REGVAL_ANNOUNCE_HOST, g_params.dwAnnounceHost,
  1923. REGVAL_ACCEPT_DEFAULT, g_params.dwAcceptDefault,
  1924. REGVAL_ANNOUNCE_DEFAULT, g_params.dwAnnounceDefault,
  1925. REGVAL_SPLITHORIZON, g_params.dwSplitHorizon,
  1926. REGVAL_POISONREVERSE, g_params.dwPoisonReverse,
  1927. REGVAL_TRIGGEREDUPDATES, g_params.dwTriggeredUpdates,
  1928. REGVAL_OVERWRITESTATIC, g_params.dwOverwriteStaticRoutes,
  1929. REGVAL_TRIGGERFREQUENCY, g_params.dwMaxTriggerFrequency / 1000,
  1930. REGVAL_SILENTRIP, g_params.dwSilentRIP);
  1931. RipLogInformation(RIPLOG_REGISTRY_PARAMETERS, 1, lplpszArgs, 0);
  1932. }
  1933. RIP_UNLOCK_PARAMS();
  1934. return 0;
  1935. }
  1936. //-----------------------------------------------------------------------
  1937. // Function: WinMain
  1938. //
  1939. // Launches the RIP service and waits for it to terminate
  1940. //-----------------------------------------------------------------------
  1941. INT APIENTRY
  1942. WinMain(
  1943. HINSTANCE hInstance,
  1944. HINSTANCE hPrevInstance,
  1945. LPSTR lpCmdLine,
  1946. int nCmdShow
  1947. )
  1948. {
  1949. MSG msg;
  1950. HANDLE RipListenerEvent, hThread, hKernel32 = NULL;
  1951. DWORD threadId, LastError;
  1952. BOOL fRegSrvcProc = FALSE;
  1953. FARPROC pRegSrvcProc;
  1954. LPCSTR event_name = RIP_LISTENER_EVENT;
  1955. DWORD err;
  1956. //
  1957. // Get entry point RegisterServiceProcess
  1958. //
  1959. /*
  1960. if ( (GetVersion() & 0x000000ff) == 0x04 )
  1961. {
  1962. if ((hKernel32 = GetModuleHandle("kernel32.dll")) == NULL)
  1963. {
  1964. //
  1965. // This should never happen but we'll try and
  1966. // load the library anyway
  1967. //
  1968. if ((hKernel32 = LoadLibrary("kernel32.dll")) == NULL)
  1969. {
  1970. fRegSrvcProc = FALSE;
  1971. }
  1972. }
  1973. if (hKernel32)
  1974. {
  1975. if ((pRegSrvcProc = GetProcAddress(hKernel32,"RegisterServiceProcess")) == NULL)
  1976. {
  1977. fRegSrvcProc = FALSE;
  1978. }
  1979. else
  1980. {
  1981. fRegSrvcProc = TRUE;
  1982. }
  1983. }
  1984. }
  1985. else
  1986. {
  1987. fRegSrvcProc = FALSE;
  1988. }
  1989. */
  1990. //
  1991. // Other instances of RIP listener running?
  1992. //
  1993. RipListenerEvent = OpenEvent( SYNCHRONIZE, FALSE, event_name ) ;
  1994. if ( RipListenerEvent == NULL)
  1995. {
  1996. if ( (RipListenerEvent = CreateEvent( NULL, FALSE, TRUE, event_name ) ) == NULL)
  1997. {
  1998. LastError = GetLastError();
  1999. dbgprintf(
  2000. "IPRIP Create Event failed, error code %d",
  2001. LastError
  2002. );
  2003. RipLogError( RIPLOG_CREATEEVENT_FAILED, 0, NULL, LastError );
  2004. return 1;
  2005. }
  2006. }
  2007. else
  2008. {
  2009. //
  2010. // another instance is running
  2011. //
  2012. HANDLE hParentWin;
  2013. dbgprintf( "IPRIP : Service already running\n" );
  2014. RipLogError( RIPLOG_SERVICE_AREADY_STARTED, 0, NULL, 0 );
  2015. return 1;
  2016. }
  2017. //
  2018. // retrieve resource strings
  2019. //
  2020. if ( !GetStrings(hInstance) )
  2021. {
  2022. dbgprintf( "IPRIP : Service failed to initialize\n" );
  2023. RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
  2024. return 1;
  2025. }
  2026. //
  2027. // required initialization for windows apps.
  2028. //
  2029. if( !InitApplication( hInstance ) )
  2030. {
  2031. dbgprintf( "IPRIP : Service failed to initialize\n" );
  2032. RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
  2033. return 1;
  2034. }
  2035. if (!InitInstance(hInstance, SW_HIDE))
  2036. {
  2037. dbgprintf( "IPRIP : Service failed to initialize\n" );
  2038. RipLogError( RIPLOG_SERVICE_INIT_FAILED, 0, NULL, 0 );
  2039. return 1;
  2040. }
  2041. //
  2042. // Launch main service controller thread
  2043. //
  2044. if ( ( hThread = CreateThread(
  2045. NULL,
  2046. 0,
  2047. (LPTHREAD_START_ROUTINE)ServiceMain,
  2048. NULL,
  2049. 0,
  2050. &threadId
  2051. )
  2052. ) == 0)
  2053. {
  2054. dbgprintf( "IPRIP : Failed thread creation\n" );
  2055. RipLogError( RIPLOG_CREATETHREAD_FAILED, 0, NULL, 0 );
  2056. return 1;
  2057. }
  2058. //
  2059. // Register service process
  2060. //
  2061. /*
  2062. if (fRegSrvcProc)
  2063. {
  2064. (*pRegSrvcProc)(GetCurrentProcessId(), RSP_SIMPLE_SERVICE);
  2065. }
  2066. */
  2067. //
  2068. // Acquire and dispatch messages until a WM_QUIT message is received.
  2069. //
  2070. while (GetMessage(&msg, NULL, 0, 0))
  2071. {
  2072. TranslateMessage(&msg); // Translates virtual key codes
  2073. DispatchMessage(&msg); // Dispatches message to window
  2074. }
  2075. //
  2076. // Un register service process
  2077. //
  2078. /*
  2079. if (fRegSrvcProc)
  2080. {
  2081. (*pRegSrvcProc)(GetCurrentProcessId(), RSP_UNREGISTER_SERVICE);
  2082. }
  2083. */
  2084. dbgprintf( "IPRIP : Service terminated\n" );
  2085. RipLogError( RIPLOG_SERVICE_STOPPED, 0, NULL, 0 );
  2086. return(0);
  2087. UNREFERENCED_PARAMETER(lpCmdLine);
  2088. }
  2089. // Name: Mohsin Ahmed
  2090. // Email: [email protected]
  2091. // Date: Mon Nov 04 13:53:46 1996
  2092. // File: s:/tcpcmd/common2/debug.c
  2093. // Synopsis: Win95 Woes, don't have ntdll.dll on win95.
  2094. #include <windows.h>
  2095. #define MAX_DEBUG_OUTPUT 1024
  2096. void DbgPrintf( char * format, ... )
  2097. {
  2098. va_list args;
  2099. char out[MAX_DEBUG_OUTPUT];
  2100. int cch=0;
  2101. // cch = wsprintf( out, MODULE_NAME ":" );
  2102. va_start( args, format );
  2103. wvsprintf( out + cch, format, args );
  2104. va_end( args );
  2105. OutputDebugString( out );
  2106. }
  2107. #endif