157416Smarkm 257416Smarkm Three pieces of state need to be kept for each side of each option. 357416Smarkm (You need the localside, sending WILL/WONT & receiving DO/DONT, and 457416Smarkm the remoteside, sending DO/DONT and receiving WILL/WONT) 557416Smarkm 657416Smarkm MY_STATE: What state am I in? 757416Smarkm WANT_STATE: What state do I want? 857416Smarkm WANT_RESP: How many requests have I initiated? 957416Smarkm 1057416Smarkm Default values: 1157416Smarkm MY_STATE = WANT_STATE = DONT 1257416Smarkm WANT_RESP = 0 1357416Smarkm 1457416Smarkm The local setup will change based on the state of the Telnet 1557416Smarkm variables. When we are the originator, we can either make the 1657416Smarkm local setup changes at option request time (in which case if 1757416Smarkm the option is denied we need to change things back) or when 1857416Smarkm the option is acknowledged. 1957416Smarkm 2057416Smarkm To initiate a switch to NEW_STATE: 2157416Smarkm 2257416Smarkm if ((WANT_RESP == 0 && NEW_STATE == MY_STATE) || 2357416Smarkm WANT_STATE == NEW_STATE) { 2457416Smarkm do nothing; 2557416Smarkm } else { 2657416Smarkm /* 2757416Smarkm * This is where the logic goes to change the local setup 2857416Smarkm * if we are doing so at request initiation 2957416Smarkm */ 3057416Smarkm WANT_STATE = NEW_STATE; 3157416Smarkm send NEW_STATE; 3257416Smarkm WANT_RESP += 1; 3357416Smarkm } 3457416Smarkm 3557416Smarkm When receiving NEW_STATE: 3657416Smarkm 3757416Smarkm if (WANT_RESP) { 3857416Smarkm --WANT_RESP; 3957416Smarkm if (WANT_RESP && (NEW_STATE == MY_STATE)) 4057416Smarkm --WANT_RESP; 4157416Smarkm } 4257416Smarkm if (WANT_RESP == 0) { 4357416Smarkm if (NEW_STATE != WANT_STATE) { 4457416Smarkm /* 4557416Smarkm * This is where the logic goes to decide if it is ok 4657416Smarkm * to switch to NEW_STATE, and if so, do any necessary 4757416Smarkm * local setup changes. 4857416Smarkm */ 4957416Smarkm if (ok_to_switch_to NEW_STATE) 5057416Smarkm WANT_STATE = NEW_STATE; 5157416Smarkm else 5257416Smarkm WANT_RESP++; 5357416Smarkm* if (MY_STATE != WANT_STATE) 5457416Smarkm reply with WANT_STATE; 5557416Smarkm } else { 5657416Smarkm /* 5757416Smarkm * This is where the logic goes to change the local setup 5857416Smarkm * if we are doing so at request acknowledgment 5957416Smarkm */ 6057416Smarkm } 6157416Smarkm } 6257416Smarkm MY_STATE = NEW_STATE; 6357416Smarkm 6457416Smarkm* This if() line is not needed, it should be ok to always do the 6557416Smarkm "reply with WANT_STATE". With the if() line, asking to turn on 6657416Smarkm an option that the other side doesn't understand is: 6757416Smarkm Send DO option 6857416Smarkm Recv WONT option 6957416Smarkm Without the if() line, it is: 7057416Smarkm Send DO option 7157416Smarkm Recv WONT option 7257416Smarkm Send DONT option 7357416Smarkm If the other side does not expect to receive the latter case, 7457416Smarkm but generates the latter case, then there is a potential for 7557416Smarkm option negotiation loops. An implementation that does not expect 7657416Smarkm to get the second case should not generate it, an implementation 7757416Smarkm that does expect to get it may or may not generate it, and things 7857416Smarkm will still work. Being conservative in what we send, we have the 7957416Smarkm if() statement in, but we expect the other side to generate the 8057416Smarkm last response. 81