Sage.UDPChatServer.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. MODULE UDPChatServer; (** AUTHOR "SAGE"; PURPOSE "UDP Chat Server" *)
  2. IMPORT
  3. Base := UDPChatBase, UDP, IP,
  4. Dates, Strings, Modules, Kernel, Events;
  5. CONST
  6. branchInit = 0;
  7. branchPacketReceive = 1;
  8. branchVersionCheck = 2;
  9. branchAuthentication = 3;
  10. branchPacketHandle = 4;
  11. branchEnd = 5;
  12. branchTerminated = 6;
  13. moduleName = "UDPChatServer";
  14. (* Event classification as in Events.XML *)
  15. EventClass = 3; (* UDP Chat *)
  16. EventSubclass = 3; (* UDP Chat Server *)
  17. TYPE
  18. String = Strings.String;
  19. Instance = OBJECT
  20. VAR
  21. s: UDP.Socket;
  22. dt: Dates.DateTime;
  23. running, terminated: BOOLEAN;
  24. ip: IP.Adr;
  25. branch, command, seqNum, messageType: INTEGER;
  26. uin, receiverUin, port, len, receiveBufOffset: LONGINT; res: WORD;
  27. user: Base.User;
  28. users: Base.Users;
  29. clients: Base.List;
  30. client, receiver: Base.Client;
  31. sendBuf: Base.Buffer;
  32. receiveBuf, password, shortName, fullName, eMail, message, textCode: String;
  33. str1, str2: ARRAY 256 OF CHAR;
  34. ACKReq: Base.ACKRec;
  35. PROCEDURE &New *(udp: UDP.Socket);
  36. BEGIN
  37. s := udp
  38. END New;
  39. PROCEDURE Destroy;
  40. BEGIN
  41. running := FALSE;
  42. s.Close;
  43. BEGIN {EXCLUSIVE}
  44. AWAIT (terminated)
  45. END;
  46. END Destroy;
  47. PROCEDURE FinalizeClients(clients: Base.List);
  48. VAR
  49. i: LONGINT;
  50. p: ANY;
  51. client: Base.Client;
  52. BEGIN
  53. i := 0;
  54. WHILE i < clients.GetCount () DO
  55. p := clients.GetItem (i);
  56. client := p (Base.Client);
  57. client.Finalize;
  58. INC (i);
  59. END;
  60. END FinalizeClients;
  61. PROCEDURE FindClient (clients: Base.List;
  62. uin: LONGINT;
  63. VAR client: Base.Client): BOOLEAN;
  64. VAR
  65. i: LONGINT;
  66. p: ANY;
  67. BEGIN
  68. i := 0;
  69. WHILE i < clients.GetCount () DO
  70. p := clients.GetItem (i);
  71. client := p (Base.Client);
  72. IF uin = client.uin THEN
  73. RETURN TRUE;
  74. END;
  75. INC (i);
  76. END;
  77. RETURN FALSE;
  78. END FindClient;
  79. PROCEDURE CheckKeepAlive (clients: Base.List);
  80. VAR
  81. i: LONGINT;
  82. p: ANY;
  83. BEGIN
  84. i := 0;
  85. WHILE i < clients.GetCount () DO
  86. p := clients.GetItem (i);
  87. client := p (Base.Client);
  88. IF Kernel.Expired (client.keepAliveTimer) THEN
  89. MulticastStatus (clients, client, Base.USER_OFFLINE, sendBuf, s);
  90. client.Finalize;
  91. clients.Remove (client);
  92. END;
  93. INC (i);
  94. END;
  95. END CheckKeepAlive;
  96. PROCEDURE Server_NewUserReply (ip: IP.Adr; port: LONGINT; uin: LONGINT;
  97. seqNum: INTEGER; sendBuf: Base.Buffer; s: UDP.Socket);
  98. VAR
  99. res: WORD;
  100. string: String;
  101. BEGIN {EXCLUSIVE}
  102. Base.ServerPacketInit (Base.NEW_USER_REPLY, seqNum, sendBuf);
  103. sendBuf.AddInt (uin, 4);
  104. string := sendBuf.GetString ();
  105. s.Send (ip, port, string^, 0, sendBuf.GetLength (), res);
  106. END Server_NewUserReply;
  107. PROCEDURE Server_LoginReply (client: Base.Client;
  108. sendBuf: Base.Buffer; s: UDP.Socket);
  109. VAR
  110. res: WORD;
  111. string: String;
  112. BEGIN {EXCLUSIVE}
  113. Base.ServerPacketInit (Base.LOGIN_REPLY, client.inSeqNum, sendBuf);
  114. sendBuf.AddInt (client.uin, 4);
  115. string := sendBuf.GetString ();
  116. s.Send (client.ip, client.port, string^, 0, sendBuf.GetLength (), res);
  117. END Server_LoginReply;
  118. PROCEDURE Server_InfoReply (client: Base.Client;
  119. user: Base.User; sendBuf: Base.Buffer; s: UDP.Socket);
  120. VAR
  121. string: String;
  122. res: WORD; len: LONGINT;
  123. BEGIN {EXCLUSIVE}
  124. Base.ServerPacketInit (Base.INFO_REPLY, client.inSeqNum, sendBuf);
  125. sendBuf.AddInt (user.uin, 4);
  126. len := Strings.Length (user.shortName) + 1;
  127. sendBuf.AddInt (len, 2);
  128. sendBuf.Add (user.shortName, 0, len, TRUE, res);
  129. string := sendBuf.GetString ();
  130. s.Send (client.ip, client.port, string^, 0, sendBuf.GetLength (), res);
  131. END Server_InfoReply;
  132. PROCEDURE Server_ACK (client: Base.Client;
  133. sendBuf: Base.Buffer; s: UDP.Socket);
  134. VAR
  135. res: WORD;
  136. string: String;
  137. BEGIN {EXCLUSIVE}
  138. Base.ServerPacketInit (Base.ACK, client.inSeqNum, sendBuf);
  139. string := sendBuf.GetString ();
  140. s.Send (client.ip, client.port, string^, 0, sendBuf.GetLength (), res);
  141. END Server_ACK;
  142. PROCEDURE Server_UserStatus (client, receiver: Base.Client;
  143. status: INTEGER; sendBuf: Base.Buffer; s: UDP.Socket);
  144. VAR
  145. res: WORD;
  146. string: String;
  147. BEGIN {EXCLUSIVE}
  148. Base.ServerPacketInit (status, receiver.outSeqNum, sendBuf);
  149. NEW (ACKReq);
  150. ACKReq.seqNum := receiver.outSeqNum;
  151. receiver.ACKList.Add (ACKReq);
  152. INC (receiver.outSeqNum);
  153. sendBuf.AddInt (client.uin, 4);
  154. string := sendBuf.GetString ();
  155. s.Send (receiver.ip, receiver.port, string^, 0, sendBuf.GetLength (), res);
  156. END Server_UserStatus;
  157. PROCEDURE Server_ReceiveMessage (client, receiver: Base.Client; dt: Dates.DateTime;
  158. messageType: INTEGER; message: String; sendBuf: Base.Buffer; s: UDP.Socket);
  159. VAR
  160. string: String;
  161. res: WORD; len: LONGINT;
  162. BEGIN {EXCLUSIVE}
  163. Base.ServerPacketInit (Base.RECEIVE_MESSAGE, receiver.outSeqNum, sendBuf);
  164. NEW (ACKReq);
  165. ACKReq.seqNum := receiver.outSeqNum;
  166. receiver.ACKList.Add (ACKReq);
  167. INC (receiver.outSeqNum);
  168. sendBuf.AddInt (client.uin, 4);
  169. sendBuf.AddInt (dt.year, 2);
  170. sendBuf.AddInt (dt.month, 1);
  171. sendBuf.AddInt (dt.day, 1);
  172. sendBuf.AddInt (dt.hour, 1);
  173. sendBuf.AddInt (dt.minute, 1);
  174. sendBuf.AddInt (messageType, 2);
  175. (*
  176. len := Strings.Length (message^) + 1;
  177. *)
  178. len := LEN (message^);
  179. sendBuf.AddInt (len, 2);
  180. sendBuf.Add (message^, 0, len, TRUE, res);
  181. string := sendBuf.GetString ();
  182. s.Send (receiver.ip, receiver.port, string^, 0, sendBuf.GetLength (), res);
  183. END Server_ReceiveMessage;
  184. PROCEDURE MulticastStatus (clients: Base.List;
  185. client: Base.Client;
  186. status: INTEGER; sendBuf: Base.Buffer; s: UDP.Socket);
  187. VAR
  188. i: LONGINT;
  189. p: ANY;
  190. receiver: Base.Client;
  191. BEGIN
  192. i := 0;
  193. WHILE i < clients.GetCount () DO
  194. p := clients.GetItem (i);
  195. receiver := p (Base.Client);
  196. IF client.uin # receiver.uin THEN
  197. Server_UserStatus (client, receiver, status, sendBuf, s);
  198. IF status = Base.USER_ONLINE THEN
  199. Server_UserStatus (receiver, client, status, sendBuf, s);
  200. END;
  201. END;
  202. INC (i);
  203. END;
  204. END MulticastStatus;
  205. PROCEDURE MulticastMessage (clients: Base.List;
  206. client: Base.Client; dt: Dates.DateTime; messageType: INTEGER; message: String;
  207. sendBuf: Base.Buffer; s: UDP.Socket);
  208. VAR
  209. i: LONGINT;
  210. p: ANY;
  211. receiver: Base.Client;
  212. BEGIN
  213. i := 0;
  214. WHILE i < clients.GetCount () DO
  215. p := clients.GetItem (i);
  216. receiver := p (Base.Client);
  217. (*IF client.uin # receiver.uin THEN*)
  218. Server_ReceiveMessage (client, receiver, dt, messageType, message, sendBuf, s);
  219. (*END;*)
  220. INC (i);
  221. END;
  222. END MulticastMessage;
  223. BEGIN {ACTIVE}
  224. branch := branchInit;
  225. REPEAT
  226. CASE branch OF
  227. | branchInit:
  228. NEW (receiveBuf, Base.MaxUDPDataLen);
  229. NEW (sendBuf, 0);
  230. NEW (clients);
  231. NEW (users);
  232. running := TRUE;
  233. terminated := FALSE;
  234. branch := branchPacketReceive;
  235. | branchPacketReceive:
  236. IF running THEN
  237. s.Receive (receiveBuf^, 0, Base.MaxUDPDataLen, 1, ip, port, len, res);
  238. IF (res = UDP.Ok) & (len > 0) THEN
  239. receiveBufOffset := 0;
  240. branch := branchVersionCheck;
  241. END;
  242. CheckKeepAlive (clients);
  243. ELSE
  244. branch := branchEnd;
  245. END;
  246. | branchVersionCheck:
  247. IF Base.BufGetInt (receiveBuf, receiveBufOffset) = Base.VERSION THEN
  248. branch := branchAuthentication;
  249. ELSE
  250. branch := branchPacketReceive;
  251. END;
  252. | branchAuthentication:
  253. command := Base.BufGetInt (receiveBuf, receiveBufOffset);
  254. seqNum := Base.BufGetInt (receiveBuf, receiveBufOffset);
  255. uin := Base.BufGetLInt (receiveBuf, receiveBufOffset);
  256. Strings.IntToStr (seqNum, str1);
  257. Strings.Concat (" SeqNum: ", str1, str1);
  258. Strings.Concat (str1, " Command: ", str1);
  259. Strings.IntToStr (uin, str2);
  260. Strings.Concat ("User ID: ", str2, str2);
  261. Strings.Concat (str2, str1, str1);
  262. Base.CommandDecode (command, str2);
  263. Strings.Concat (str1, str2, str1);
  264. Log (Events.Information, 0, str1, FALSE);
  265. IF FindClient (clients, uin, client) THEN
  266. (* Additional check *)
  267. IF (IP.AdrsEqual (client.ip, ip)) & (client.port = port) THEN
  268. branch := branchPacketHandle;
  269. ELSE
  270. branch := branchPacketReceive;
  271. END;
  272. ELSE
  273. CASE command OF
  274. | Base.LOGIN:
  275. password := Base.BufGetString (receiveBuf, receiveBufOffset);
  276. IF users.PasswordCorrect (uin, password) THEN
  277. NEW (client);
  278. client.ip := ip;
  279. client.port := port;
  280. client.uin := uin;
  281. client.inSeqNum := seqNum;
  282. client.outSeqNum := 0;
  283. Kernel.SetTimer (client.keepAliveTimer, Base.clientKeepAliveAwait);
  284. clients.Add (client);
  285. Server_LoginReply (client, sendBuf, s);
  286. (* Now we will send client status to all other On-Line clients,
  287. and they statuses to this client *)
  288. MulticastStatus (clients, client, Base.USER_ONLINE, sendBuf, s);
  289. END;
  290. | Base.NEW_USER_REG:
  291. password := Base.BufGetString (receiveBuf, receiveBufOffset);
  292. shortName := Base.BufGetString (receiveBuf, receiveBufOffset);
  293. fullName := Base.BufGetString (receiveBuf, receiveBufOffset);
  294. eMail := Base.BufGetString (receiveBuf, receiveBufOffset);
  295. user := users.Add (password, shortName, fullName, eMail);
  296. Server_NewUserReply (ip, port, user.uin, seqNum, sendBuf, s);
  297. ELSE
  298. END;
  299. branch := branchPacketReceive;
  300. END;
  301. | branchPacketHandle:
  302. IF command = Base.ACK THEN
  303. IF Base.SeqNumInACKList (client.ACKList, seqNum, ACKReq) THEN
  304. client.ACKList.Remove (ACKReq);
  305. END;
  306. ELSIF Base.isNextSeqNum (seqNum, client.inSeqNum) THEN
  307. client.inSeqNum := seqNum;
  308. CASE command OF
  309. | Base.SEND_MESSAGE:
  310. Server_ACK (client, sendBuf, s);
  311. receiverUin := Base.BufGetLInt (receiveBuf, receiveBufOffset);
  312. messageType := Base.BufGetInt (receiveBuf, receiveBufOffset);
  313. message := Base.BufGetString (receiveBuf, receiveBufOffset);
  314. dt := Dates.Now ();
  315. IF receiverUin = 0 THEN
  316. MulticastMessage (clients, client, dt, messageType, message, sendBuf, s);
  317. ELSE
  318. IF FindClient (clients, receiverUin, receiver) THEN
  319. Server_ReceiveMessage (client, receiver, dt, messageType, message, sendBuf, s);
  320. ELSE
  321. (*
  322. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  323. *)
  324. END;
  325. END;
  326. | Base.KEEP_ALIVE:
  327. Server_ACK (client, sendBuf, s);
  328. Kernel.SetTimer (client.keepAliveTimer, Base.clientKeepAliveAwait);
  329. | Base.INFO_REQ:
  330. receiverUin := Base.BufGetLInt (receiveBuf, receiveBufOffset);
  331. user := users.Find (receiverUin);
  332. IF user # NIL THEN
  333. Server_InfoReply (client, user, sendBuf, s);
  334. END;
  335. | Base.SEND_TEXT_CODE:
  336. Server_ACK (client, sendBuf, s);
  337. textCode := Base.BufGetString (receiveBuf, receiveBufOffset);
  338. IF textCode^ = "USER_DISCONNECTED" THEN
  339. MulticastStatus (clients, client, Base.USER_OFFLINE, sendBuf, s);
  340. clients.Remove (client);
  341. ELSE
  342. (*
  343. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  344. *)
  345. END;
  346. ELSE
  347. END;
  348. END;
  349. branch := branchPacketReceive;
  350. | branchEnd:
  351. users.Store;
  352. FinalizeClients (clients);
  353. clients.Clear;
  354. BEGIN {EXCLUSIVE}
  355. terminated := TRUE
  356. END;
  357. branch := branchTerminated;
  358. ELSE
  359. END;
  360. UNTIL branch = branchTerminated;
  361. END Instance;
  362. VAR
  363. instance: Instance;
  364. PROCEDURE Log (type, code : SHORTINT; msg: ARRAY OF CHAR; showOnKernelLog : BOOLEAN);
  365. VAR message : Events.Message;
  366. BEGIN
  367. COPY(msg, message);
  368. Events.AddEvent(moduleName, type, EventClass, EventSubclass, code, message, showOnKernelLog);
  369. END Log;
  370. PROCEDURE Start* ;
  371. VAR
  372. s: UDP.Socket;
  373. res: WORD;
  374. str: ARRAY 256 OF CHAR;
  375. BEGIN
  376. IF instance = NIL THEN
  377. NEW (s, Base.serverPort, res);
  378. IF res = UDP.Ok THEN
  379. NEW (instance, s);
  380. Strings.IntToStr (Base.serverPort, str);
  381. Strings.Concat ("server started on port: ", str, str);
  382. Log (Events.Information, 0, str, TRUE);
  383. ELSE
  384. Log (Events.Error, 0, "server NOT started!", TRUE);
  385. END;
  386. END;
  387. END Start;
  388. PROCEDURE Stop*;
  389. BEGIN
  390. Cleanup;
  391. END Stop;
  392. (** Termination handler. *)
  393. PROCEDURE Cleanup;
  394. BEGIN
  395. IF instance # NIL THEN
  396. instance.Destroy;
  397. END;
  398. END Cleanup;
  399. BEGIN
  400. Modules.InstallTermHandler (Cleanup);
  401. END UDPChatServer.