em_server.rb 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. #!/usr/bin/env ruby
  2. require 'eventmachine'
  3. require 'digest/md5'
  4. require 'fiber'
  5. require 'geoip'
  6. require 'socket'
  7. require 'timeout'
  8. # .. allowed commands .. ROLES = CAPABILITIES
  9. # normal users have ROLE broadcast. Roles are defined on a per-user basis .. in a config.
  10. $version = "0.4em_cooldns_classes_for_caching"
  11. $debug = 0
  12. $role_commands = Hash[
  13. #noinspection RubyStringKeysInHashInspection
  14. 'everyone' => %w(PING WHO C PART),
  15. 'broadcast_admin' => %w(BC_ID BC BC_ENDCOUNT),
  16. 'broadcast' => %w(REQ_BC BC_RE),
  17. 'specbot_admin' => %w(REQ_ASSIGN REQ_UNASSIGN REQ_PING REQ_ASSIGNMENTS),
  18. 'specbot' => %w(ASSIGN_RE UNASSIGN_RE PING_RE ASSIGNMENTS_RE REQ_DNS),
  19. ]
  20. $default_role = "everyone"
  21. # which role is talking to which role?
  22. # effectively it says: this (local) command is sent to that (remote) topic .. that certain topic is read by that user with that role.
  23. $role_dialogs = Hash[
  24. #noinspection RubyStringKeysInHashInspection
  25. 'everyone' => %w(everyone),
  26. 'broadcast_admin' => %w(broadcast),
  27. 'broadcast' => %w(broadcast_admin),
  28. 'specbot_admin' => %w(specbot),
  29. 'specbot' => %w(specbot_admin),
  30. ]
  31. $user_roles = Hash[
  32. #noinspection RubyStringKeysInHashInspection
  33. 'paul_tester' => %w(everyone broadcast specbot specbot_admin),
  34. 'paul_dev_eggdrop' => %w(everyone broadcast),
  35. 'paul_eggdrop' => %w(everyone broadcast),
  36. 'paul_dev_specbot' => %w(everyone broadcast specbot),
  37. 'paul_specbot' => %w(everyone broadcast specbot),
  38. 'qw.nu' => %w(everyone broadcast),
  39. 'qw.nu_poster' => %w(everyone broadcast),
  40. 'mihawk_dev_specbot' => %w(everyone broadcast specbot),
  41. 'mihawk_specbot' => %w(everyone broadcast specbot),
  42. 'armitage_specbot' => %w(everyone broadcast specbot),
  43. 'blaze_specbot' => %w(everyone broadcast specbot),
  44. ]
  45. $qw_list = Array.new
  46. $qw_list = [
  47. "89.149.194.72:27700",
  48. "84.200.47.113:30000",
  49. "89.149.194.72:27500",
  50. "84.200.47.113:28502",
  51. "89.149.194.72:30000",
  52. "89.149.194.72:27600",
  53. "93.186.192.16:28502",
  54. "84.200.47.113:28501",
  55. "93.186.192.16:28501",
  56. "188.40.130.10:27502",
  57. "93.186.192.16:30000",
  58. "188.40.130.10:27599",
  59. "188.40.130.10:27503",
  60. "194.109.69.75:28000",
  61. "194.109.69.75:27500",
  62. "194.109.69.75:27501",
  63. "194.109.69.76:28504",
  64. "188.165.243.56:30000",
  65. "188.40.130.10:27501",
  66. "194.109.69.76:28502",
  67. "194.109.69.76:28501",
  68. "194.109.69.76:28503",
  69. "62.24.64.11:27501",
  70. "62.24.64.11:44444",
  71. "188.40.103.81:27600",
  72. "62.24.64.11:30000",
  73. "194.109.69.75:27502",
  74. "91.121.69.201:30000",
  75. "37.59.63.97:28504",
  76. "188.40.130.10:27500",
  77. "188.165.243.56:28009",
  78. "37.59.63.97:28501",
  79. "62.24.64.11:27500",
  80. "37.59.63.97:28503",
  81. "194.109.69.76:30000",
  82. "188.165.243.56:28008",
  83. "188.165.243.56:28006",
  84. "188.165.243.56:28001",
  85. "188.165.243.56:28002",
  86. "93.186.192.16:27500",
  87. "91.121.69.201:27600",
  88. "37.59.63.97:28502",
  89. "91.121.223.163:28001",
  90. "188.165.243.56:28003",
  91. "109.74.195.224:30000",
  92. "178.79.183.178:27500",
  93. "77.74.194.189:27501",
  94. "91.121.69.201:27502",
  95. "188.165.243.56:28007",
  96. "109.74.195.224:27500",
  97. "213.5.176.135:27502",
  98. "77.74.194.189:27504",
  99. "178.79.172.251:27600",
  100. "77.74.194.189:27502",
  101. "77.74.194.189:27503",
  102. "213.5.176.135:27500",
  103. "109.74.195.224:27501",
  104. "89.104.194.146:27504",
  105. "89.104.194.146:27503",
  106. "89.104.194.146:27508",
  107. "213.5.176.136:27510",
  108. "213.5.176.135:27501",
  109. "213.5.176.135:27503",
  110. "77.74.194.189:30000",
  111. "89.149.194.72:27800",
  112. "89.104.194.146:27502",
  113. "89.104.194.146:27666",
  114. "89.104.194.146:27507",
  115. "89.104.194.146:27509",
  116. "89.104.194.146:30000",
  117. "188.165.243.56:28004",
  118. "89.104.194.146:27500",
  119. "89.104.194.146:27501",
  120. "194.109.69.76:27500",
  121. "89.104.194.146:27506",
  122. "94.236.92.49:27501",
  123. "91.121.69.201:27501",
  124. "213.239.214.134:27500",
  125. "89.104.194.146:27510",
  126. "95.131.48.86:27502",
  127. "94.236.92.49:27500",
  128. "94.236.92.49:30000",
  129. "95.131.48.86:27504",
  130. "78.137.161.109:27501",
  131. "188.165.243.56:28005",
  132. "178.217.185.104:27500",
  133. "178.217.185.104:27600",
  134. "178.217.185.104:30000",
  135. "87.102.202.23:27502",
  136. "78.137.161.109:27500",
  137. "89.104.194.146:27505",
  138. "87.102.202.23:27505",
  139. "178.217.185.104:27501",
  140. "91.121.69.201:27500",
  141. "82.141.152.3:27501",
  142. "82.141.152.3:27500",
  143. "83.179.23.16:28002",
  144. "109.74.7.60:27500",
  145. "212.62.234.153:27502",
  146. "83.179.23.16:28003",
  147. "195.54.182.34:27500",
  148. "83.179.23.16:28005",
  149. "212.62.234.153:27503",
  150. "95.143.243.24:27600",
  151. "83.179.23.16:28001",
  152. "212.62.234.153:27504",
  153. "78.137.161.109:27502",
  154. "83.179.23.16:28004",
  155. "212.62.234.153:27501",
  156. "95.143.243.24:27500",
  157. "109.228.137.161:28501",
  158. "95.143.243.24:27900",
  159. "83.226.149.218:27500",
  160. "83.226.149.218:28001",
  161. "83.226.149.218:28002",
  162. "83.226.149.218:28003",
  163. "193.1.40.166:27975",
  164. "87.237.112.11:30000",
  165. "217.30.184.104:27500",
  166. "78.108.53.19:27500",
  167. "78.108.53.19:27501",
  168. "195.54.142.7:28001",
  169. "193.1.40.166:27500",
  170. "87.237.112.11:27501",
  171. "195.54.142.7:30000",
  172. "195.54.142.7:28007",
  173. "217.119.36.79:30000",
  174. "95.131.48.86:27501",
  175. "195.54.142.7:28002",
  176. "195.54.142.7:28008",
  177. "80.101.105.103:27500",
  178. "87.237.112.11:27502",
  179. "217.119.36.79:27500",
  180. "81.170.128.75:28501",
  181. "217.119.36.79:28001",
  182. "193.1.40.167:27500",
  183. "217.119.36.79:28003",
  184. "217.119.36.79:28002",
  185. "81.170.128.75:30000",
  186. "81.170.128.75:28504",
  187. "195.54.142.7:28005",
  188. "195.54.142.7:28010",
  189. "81.170.128.75:28503",
  190. "93.81.254.63:27502",
  191. "212.42.38.88:27504",
  192. "81.170.128.75:28502",
  193. "93.81.254.63:27500",
  194. "81.170.128.75:28000",
  195. "212.42.38.88:27500",
  196. "82.203.213.117:28002",
  197. "212.42.38.88:30000",
  198. "93.81.254.63:30000",
  199. "82.203.213.117:28001",
  200. "212.42.38.88:27501",
  201. "212.42.38.88:27503",
  202. "93.81.254.63:27503",
  203. "93.81.254.63:27501",
  204. "82.203.213.117:30000",
  205. "95.131.48.86:27503",
  206. "83.252.244.76:27500",
  207. "212.42.38.88:27502",
  208. "195.54.142.7:28003",
  209. "95.31.4.132:30000",
  210. "83.252.244.76:27501",
  211. "93.81.254.63:30001",
  212. "195.54.142.7:28006",
  213. "82.203.213.117:28003",
  214. "95.143.243.24:27700",
  215. "84.234.185.215:27503",
  216. "84.234.185.215:27500",
  217. "84.234.185.215:27519",
  218. "84.234.185.215:27508",
  219. "84.234.185.215:27506",
  220. "84.234.185.215:27505",
  221. "195.54.142.7:28004",
  222. "84.234.185.215:27501",
  223. "195.54.142.7:28009",
  224. "212.109.128.148:27501",
  225. "84.234.185.215:27502",
  226. "31.209.7.104:28501",
  227. "194.79.85.66:27501",
  228. "194.79.85.66:30000",
  229. "95.84.164.245:27501",
  230. "194.79.85.66:27502",
  231. "83.222.112.157:30000",
  232. "212.109.128.148:27500",
  233. "94.100.6.66:27500",
  234. "129.241.205.153:28000",
  235. "84.234.185.215:27507",
  236. "129.241.205.153:27500",
  237. "95.84.164.245:27500",
  238. "69.31.82.226:27501",
  239. "69.31.82.226:30000",
  240. "130.240.207.177:30000",
  241. "69.31.82.226:28100",
  242. "69.31.82.226:27500",
  243. "69.31.82.226:28101",
  244. "69.31.82.226:28010",
  245. "69.31.82.226:30001",
  246. "69.31.82.226:28000",
  247. "69.31.82.226:28002",
  248. "93.186.192.16:28000",
  249. "195.222.130.83:27500",
  250. "84.200.47.113:28000",
  251. "130.85.56.131:27500",
  252. "108.174.51.73:28003",
  253. "96.8.113.36:27501",
  254. "96.8.113.36:27500",
  255. "68.100.130.114:27501",
  256. "65.31.69.75:27500",
  257. "108.174.51.73:28006",
  258. "65.31.69.75:27508",
  259. "108.174.51.73:30000",
  260. "67.81.59.41:27500",
  261. "108.174.51.73:28004",
  262. "217.18.138.23:27505",
  263. "108.174.51.73:28001",
  264. "68.100.130.114:27500",
  265. "174.49.198.60:27502",
  266. "174.49.198.60:27503",
  267. "209.239.113.236:27500",
  268. "174.49.198.60:27515",
  269. "217.119.36.79:28000",
  270. "108.174.51.73:28005",
  271. "74.91.115.244:28001",
  272. "174.49.198.60:27500",
  273. "74.91.115.244:28000",
  274. "199.101.96.48:27501",
  275. "96.8.113.36:30000",
  276. "174.101.185.59:27500",
  277. "67.228.69.114:27502",
  278. "199.101.96.48:27500",
  279. "108.174.51.73:28002",
  280. "199.192.229.74:28001",
  281. "74.86.171.201:27502",
  282. "67.228.69.114:27501",
  283. "74.86.171.201:27500",
  284. "67.228.69.114:26666",
  285. "199.192.228.71:27501",
  286. "199.192.229.74:28003",
  287. "74.86.171.201:27501",
  288. "199.192.229.74:30000",
  289. "199.192.229.74:28002",
  290. "74.91.115.244:28002",
  291. "199.192.228.71:27500",
  292. "199.101.96.48:30000",
  293. "199.101.96.48:28000",
  294. "199.192.229.74:28004",
  295. "199.192.228.71:30000",
  296. "65.31.238.37:27500",
  297. "31.209.7.104:28000",
  298. "208.131.136.169:27500",
  299. "66.212.17.78:27500",
  300. "200.177.229.11:27510",
  301. "200.177.229.11:27522",
  302. "200.177.229.11:27521",
  303. "200.177.229.11:27500",
  304. "190.96.80.67:27500",
  305. "200.177.229.11:27511",
  306. "200.177.229.11:27520",
  307. "190.96.80.67:27000",
  308. "202.37.129.186:27500",
  309. "202.37.129.186:27505",
  310. "202.37.129.186:27501",
  311. "219.88.241.81:27500",
  312. "202.172.99.2:28001",
  313. "202.172.99.2:28002",
  314. "202.172.99.2:28003",
  315. "202.172.99.2:27500",
  316. "210.50.4.11:27501",
  317. "202.172.99.2:27501",
  318. "210.50.4.11:27508",
  319. "210.50.4.11:27511",
  320. "210.50.4.11:27509",
  321. "210.50.4.11:27510",
  322. "122.99.118.2:28001",
  323. "210.50.4.11:27500",
  324. "210.50.4.11:27503",
  325. "210.50.4.11:27506",
  326. "210.50.4.11:27505",
  327. "210.50.4.11:27504",
  328. ]
  329. class GameServers
  330. attr_accessor :gameservers # now, @gameservers is accessible via GameServers.gameservers
  331. def initialize
  332. @gameservers = Hash.new
  333. @gameservers.default = {
  334. :reverse_dns => "",
  335. :hostname_dns => "",
  336. :cool_dns => "",
  337. :type => "",
  338. :serverinfos => "",
  339. :timestamp => 0,
  340. }
  341. @gameservers["blah:blah"]
  342. wat = Hash.new(@gameservers["blah:blah"])
  343. wat
  344. wat.store(:reverse_dns, "6")
  345. @gameservers.merge(wat)
  346. p @gameservers
  347. p @gameservers.default
  348. wat = Hash.new(@gameservers["blah:blah"])
  349. wat
  350. wat.store(:hostname_dns, "12")
  351. @gameservers.merge(wat)
  352. p @gameservers
  353. p @gameservers.default
  354. end
  355. def scanserver(iphostport, type="qw", force=false)
  356. put_log "scanserver drin"
  357. if iphostport =~ /^(\d+\.\d+\.\d+\.\d+):(\d{1,5})/
  358. iphost = $1
  359. ipport = $2
  360. if type == "qw"
  361. #p current
  362. # check if it already exists
  363. #if @gameservers["#{iphost}:#{ipport}"][:timestamp] > 0
  364. # if old general data, then freshly get general data...
  365. # if @gameservers["#{iphost}:#{ipport}"][:timestamp] + 60 * 60 * 20 < Time.now.utc.to_i || force == true
  366. # end # of old
  367. #else
  368. current = Hash.new
  369. serverinfos = qwstatus(iphost, ipport)
  370. current.store(:serverinfos, serverinfos)
  371. current.store(:reverse_dns, find_reverse_dname(iphost))
  372. current.store(:hostname_dns, qw_find_dname_by_serverinfos(serverinfos))
  373. current.store(:type, "qw")
  374. # set new timestamp
  375. current.store(:timestamp, Time.now.utc.to_i)
  376. @gameservers.store("#{iphost}:#{ipport}", current) # save it all.
  377. current.store(:cool_dns, find_cooldns(iphost, ipport))
  378. @gameservers.store("#{iphost}:#{ipport}", current) # save it all.
  379. #put_log "the saved one: #{@gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)}"
  380. #puts "ALL"
  381. #p @gameservers
  382. #puts "DEFAULT of the hash"
  383. #p @gameservers.default
  384. #end
  385. end # of type qw
  386. end # of check form of iphostport parameter
  387. end # of scan()
  388. def scanserverlist(gs_array, type="qw")
  389. put_log "scanserverlist drin"
  390. gs_array.each do
  391. |gserver|
  392. scanserver(gserver, type)
  393. end
  394. put_log "End of scanning."
  395. put_log "foppa: #{@gameservers.fetch("89.104.194.146:27503")} "
  396. end # of scanserverlist()
  397. def get_cool_dns(iphost, ipport)
  398. put_log "get_cool_dns drin"
  399. @gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)
  400. rescue
  401. scanserver("#{iphost}:#{ipport}", "qw")
  402. @gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)
  403. end
  404. private # all following methods are private
  405. # returns serverinfo hash
  406. def qwstatus(iphost, ipport)
  407. put_log "qwstatus drin"
  408. udp_payload = [0xFF, 0xFF, 0xFF, 0xFF]
  409. udp_payload.concat(string2bytearray("status 23"))
  410. udp_payload.concat([0x0a]) # linefeed at the end
  411. udp_payload = udp_payload.pack("C*")
  412. #p udp_payload
  413. Timeout::timeout(2) do
  414. begin
  415. u2 = UDPSocket.new
  416. #put_log "#{iphost} #{ipport} #{udp_payload}"
  417. u2.send(udp_payload, 0, iphost, ipport)
  418. #put_log "sent"
  419. the_return = u2.recv(500)
  420. u2.close
  421. #put_log "muh #{the_return}"
  422. if the_return =~ /\W\W\W\Wn\\(.+)$/
  423. line = $1
  424. #put_log "line #{line}"
  425. matches = line.scan(/(.+?)\\(.+?)(\\|$)/)
  426. the_hash = Hash.new
  427. matches.each {
  428. |k, v, _|
  429. the_hash[k] = "#{v}"
  430. }
  431. return the_hash
  432. else
  433. return false
  434. end
  435. rescue Exception => e
  436. puts e.message
  437. end # of begin
  438. end # of Timeout
  439. end
  440. def find_cooldns_full(iphost, ipport)
  441. targetname = iphost
  442. # resolve it to a dns name (reverse lookup)
  443. if targetname == iphost # if it is still default
  444. put_log "Ip not resolved .. we try hostname dns finder"
  445. targetname = qw_find_dname_in_hostnames(iphost, ipport)
  446. end
  447. # resolve it to a dns name (reverse lookup)
  448. if targetname == iphost
  449. put_log "Still no resolve .. we try reverse dns lookup"
  450. targetname = find_reverse_dname(iphost)
  451. end
  452. return targetname
  453. end
  454. def find_cooldns(iphost, ipport)
  455. put_log "find_cooldns drin"
  456. current = @gameservers["#{iphost}:#{ipport}"] # only use this for reading...
  457. my_cooldns = iphost
  458. # we still haven't found a cool dns
  459. if (my_cooldns == iphost) && (not current[:hostname_dns].to_s.empty?)
  460. put_log "Try if #{current[:hostname_dns]} resolves to #{iphost}"
  461. begin
  462. ip_of_hostnamedns = Resolv.getaddress(current[:hostname_dns])
  463. if ip_of_hostnamedns && (ip_of_hostnamedns == iphost)
  464. # ok, we take it.
  465. put_log "Ok, we take #{current[:hostname_dns]} for #{iphost} here.."
  466. my_cooldns = current[:hostname_dns]
  467. else
  468. put_log "Found #{current[:hostname_dns]} but #{ip_of_hostnamedns} is not #{iphost}"
  469. end
  470. rescue Exception => e
  471. my_cooldns = iphost
  472. end
  473. end
  474. # we still haven't found a cool dns
  475. unless current[:reverse_dns].to_s.empty?
  476. if my_cooldns == iphost
  477. rdns = current[:reverse_dns]
  478. # if the resulting dns name...
  479. # .. is too long, use ip-address instead.
  480. # .. has too many dots, use ip-address instead.
  481. # .. has too many numbers, use ip-address instead.
  482. if rdns.length > 21 || rdns.split(".").size > 3 || rdns.scan(/\d/).size > 3
  483. put_log "cutting down host_name: #{rdns}, because:"
  484. put_log "length: #{rdns.length}"
  485. put_log "chunks count: #{rdns.split(".").size}"
  486. put_log "num count: #{rdns.scan(/\d/).size}"
  487. else
  488. my_cooldns = rdns
  489. end # of Resolv.getname
  490. end
  491. end
  492. put_log "COOOOOOOOOOOOLDNS: #{my_cooldns}"
  493. my_cooldns
  494. end
  495. def find_reverse_dname(iphost)
  496. put_log "find_reverse_dname drin"
  497. dname = Resolv.getname(iphost)
  498. ip_of_dname = Resolv.getaddress(dname)
  499. if ip_of_dname == iphost
  500. return dname
  501. end
  502. rescue
  503. iphost
  504. end
  505. def qw_find_dname_by_udp(iphost, ipport)
  506. targetname = iphost # set a default
  507. # get hostname from a qw status packet! perhaps there's a DNS name inside, which we can use!
  508. status = qwstatus(iphost, ipport)
  509. p status
  510. if status["hostname"] =~ /([\w\.-]{3,}\.\w{2,4})/
  511. hostnamedns = $1.downcase
  512. begin
  513. ip_of_hostnamedns = Resolv.getaddress(hostnamedns)
  514. if ip_of_hostnamedns && (ip_of_hostnamedns == iphost)
  515. # ok, we take it.
  516. put_log "Ok, we take #{hostnamedns} for #{iphost} here.."
  517. targetname = hostnamedns
  518. else
  519. put_log "Found #{hostnamedns} but #{ip_of_hostnamedns} is not #{iphost}"
  520. end
  521. rescue Exception => e
  522. targetname = iphost
  523. end
  524. end
  525. targetname
  526. end
  527. def qw_find_dname_by_serverinfos(serverinfos)
  528. hostnamedns = ""
  529. begin
  530. hostname = serverinfos.fetch("hostname")
  531. if hostname =~ /([\w\.-]{3,}\.\w{2,4})/
  532. hostnamedns = $1.downcase
  533. end
  534. return hostnamedns
  535. rescue
  536. return ""
  537. end
  538. end
  539. end # of Class GameServers!
  540. def string2bytearray(text)
  541. return_array = Array.new
  542. text.each_byte{
  543. |b|
  544. return_array.push(b)
  545. }
  546. return_array
  547. end
  548. def put_log(msg)
  549. puts "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")}: #{msg}"
  550. end
  551. module CentralProtocolHandler
  552. @@connected_clients = Array.new
  553. @@broadcasts = Hash.new
  554. put_log "Server started"
  555. # default method that is being run on connection!
  556. def post_init # connection of someone starts here...
  557. @username = nil
  558. end
  559. ### getters
  560. def entered_username?
  561. !@username.nil? && !@username.empty? # then it's true
  562. end
  563. def username
  564. @username
  565. end
  566. def my_roles
  567. $user_roles[@username]
  568. end
  569. def my_cmds
  570. my_roles.collect {|v| $role_commands[v]}.flatten
  571. end
  572. # returns online users by default by searching through saved connections
  573. def ousers
  574. users = Array.new
  575. @@connected_clients.each {|c| users.push(c.username)}
  576. users
  577. end # of ousers
  578. ### checkers
  579. def allowed_cmd(inputmessage)
  580. my_cmds.each{|c|
  581. #print "A #{c} B #{inputmessage}\n"
  582. if inputmessage =~ /^#{c}/
  583. return true
  584. end
  585. }
  586. false
  587. end
  588. def online(user)
  589. if ousers.include? user
  590. true
  591. else
  592. false
  593. end
  594. end
  595. ### actions
  596. # searches through our hash of saved connections and writes them a messages.
  597. def write_user(input, username = nil)
  598. if username.nil? || username.empty?
  599. username = @username
  600. end
  601. if @@connected_clients.find { |c| c.username == username }
  602. connection = @@connected_clients.find { |c| c.username == username }
  603. put_log("to #{username}: #{input}")
  604. sometime = "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S %z")}"
  605. line = "#{sometime}: #{input}\n"
  606. connection.send_data line
  607. end
  608. end # of write_user
  609. # searches through roles and writes those users on their connections
  610. def write_role(role, input, *exempts)
  611. #find users with role
  612. users = Array.new
  613. $user_roles.each {|k, v|
  614. if v.include? role
  615. users.push(k)
  616. end
  617. }
  618. # find users that are online and inside Array "users"
  619. lala = Array.new
  620. users.each {|v|
  621. if ousers.include? v
  622. lala.push(v)
  623. end
  624. }
  625. # now write to them
  626. lala.each {|user|
  627. if not exempts.include? user
  628. write_user(input, user)
  629. end
  630. }
  631. end # of write_role()
  632. # what happens with what input?!
  633. def inputting(input)
  634. put_log("SYS #{@username} typed: #{input}")
  635. #write_user("SYS You typed: #{input}")
  636. if input =~ /^([A-Z_]+)/
  637. cmd = $1
  638. end
  639. # now we have the cmd .. or not ;)
  640. if input =~ /^[A-Z_]+ (.+)/
  641. payload = $1
  642. end
  643. # now we can use payload
  644. if allowed_cmd(cmd)
  645. ### typical system commands follow
  646. if cmd == "PING"
  647. write_user("PONG")
  648. elsif cmd == "C"
  649. if payload =~ /^(.+)$/
  650. write_role($default_role, "C #{@username}: #{$1}")
  651. else
  652. write_user("SYS Format is C <chattext>")
  653. end
  654. elsif cmd == "WHO"
  655. ousers.each {|ouser| write_user("WHO_RE #{ouser} ROLES: #{$user_roles[ouser].join(", ")}")}
  656. elsif cmd == "PART"
  657. write_user("SYS Goodbye '#{@username}'.")
  658. write_role($default_role, "PARTED User '#{@username}' leaves the party.", @username)
  659. return "bye"
  660. ###now for the good stuff, broadcasting
  661. elsif cmd == "REQ_BC"
  662. # help with format .. but send the raw payload
  663. if payload =~ /^(.+),(.+),(.+),'(.+)','(.+)'$/
  664. # n f s ni txt
  665. error = 0
  666. # $&
  667. # The string matched by the last successful pattern match in this scope, or nil if the last pattern match failed. (Mnemonic: like & in some editors.) This variable is r
  668. network = $1
  669. freqname = $2
  670. source = $3
  671. nickname = $4
  672. text = $5
  673. if not network =~ /^(QWalt)|(QDEV)/
  674. write_user("SYS Network name #{network} is unknown: QWalt or QDEV allowed.")
  675. error = 1
  676. end
  677. if not freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
  678. write_user("SYS Frequency name is unknown #{freqname}")
  679. error = 1
  680. end
  681. if source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
  682. else
  683. write_user("SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/) was: #{source}")
  684. error = 1
  685. end
  686. if not nickname =~ /^.+/
  687. write_user("SYS Nickname string is not in the form ^.+ #{nickname}")
  688. error = 1
  689. end
  690. if not text =~ /^.+/
  691. write_user("SYS Message string is not in the form ^.+ #{text}")
  692. error = 1
  693. end
  694. else # of payload has format
  695. write_user("SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'")
  696. error = 1
  697. end # of payload has format
  698. if error == 0
  699. # send REQ_BC to the corresponding role.
  700. bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
  701. # so it only reaches the issuer of REQ_BC
  702. write_user("BC_ID #{bcid} for: #{network},#{freqname},#{source}")
  703. @@broadcasts[bcid] = @username
  704. # qw:// ip resolving
  705. if source =~ /^qw:\/\/(.+):(\d+)(.*)$/
  706. # ip address is 15 in length
  707. iphost = $1
  708. targetname = iphost # set a default
  709. ipport = $2
  710. rest = $3
  711. if iphost =~ /^\d+\.\d+\.\d+\.\d+/
  712. targetname = $gs.get_cool_dns(iphost, ipport)
  713. # find country code
  714. cc = GeoIP.new('GeoIP.dat').country(iphost)[3].to_s.downcase
  715. rest.prepend " #{cc}" unless cc.nil? || cc.empty? || targetname =~ /\.#{cc}$/
  716. end # if ip is x.x.x.x
  717. source = "qw://#{targetname}:#{ipport}#{rest}"
  718. end # of if source qw://x.x.x.x:portzzz
  719. # resolve
  720. finalmessage = "BC %s %s,%s,%s,'%s','%s'" % [bcid, network, freqname, source, nickname, text]
  721. write_role("broadcast", finalmessage, @username) # write to the role with the exempt of myself.
  722. end
  723. #end of REQ_BC here..
  724. elsif cmd == "REQ_DNS"
  725. # help with format .. but send the raw payload
  726. if payload =~ /^(\d+\.\d+\.\d+\.\d+):(\d{1,5})/
  727. iphost = $1
  728. ipport = $2
  729. targetname = $gs.get_cool_dns(iphost, ipport)
  730. write_user("DNS_RE #{iphost}:#{ipport} #{targetname}") # write back to asking user.
  731. else # of payload has format
  732. write_user("SYS Command format is REQ_DNS <serverip>:<serverport>")
  733. error = 1
  734. end # of if payload has format
  735. #end of REQ_DNS here..
  736. elsif cmd == "BC_RE"
  737. if payload =~ /^(.+) (.+)=(\d+),(.+)=(\d+)$/
  738. bcid = $1
  739. user_string = $2
  740. user_count = $3
  741. item_string = $4
  742. item_count = $5
  743. payload = "%s %s=%d,%s=%d" % [bcid, user_string, user_count, item_string, item_count]
  744. # according bcid it is possible to get the originating user.. so send only to his topic!
  745. if @@broadcasts[bcid]
  746. to_user = @@broadcasts[bcid]
  747. write_user("SYS Broadcast reply bcid: #{bcid} underway to #{to_user}.")
  748. write_user("#{cmd} #{payload}", to_user)
  749. else
  750. write_user("SYS Broadcast reply bcid: #{bcid} underway.")
  751. write_role("broadcast", "#{cmd} #{payload}", @username)
  752. end
  753. else # of bc_re format check
  754. put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
  755. end
  756. end
  757. else # of if allowed command
  758. if input.length > 15
  759. input = input.slice(0,14) + ".."
  760. end
  761. write_user("SYS Command '#{input}' not allowed, your commands are: #{my_cmds.join(", ")}.")
  762. end # of if allowed command
  763. end # of inputting!
  764. # default method that is being run on receiving data!
  765. def receive_data(data) # connection receives a line on the server end
  766. data = data.chomp unless data.chomp.nil?
  767. data.each_line do |line|
  768. unless line.empty?
  769. if entered_username? # oh, it's a known user
  770. # it's alive! kill ping timer, set a new one:
  771. if @ping_timer
  772. EventMachine.cancel_timer(@ping_timer)
  773. end
  774. @ping_timer = EventMachine.add_periodic_timer 180, proc { write_user("PING alive?") }
  775. # work on input
  776. inputter = inputting(line)
  777. if inputter == "bye"
  778. close_connection
  779. end
  780. else # of username known, then it seems to be the first connect
  781. # and this line is the user name coming in!
  782. username = line
  783. if online(username)
  784. put_log "SYS User '#{username}' tried to double connect. Say bye bye."
  785. send_data "SYS Hey '#{username}', only one connection allowed. Bye.\n"
  786. EventMachine.add_timer 1, proc {
  787. write_user("PING check forced", username)
  788. close_connection
  789. }
  790. return false
  791. end
  792. if $user_roles.any? {|k| k.include? username}
  793. @username = username
  794. @@connected_clients.push(self)
  795. @ping_timer = EventMachine.add_periodic_timer 90, proc { write_user("PING alive?") }
  796. # starting a pinger
  797. put_log("SYS '#{@username}' connected. Online now: #{ousers.join(", ")}")
  798. write_user("HELLO Hi user '#{@username}'! How are you? I'm '#{$version}'")
  799. write_user("ROLES #{my_roles.join(", ")}")
  800. write_user("COMMANDS #{my_cmds.join(", ")}")
  801. write_role($default_role, "JOINED User '#{@username}' just joined the party.", @username)
  802. else
  803. put_log "SYS User '#{username}' unknown to me. Saying bye."
  804. send_data "SYS User '#{username}' unknown to me. Bye.\n"
  805. # disconnect him
  806. close_connection
  807. end
  808. end # of username known
  809. end # of unless line.empty?
  810. end # of data.each_line
  811. end # of receive data
  812. # default method that is being run on disconnection!
  813. def unbind # a connection goes bye bye
  814. if @username
  815. @@connected_clients.delete(self)
  816. if @ping_timer
  817. EventMachine.cancel_timer(@ping_timer)
  818. end
  819. put_log "SYS '#{@username}' disconnected."
  820. write_role($default_role, "SYS User '#{@username}' disconnected.", @username)
  821. end
  822. put_log "SYS Online users now: #{ousers.join(", ")}"
  823. end
  824. end
  825. def main
  826. # #run: Note that this will block current thread.
  827. $gs = GameServers.new
  828. EventMachine.run do
  829. # initial scan
  830. EM.defer do
  831. $gs.scanserverlist($qw_list, "qw") # initial scan
  832. end
  833. # periodic scan, 20 hours
  834. EventMachine.add_periodic_timer( 60 * 60 * 20 ) {
  835. EM.defer do
  836. $gs.scanserverlist($qw_list, "qw") # initial scan
  837. end
  838. }
  839. EventMachine.start_server("0.0.0.0", 7337, CentralProtocolHandler)
  840. end
  841. end # of main
  842. main