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.

559 lines
13 KiB

  1. #include "private.h"
  2. #include "new.tmh"
  3. #define NLB_MAX_PORT_STRING_SIZE 128 // in WCHARS, including ending NULL
  4. BOOL
  5. gen_port_rule_string(
  6. IN PWLBS_PORT_RULE pPr,
  7. OUT LPWSTR pString // At least NLB_MAX_PORT_STRING_SIZE wchars
  8. );
  9. BOOL
  10. parse_port_rule_string(
  11. IN LPCWSTR pString,
  12. OUT PWLBS_PORT_RULE pPr
  13. );
  14. VOID
  15. test_port_rule_string(VOID)
  16. {
  17. LPCWSTR RuleStrings[] =
  18. {
  19. L"",
  20. L" \t \n ",
  21. L"n=v",
  22. L" \t \n n=v",
  23. L" \t \n n \t \n = \t \n v",
  24. L"na=v1 nb=v2 nc=v3",
  25. L"\t na \t = \t v1 \t nb \t \n =\t \n v2 \t \n nc \t = \n v3 ",
  26. #if 1
  27. L"ip=1.1.1.1 protocol=TCP start=80 end=288 mode=SINGLE"
  28. L" priority=1",
  29. L"ip=1.1.1.1 protocol=UDP start=80 end=288 mode=MULTIPLE"
  30. L" affinity=SINGLE load=80",
  31. L"ip=1.1.1.1 protocol=UDP start=80 end=288 mode=MULTIPLE"
  32. L" affinity=NONE load=80",
  33. L"ip=1.1.1.1 protocol=UDP start=80 end=288 mode=MULTIPLE"
  34. L" affinity=CLASSC",
  35. L"ip=1.1.1.1 protocol=BOTH start=80 end=288 mode=DISABLED",
  36. #endif // 0
  37. NULL // Must be last
  38. };
  39. for (LPCWSTR *ppRs = RuleStrings; *ppRs!=NULL; ppRs++)
  40. {
  41. LPCWSTR szRule = *ppRs;
  42. WCHAR szGenString[NLB_MAX_PORT_STRING_SIZE];
  43. printf("ORIG: %ws\n", szRule);
  44. WLBS_PORT_RULE Pr;
  45. BOOL fRet;
  46. fRet = parse_port_rule_string(
  47. szRule,
  48. &Pr
  49. );
  50. if (fRet == FALSE)
  51. {
  52. printf("parse_port_rule_string returned FAILURE.\n");
  53. continue;
  54. }
  55. fRet = gen_port_rule_string(
  56. &Pr,
  57. szGenString
  58. );
  59. if (fRet == FALSE)
  60. {
  61. printf("gen_port_rule_string returned FAILURE.\n");
  62. continue;
  63. }
  64. printf("GEN: %ws\n", szGenString);
  65. }
  66. }
  67. BOOL
  68. gen_port_rule_string(
  69. IN PWLBS_PORT_RULE pPr,
  70. OUT LPWSTR pString // At least NLB_MAX_PORT_STRING_SIZE wchars
  71. )
  72. {
  73. BOOL fRet = FALSE;
  74. LPCWSTR szProtocol = L"";
  75. LPCWSTR szMode = L"";
  76. LPCWSTR szAffinity = L"";
  77. ZeroMemory(pString, NLB_MAX_PORT_STRING_SIZE*sizeof(WCHAR));
  78. switch(pPr->protocol)
  79. {
  80. case CVY_TCP:
  81. szProtocol = L"TCP";
  82. break;
  83. case CVY_UDP:
  84. szProtocol = L"UDP";
  85. break;
  86. case CVY_TCP_UDP:
  87. szProtocol = L"BOTH";
  88. break;
  89. default:
  90. goto end; // bad parse
  91. }
  92. switch(pPr->mode)
  93. {
  94. case CVY_SINGLE:
  95. szMode = L"SINGLE";
  96. break;
  97. case CVY_MULTI:
  98. szMode = L"MULTIPLE";
  99. switch(pPr->mode_data.multi.affinity)
  100. {
  101. case CVY_AFFINITY_NONE:
  102. szAffinity = L"NONE";
  103. break;
  104. case CVY_AFFINITY_SINGLE:
  105. szAffinity = L"SINGLE";
  106. break;
  107. case CVY_AFFINITY_CLASSC:
  108. szAffinity = L"CLASSC";
  109. break;
  110. default:
  111. goto end; // bad parse
  112. }
  113. break;
  114. case CVY_NEVER:
  115. szMode = L"DISABLED";
  116. break;
  117. default:
  118. goto end; // bad parse
  119. }
  120. *pString = 0;
  121. _snwprintf(
  122. pString,
  123. NLB_MAX_PORT_STRING_SIZE-1,
  124. L"ip=%ws protocol=%ws start=%u end=%u mode=%ws ",
  125. pPr->virtual_ip_addr,
  126. szProtocol,
  127. pPr->start_port,
  128. pPr->end_port,
  129. szMode
  130. );
  131. UINT Len = wcslen(pString);
  132. if (Len >= (NLB_MAX_PORT_STRING_SIZE-1))
  133. {
  134. goto end; // not enough space.
  135. }
  136. if (pPr->mode == CVY_MULTI)
  137. {
  138. if (pPr->mode_data.multi.equal_load)
  139. {
  140. _snwprintf(
  141. pString+Len,
  142. (NLB_MAX_PORT_STRING_SIZE-1-Len),
  143. L"affinity=%ws",
  144. szAffinity
  145. );
  146. }
  147. else
  148. {
  149. _snwprintf(
  150. pString+Len,
  151. (NLB_MAX_PORT_STRING_SIZE-1-Len),
  152. L"affinity=%ws load=%u",
  153. szAffinity,
  154. pPr->mode_data.multi.load
  155. );
  156. }
  157. }
  158. else if (pPr->mode == CVY_SINGLE)
  159. {
  160. _snwprintf(
  161. pString+Len,
  162. (NLB_MAX_PORT_STRING_SIZE-1-Len),
  163. L"priority=%u",
  164. pPr->mode_data.single.priority
  165. );
  166. }
  167. if (pString[NLB_MAX_PORT_STRING_SIZE-1] !=0)
  168. {
  169. // out of space
  170. goto end;
  171. }
  172. fRet = TRUE;
  173. end:
  174. return fRet;
  175. }
  176. BOOL
  177. parse_port_rule_string(
  178. IN LPCWSTR pString,
  179. OUT PWLBS_PORT_RULE pPr
  180. )
  181. {
  182. //
  183. // Look for following name=value pairs
  184. //
  185. // ip=1.1.1.1
  186. // protocol=[TCP|UDP|BOTH]
  187. // start=122
  188. // end=122
  189. // mode=[SINGLE|MULTIPLE|DISABLED]
  190. // affinity=[NONE|SINGLE|CLASSC]
  191. // load=80
  192. // priority=1"
  193. //
  194. #define INVALID_VALUE ((DWORD)-1)
  195. LPWSTR psz = NULL;
  196. WCHAR szCleanedString[2*NLB_MAX_PORT_STRING_SIZE];
  197. WCHAR c;
  198. BOOL fRet = FALSE;
  199. DWORD protocol= INVALID_VALUE;
  200. DWORD start_port= INVALID_VALUE;
  201. DWORD end_port= INVALID_VALUE;
  202. DWORD mode= INVALID_VALUE;
  203. DWORD affinity= INVALID_VALUE;
  204. DWORD load= INVALID_VALUE;
  205. DWORD priority= INVALID_VALUE;
  206. ZeroMemory(pPr, sizeof(*pPr));
  207. //
  208. // Set szCleanedString to be a version of pString in "canonical" form:
  209. // extraneous whitespace stripped out and whitspace represented by a
  210. // single '\b' character.
  211. {
  212. UINT Len = wcslen(pString);
  213. if (Len > (sizeof(szCleanedString)/sizeof(WCHAR)))
  214. {
  215. goto end;
  216. }
  217. wcscpy(szCleanedString, pString);
  218. //
  219. // convert different forms of whitespace into blanks
  220. //
  221. for (psz=szCleanedString; (c=*psz)!=0; psz++)
  222. {
  223. if (c == ' ' || c == '\t' || c == '\n')
  224. {
  225. *psz = ' ';
  226. }
  227. }
  228. //
  229. // convert runs of whitespace into a single blank
  230. // also get rid of initial whitespace
  231. //
  232. LPWSTR psz1 = szCleanedString;
  233. BOOL fRun = TRUE; // initial value of TRUE gets rid of initial space
  234. for (psz=szCleanedString; (c=*psz)!=0; psz++)
  235. {
  236. if (c == ' ')
  237. {
  238. if (fRun)
  239. {
  240. continue;
  241. }
  242. else
  243. {
  244. fRun = TRUE;
  245. }
  246. }
  247. else if (c == '=')
  248. {
  249. if (fRun)
  250. {
  251. //
  252. // The '=' was preceed by whitespace -- delete that
  253. // whitespace. We keep fRun TRUE so subsequent whitespace
  254. // is eliminated.
  255. //
  256. if (psz1 == szCleanedString)
  257. {
  258. // we're just starting, and we get an '=' -- bad
  259. goto end;
  260. }
  261. psz1--;
  262. if (*psz1 != ' ')
  263. {
  264. ASSERT(*psz1 == '=');
  265. goto end; // two equals in a row, not accepted!
  266. }
  267. }
  268. }
  269. else // non blank and non '=' chracter
  270. {
  271. fRun = FALSE;
  272. }
  273. *psz1++ = c;
  274. }
  275. *psz1=0;
  276. }
  277. wprintf(L"CLEANED: \"%ws\"\n", szCleanedString);
  278. //
  279. // Now actually do the parse.
  280. //
  281. psz = szCleanedString;
  282. while(*psz!=0)
  283. {
  284. WCHAR Name[32];
  285. WCHAR Value[32];
  286. //
  287. // Look for the Name in Name=Value pair.
  288. //
  289. if (swscanf(psz, L"%16[a-zA-Z]=%16[0-9.a-zA-Z]", Name, Value) != 2)
  290. {
  291. // bad parse;
  292. goto end;
  293. }
  294. //
  295. // Skip past the name=value pair -- it contains no blanks
  296. //
  297. for (; (c=*psz)!=NULL; psz++)
  298. {
  299. if (c==' ')
  300. {
  301. psz++; // to skip past the blank
  302. break;
  303. }
  304. }
  305. //
  306. // Now look for the specific name/values
  307. //
  308. // ip=1.1.1.1
  309. // protocol=[TCP|UDP|BOTH]
  310. // start=122
  311. // end=122
  312. // mode=[SINGLE|MULTIPLE|DISABLED]
  313. // affinity=[NONE|SINGLE|CLASSC]
  314. // load=80
  315. // priority=1"
  316. //
  317. if (!_wcsicmp(Name, L"ip"))
  318. {
  319. if (swscanf(Value, L"%15[0-9.]", pPr->virtual_ip_addr) != 1)
  320. {
  321. goto end;
  322. }
  323. }
  324. else if (!_wcsicmp(Name, L"protocol"))
  325. {
  326. if (!_wcsicmp(Value, L"TCP"))
  327. {
  328. protocol = CVY_TCP;
  329. }
  330. else if (!_wcsicmp(Value, L"UDP"))
  331. {
  332. protocol = CVY_UDP;
  333. }
  334. else if (!_wcsicmp(Value, L"BOTH"))
  335. {
  336. protocol = CVY_TCP_UDP;
  337. }
  338. else
  339. {
  340. // bad parse;
  341. goto end;
  342. }
  343. }
  344. else if (!_wcsicmp(Name, L"protocol"))
  345. {
  346. }
  347. else if (!_wcsicmp(Name, L"start"))
  348. {
  349. if (swscanf(Value, L"%u", &start_port)!=1)
  350. {
  351. // bad parse;
  352. goto end;
  353. }
  354. if (start_port > 65535)
  355. {
  356. // bad parse;
  357. goto end;
  358. }
  359. }
  360. else if (!_wcsicmp(Name, L"end"))
  361. {
  362. if (swscanf(Value, L"%u", &end_port)!=1)
  363. {
  364. // bad parse;
  365. goto end;
  366. }
  367. if (end_port > 65535)
  368. {
  369. // bad parse;
  370. goto end;
  371. }
  372. }
  373. else if (!_wcsicmp(Name, L"mode"))
  374. {
  375. if (!_wcsicmp(Value, L"SINGLE"))
  376. {
  377. mode = CVY_SINGLE;
  378. }
  379. else if (!_wcsicmp(Value, L"MULTIPLE"))
  380. {
  381. mode = CVY_MULTI;
  382. }
  383. else if (!_wcsicmp(Value, L"DISABLED"))
  384. {
  385. mode = CVY_NEVER;
  386. }
  387. else
  388. {
  389. // bad parse;
  390. goto end;
  391. }
  392. }
  393. else if (!_wcsicmp(Name, L"affinity"))
  394. {
  395. if (!_wcsicmp(Value, L"NONE"))
  396. {
  397. affinity = CVY_AFFINITY_NONE;
  398. }
  399. else if (!_wcsicmp(Value, L"SINGLE"))
  400. {
  401. affinity = CVY_AFFINITY_SINGLE;
  402. }
  403. else if (!_wcsicmp(Value, L"CLASSC"))
  404. {
  405. affinity = CVY_AFFINITY_CLASSC;
  406. }
  407. else
  408. {
  409. // bad parse;
  410. goto end;
  411. }
  412. }
  413. else if (!_wcsicmp(Name, L"load"))
  414. {
  415. if (swscanf(Value, L"%u", &load)!=1)
  416. {
  417. if (load > 100)
  418. {
  419. // bad parse;
  420. goto end;
  421. }
  422. }
  423. }
  424. else if (!_wcsicmp(Name, L"priority"))
  425. {
  426. if (swscanf(Value, L"%u", &priority)!=1)
  427. {
  428. if (priority > 31)
  429. {
  430. // bad parse;
  431. goto end;
  432. }
  433. }
  434. }
  435. else
  436. {
  437. // bad parse
  438. goto end;
  439. }
  440. printf("SUCCESSFUL PARSE: %ws = %ws\n", Name, Value);
  441. }
  442. //
  443. // Set up the PARAMS structure, doing extra parameter validation along the
  444. // way.
  445. //
  446. switch(mode)
  447. {
  448. case CVY_SINGLE:
  449. if (load != INVALID_VALUE || affinity != INVALID_VALUE)
  450. {
  451. goto end; // bad parse;
  452. }
  453. if ((priority < CVY_MIN_PRIORITY) || (priority > CVY_MAX_PRIORITY))
  454. {
  455. goto end; // bad parse
  456. }
  457. pPr->mode_data.single.priority = priority;
  458. break;
  459. case CVY_MULTI:
  460. if (priority != INVALID_VALUE)
  461. {
  462. goto end; // bad parse;
  463. }
  464. switch(affinity)
  465. {
  466. case CVY_AFFINITY_NONE:
  467. break;
  468. case CVY_AFFINITY_SINGLE:
  469. break;
  470. case CVY_AFFINITY_CLASSC:
  471. break;
  472. case INVALID_VALUE:
  473. default:
  474. goto end; // bad parse;
  475. }
  476. pPr->mode_data.multi.affinity = affinity;
  477. if (load == INVALID_VALUE)
  478. {
  479. // this means it's unassigned, which means equal.
  480. pPr->mode_data.multi.equal_load = 1;
  481. }
  482. else if (load > CVY_MAX_LOAD)
  483. {
  484. goto end; // bad parse
  485. }
  486. else
  487. {
  488. pPr->mode_data.multi.load = load;
  489. }
  490. break;
  491. case CVY_NEVER:
  492. if (load != INVALID_VALUE || affinity != INVALID_VALUE
  493. || priority != INVALID_VALUE)
  494. {
  495. goto end; // bad parse;
  496. }
  497. break;
  498. case INVALID_VALUE:
  499. default:
  500. goto end; // bad parse;
  501. }
  502. pPr->mode = mode;
  503. pPr->end_port = end_port;
  504. pPr->start_port = start_port;
  505. pPr->protocol = protocol;
  506. fRet = TRUE;
  507. end:
  508. return fRet;
  509. }