Connection.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define CONNECTION_CC4 CC4('E','E','N','C') // Esenthel Engine Network Connection
  6. #define CONNECTION_VERSION 0
  7. #define MSG_SIZE_KNOWN 0xFF
  8. #define SEND_WAIT_TIME (15*1000)
  9. #define LOG_ERROR 0
  10. #if LOG_ERROR
  11. #pragma message("!! Warning: Use this only for debugging !!")
  12. #endif
  13. /******************************************************************************/
  14. // CONNECTION
  15. /******************************************************************************/
  16. Connection& Connection::del()
  17. {
  18. if(_state==CONNECT_GREETED)flush(0); // if we were connected then flush any data, don't attempt to flush in other states (like sending a greeting for example)
  19. _state =CONNECT_INVALID;
  20. _birth =0;
  21. _msg_size_progress=0;
  22. _msg_size =0;
  23. _socket.del();
  24. _out .del();
  25. data .del();
  26. // don't clear '_in_offset' '_out_offset' '_address' as they may be called after connection got deleted (deletion may occur upon error/connection lost and we want to keep the stats even after that)
  27. return T;
  28. }
  29. Bool Connection::serverAcceptClient(Socket &server)
  30. {
  31. del();
  32. _in_offset=_out_offset=0; // clear at this stage because it's needed before 'greet', also make sure to always clear at connection time for stats usage
  33. if(server.accept(_socket, _address))
  34. {
  35. _socket.block(false);
  36. _birth=Time.curTimeMs();
  37. return greet();
  38. }
  39. return false;
  40. }
  41. Connection& Connection::clientConnectToServer(C SockAddr &server_addr)
  42. {
  43. del();
  44. _in_offset=_out_offset=0; // clear at this stage because it's needed before 'greet', also make sure to always clear at connection time for stats usage
  45. if(_socket.createTcp(server_addr))
  46. {
  47. _socket.block(false);
  48. _address=server_addr;
  49. _birth =Time.curTimeMs();
  50. switch(_socket.connect(server_addr, 0))
  51. {
  52. case Socket::FAILED : del(); break;
  53. case Socket::CONNECTED : greet(); break; // 'greet' sets the '_state'
  54. case Socket::IN_PROGRESS: _state=CONNECT_CONNECTING; break;
  55. }
  56. }
  57. return T;
  58. }
  59. /******************************************************************************/
  60. UInt Connection::life()C
  61. {
  62. return (_state!=CONNECT_INVALID) ? Time.curTimeMs()-_birth : 0; // this code was tested OK for UInt overflow
  63. }
  64. /******************************************************************************/
  65. Bool Connection::greet()
  66. {
  67. _out .writeMem(4*1024);
  68. data.writeMem(4*1024);
  69. _cipher.randomizeKey();
  70. // since we need to know the size of the cipher key up-front, first let's save it to 'data'
  71. if(!_cipher.saveKey(data))goto error;
  72. _out.cmpUIntV(4+1+data.size() ); // message length
  73. _out.putUInt (CONNECTION_CC4 ); // 4
  74. _out.putByte (CONNECTION_VERSION); // 1
  75. data.pos(0); data.copy(_out); data.reset(); // cipher key
  76. _out.pos(0);
  77. _state=CONNECT_AWAIT_GREET;
  78. if(flush())return true;
  79. error:
  80. del(); return false;
  81. }
  82. /******************************************************************************/
  83. Bool Connection::flush(Int timeout)
  84. {
  85. for(;;)
  86. {
  87. if(_out.end()){_out.reset(); return true;} // all data was sent
  88. if(!_socket.flush((timeout<0) ? SEND_WAIT_TIME : timeout))return false; // socket is busy
  89. if(timeout>0)timeout=0; // don't wait for next steps
  90. Byte buf[(64+1)*1024]; // 1 extra for the headers
  91. Int left=Min(SIZEI(buf), _out.left()); if(!_out.get(buf, left))break; if(_state==CONNECT_GREETED)_cipher.encrypt(buf, buf, left, _out_offset); // read data
  92. Int sent=_socket.send(buf, left); // send data
  93. if(sent<0 || sent>left)sent=0; // if an error occurred then clear sent. "sent==0" is also an error, but in this statement we don't need to change sent=0 -> 0
  94. if(_state==CONNECT_GREETED)_out_offset+=sent;
  95. if(left!=sent) // if haven't sent everything
  96. {
  97. _out.skip(sent-left); // go back the amount of bytes that weren't sent
  98. if(!sent) // if nothing was sent
  99. {
  100. if(Socket::WouldBlock()) // this can happen if data doesn't fit in the buffer
  101. {
  102. if(timeout<0)continue; // if we have unlimited timeout, then try again
  103. return false; // flush failed, but don't delete
  104. }
  105. break; // break so we can delete
  106. }
  107. }
  108. }
  109. _state=CONNECT_INVALID; // this will prevent calling 'flush' in the 'del' method
  110. del(); return false;
  111. }
  112. Bool Connection::flushEx(Int timeout)
  113. {
  114. return flush() && _socket.flush((timeout<0) ? SEND_WAIT_TIME : timeout);
  115. }
  116. /******************************************************************************/
  117. Bool Connection::updateEx(Int timeout, Bool read)
  118. {
  119. UInt end_time; // this function was tested OK for UInt overflow
  120. Bool adjust_time; // if adjust 'timeout' based on 'Time.curTimeMs' and 'end_time' before making some func call
  121. switch(_state)
  122. {
  123. case CONNECT_CONNECTING:
  124. {
  125. if(timeout>0)end_time=Time.curTimeMs()+timeout;
  126. if(_socket.any(timeout) && greet()){adjust_time=true; goto read_data;} // connected
  127. if(_socket.connectFailed())goto error;
  128. }break;
  129. case CONNECT_GREETED:
  130. {
  131. if(!read) // if we're not going to try and read a message (which can detect disconnects), then we have to at least check if we've got disconnected
  132. {
  133. if(_socket.wait(0) && _socket.available()<=0) // connection lost
  134. {
  135. #if LOG_ERROR
  136. LogN(S+"Connection.updateEx 0:"+PLATFORM(WSAGetLastError(), errno)+", available:"+_socket.available());
  137. #endif
  138. _state=CONNECT_INVALID; goto error; // set '_state' to prevent calling 'flush' in the 'del' method
  139. }
  140. return true;
  141. } // otherwise continue below
  142. case CONNECT_AWAIT_GREET:
  143. // in this section only 'end_time' and 'adjust_time' should be set
  144. if(timeout>0){end_time=Time.curTimeMs()+timeout; adjust_time=false;}
  145. // in this section only 'end_time' and 'adjust_time' should be set
  146. read_data:
  147. for(; _msg_size_progress!=MSG_SIZE_KNOWN; ) // unknown packet size
  148. {
  149. if(timeout>0)if(adjust_time)MAX(timeout=end_time-Time.curTimeMs(), 0);else adjust_time=true;
  150. if(!_socket.wait(timeout))return false; // if there's no data yet then abort
  151. Byte b; Int l=_socket.receive(&b, 1); // '_msg_size' is compressed using 'File.cmpUIntV', so we need to decompress it byte by byte until last read byte doesn't have the last bit enabled (b&128)
  152. if(l!=1) // connection lost
  153. {
  154. #if LOG_ERROR
  155. LogN(S+"Connection.updateEx 1:"+PLATFORM(WSAGetLastError(), errno)+", receive:"+l);
  156. #endif
  157. _state=CONNECT_INVALID; goto error; // set '_state' to prevent calling 'flush' in the 'del' method
  158. }
  159. if(_state==CONNECT_GREETED){_cipher.decrypt(&b, &b, 1, _in_offset); _in_offset++;} // decrypt
  160. _msg_size|=((b&127)<<(_msg_size_progress*7)); // each step grants knowledge of 7 bits
  161. if(b&128)_msg_size_progress++;else // need more info
  162. {
  163. data.reset(); // reset for upcoming data
  164. _msg_size_progress=((_msg_size<=0) ? 0 : MSG_SIZE_KNOWN); // if the message size was zero, then ignore it, and read the next one
  165. }
  166. }
  167. if(_msg_size_progress==MSG_SIZE_KNOWN)for(; _msg_size>0; ) // we await data
  168. {
  169. if(timeout>0)if(adjust_time)MAX(timeout=end_time-Time.curTimeMs(), 0);else adjust_time=true;
  170. if(!_socket.wait(timeout))return false; // if there's no data yet then abort
  171. Byte buf[65536];
  172. Int want=Min(SIZEU(buf), _msg_size),
  173. got =_socket.receive(buf, want);
  174. if( got<=0 || got>want) // connection lost
  175. {
  176. #if LOG_ERROR
  177. LogN(S+"Connection.updateEx 2:"+PLATFORM(WSAGetLastError(), errno)+", receive:"+got);
  178. #endif
  179. _state=CONNECT_INVALID; goto error; // set '_state' to prevent calling 'flush' in the 'del' method
  180. }
  181. if(_state==CONNECT_GREETED){_cipher.decrypt(buf, buf, got, _in_offset); _in_offset+=got;} // decrypt
  182. data.put(buf, got);
  183. _msg_size-=got;
  184. if(_msg_size<=0) // we've received entire message
  185. {
  186. _msg_size_progress=0;
  187. data.pos(0);
  188. if(_state==CONNECT_AWAIT_GREET)
  189. {
  190. if(data.getUInt()!=CONNECTION_CC4 )goto error;
  191. if(data.getByte()!=CONNECTION_VERSION){del()._state=CONNECT_VERSION_CONFLICT; return false;}
  192. if(!_cipher.mixKey(data) )goto error;
  193. if(!data.end() )goto error; // there should be no data left after the cipher key
  194. _state=CONNECT_GREETED;
  195. data.reset(); // don't leave the greeting for the user
  196. if(read)goto read_data; // here we've only greeted, however if we want an actual message, then try again
  197. // proceed below to return 'true' as success
  198. }
  199. return true; // return this message to the user
  200. }
  201. }
  202. }break;
  203. }
  204. return false;
  205. error:
  206. del(); return false;
  207. }
  208. Bool Connection::updateState(Int timeout) {return updateEx(timeout, false);}
  209. Bool Connection::receive (Int timeout) {return updateEx(timeout, true );}
  210. /******************************************************************************/
  211. Bool Connection::send(CPtr buf, Int size, Bool flush)
  212. {
  213. if(size>0 && _state==CONNECT_GREETED)
  214. {
  215. Int pos=_out.pos(); _out.pos(_out.size());
  216. _out.cmpUIntV(size);
  217. _out.put (buf, size); // size
  218. _out.pos (pos);
  219. return flush ? T.flush() : true;
  220. }
  221. return size==0;
  222. }
  223. Bool Connection::send(File &f, Int size, Bool flush)
  224. {
  225. if(size<0)size=f.left();
  226. if(size>0 && _state==CONNECT_GREETED)
  227. {
  228. Int pos=_out.pos(); _out.pos(_out.size());
  229. _out.cmpUIntV(size);
  230. for(; size>0; )
  231. {
  232. Byte buf[65536];
  233. Int l=Min(SIZEU(buf), size);
  234. f .get(buf, l);
  235. _out.put(buf, l); // size
  236. size-=l;
  237. }
  238. _out.pos(pos);
  239. return flush ? T.flush() : true;
  240. }
  241. return size==0;
  242. }
  243. /******************************************************************************/
  244. // FAST CONNECTION
  245. /******************************************************************************/
  246. void FastConnection::del()
  247. {
  248. _socket.del();
  249. // don't clear '_sent' '_received' so they can be read after connection is deleted
  250. }
  251. Bool FastConnection::create(Int port)
  252. {
  253. del(); _sent=_received=0; // instead of clearing params in 'del', clear them here
  254. SockAddr addr; addr.setServer(port);
  255. if(_socket.createUdp(addr))
  256. {
  257. _socket.block(false);
  258. if(port>=0) // try specified port
  259. {
  260. if(_socket.bind(addr))return true;
  261. }else
  262. REP(0x10000)if(_socket.bind(addr.port(i)))return true; // find first available
  263. }
  264. del(); return false;
  265. }
  266. Bool FastConnection::create(C SockAddr &addr)
  267. {
  268. del(); _sent=_received=0; // instead of clearing params in 'del', clear them here
  269. if(_socket.createUdp(addr) && _socket.bind(addr))
  270. {
  271. _socket.block(false);
  272. return true;
  273. }
  274. del(); return false;
  275. }
  276. /******************************************************************************/
  277. Bool FastConnection::send(C SockAddr &addr, CPtr data, Int size, Cipher *cipher)
  278. {
  279. if(size>=0 && size<=65536)
  280. {
  281. Byte temp[65536]; if(cipher){cipher->encrypt(temp, data, size, 0); data=temp;}
  282. Int sent=_socket.send(addr, data, size);
  283. if( sent>0)T._sent+=sent;
  284. return sent==size;
  285. }
  286. return false;
  287. }
  288. Bool FastConnection::send(C SockAddr &addr, File &f, Cipher *cipher)
  289. {
  290. Int left =f.left();
  291. if( left<=65536)
  292. {
  293. Byte temp[65536]; f.get(temp, left);
  294. return send(addr, temp, left, cipher);
  295. }
  296. return false;
  297. }
  298. Int FastConnection::receive(SockAddr &addr, Byte (&data)[65536])
  299. {
  300. Int received=_socket.receive(addr, data, SIZE(data));
  301. if( received>0)T._received+=received;
  302. return received;
  303. }
  304. /******************************************************************************/
  305. // CONNECTION SERVER
  306. /******************************************************************************/
  307. Bool ConnectionServer::Client::update()
  308. {
  309. if(connection.updateState(0))return true;
  310. switch(connection.state())
  311. {
  312. case CONNECT_CONNECTING :
  313. case CONNECT_AWAIT_GREET: return connection.life()<=5000; // allow some time to connect
  314. }
  315. return false;
  316. }
  317. /******************************************************************************/
  318. ConnectionServer::ConnectionServer() : clients(Compare)
  319. {
  320. }
  321. /******************************************************************************/
  322. void ConnectionServer::del()
  323. {
  324. _server .del();
  325. clients.del();
  326. }
  327. Bool ConnectionServer::create(Int port)
  328. {
  329. del();
  330. SockAddr addr; addr.setServer(port);
  331. if(_server.createTcp(addr))
  332. {
  333. _server.block(false); // disable blocking before calling 'listen' in case that would block
  334. if(port>=0) // try specified port
  335. {
  336. if(_server.bind(addr))if(_server.listen())return true;
  337. }else
  338. REP(0x10000)if(_server.bind(addr.port(i))) // find first available
  339. {
  340. if(_server.listen())return true;
  341. break;
  342. }
  343. }
  344. del(); return false;
  345. }
  346. Bool ConnectionServer::create(C SockAddr &addr)
  347. {
  348. del();
  349. if(_server.createTcp(addr))
  350. {
  351. _server.block(false); // disable blocking before calling 'listen' in case that would block
  352. if(_server.bind(addr))if(_server.listen())return true;
  353. }
  354. del(); return false;
  355. }
  356. Str ConnectionServer::localAddressName()C
  357. {
  358. if(is())return GetComputerName()+':'+port();
  359. return S;
  360. }
  361. SockAddr ConnectionServer::localAddress()C
  362. {
  363. SockAddr addr; if(is())addr.setLocal(port()); // can't use "_server.addr()" because if it was created with 'SockAddr.setServer' (INADDR_ANY) then that address will be returned
  364. return addr;
  365. }
  366. SockAddr ConnectionServer::globalAddress()C
  367. {
  368. SockAddr addr; if(is())addr.setGlobal(port());
  369. return addr;
  370. }
  371. /******************************************************************************/
  372. void ConnectionServer::update()
  373. {
  374. // accept new clients
  375. for(; _server.wait(0); )
  376. {
  377. Connection connection; if(connection.serverAcceptClient(_server))
  378. {
  379. Client &client=*clients(connection.address());
  380. Swap(client.connection, connection);
  381. client.create(T);
  382. }
  383. }
  384. // update clients
  385. REPA(clients)if(!clients[i].update())clients.remove(i);
  386. }
  387. /******************************************************************************/
  388. }
  389. /******************************************************************************/