client.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <pthread.h>
  5. #include <unistd.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <sys/time.h>
  9. #include <sys/prctl.h>
  10. #include <sys/socket.h>
  11. #include "client.h"
  12. static int renderEventHandler( Tcl_Event* evPtr, int flags ){
  13. int i;
  14. const char* res;
  15. unsigned char pos;
  16. char type;
  17. const char* buf[200];
  18. char statusText[1024];
  19. struct renderEvent* render;
  20. struct timeval startTime;
  21. struct timeval endTime;
  22. int avgRender;
  23. //get start time
  24. gettimeofday( &startTime, NULL );
  25. //init some vars
  26. render = ( struct renderEvent* )evPtr;
  27. for( i = 0; i < 200; i++ ) buf[i] = "0";
  28. //render objects to buf
  29. for( i = 0; i < render->count * 2; i++ ){
  30. type = render->data[i];
  31. i++;
  32. pos = render->data[i];
  33. if( type == 'f' ){
  34. if( pos > 199 ) continue;
  35. buf[pos] = "1";
  36. }
  37. if( pos < 11 || pos > 188 ) continue;
  38. if( type == 'u' || type == 'd' ){
  39. buf[ pos - 1 ] = "1";
  40. buf[ pos ] = "1";
  41. buf[ pos + 1 ] = "1";
  42. if( type == 'u' ){
  43. buf[ pos - 10 ] = "1";
  44. buf[ pos + 9 ] = "1";
  45. buf[ pos + 11 ] = "1";
  46. } else {
  47. buf[ pos - 11 ] = "1";
  48. buf[ pos - 9 ] = "1";
  49. buf[ pos + 10 ] = "1";
  50. }
  51. }else if( type == 'l' || type == 'r' ){
  52. buf[ pos - 10 ] = "1";
  53. buf[ pos ] = "1";
  54. buf[ pos + 10 ] = "1";
  55. if( type == 'l' ){
  56. buf[ pos - 9 ] = "1";
  57. buf[ pos - 1 ] = "1";
  58. buf[ pos + 11 ] = "1";
  59. } else {
  60. buf[ pos - 11 ] = "1";
  61. buf[ pos + 1 ] = "1";
  62. buf[ pos + 9 ] = "1";
  63. }
  64. }else if( type == 'b' ){
  65. buf[ pos - 10 ] = "1";
  66. buf[ pos - 1 ] = "1";
  67. buf[ pos + 1 ] = "1";
  68. buf[ pos + 10 ] = "1";
  69. }else if( type == 'B' ){
  70. buf[ pos ] = "1";
  71. buf[ pos - 11 ] = "1";
  72. buf[ pos - 9 ] = "1";
  73. buf[ pos + 9 ] = "1";
  74. buf[ pos + 11 ] = "1";
  75. }
  76. }
  77. if( render->count ) ckfree( render->data );
  78. //"render" buffer on checkboxes
  79. for( i = 0; i < 200; i++ ){
  80. res = Tcl_SetVar( render->tcl, fieldPixelsIds[i], buf[i], TCL_GLOBAL_ONLY );
  81. if( !res ){
  82. printf( "on err\n" );
  83. break;
  84. }
  85. }
  86. //calculate render time
  87. gettimeofday( &endTime, NULL );
  88. render->avgRender[*render->avgIndex] = (endTime.tv_usec+((endTime.tv_sec-startTime.tv_sec)*1000000)) - startTime.tv_usec;
  89. (*render->avgIndex)++;
  90. if( *render->avgIndex == 10 ) {
  91. *render->avgIndex = 0;
  92. avgRender = 0;
  93. for( i = 0; i < 10; i++ ) avgRender += render->avgRender[i];
  94. avgRender /= 10;
  95. //update status bar
  96. sprintf( statusText, "RT: %ius", avgRender );
  97. Tcl_SetVar( render->tcl, "statusText", statusText, 0 );
  98. }
  99. return 1;
  100. }
  101. static int allertEventHandler( Tcl_Event* evPtr, int flags ){
  102. struct alertEvent* ev;
  103. char buf[4096];
  104. ev = (struct alertEvent*)evPtr;
  105. sprintf( buf, "tk_messageBox -type ok -icon info -title Message -message \"%s\"", ev->msg );
  106. Tcl_Eval( ev->tcl, buf );
  107. //ckfree( ev->msg );
  108. return 1;
  109. }
  110. static int connect2serverResult( Tcl_Event* evPtr, int flags ){
  111. struct alertEvent* ev;
  112. char buf[4096];
  113. ev = (struct alertEvent*)evPtr;
  114. sprintf( buf, "connect2serverRes \"%s\"", ev->msg );
  115. Tcl_Eval( ev->tcl, buf );
  116. //ckfree( ev->msg );
  117. return 1;
  118. }
  119. /*
  120. net proto
  121. server -> client
  122. <num objs u8> <obj desc u8> <obj pos u8> ....
  123. client -> server
  124. <intent u8> <intent desc u8>
  125. */
  126. static void networkThreadCleanup( void *arg ) {
  127. struct instance* this;
  128. this = arg;
  129. close( this->netClientSocket );
  130. this->netClientSocket = -1;
  131. }
  132. static void* networkThread( void* arg ){
  133. int res;
  134. int bytes;
  135. char buf[16];
  136. char* msg2gui;
  137. struct instance* this;
  138. struct renderEvent* ev;
  139. struct alertEvent* dropEv;
  140. pthread_cleanup_push( networkThreadCleanup, arg );
  141. prctl( PR_SET_NAME, "net", 0, 0, 0 );
  142. this = arg;
  143. msg2gui = "Failed to connect to server.";
  144. //connect to server
  145. res = connect( this->netClientSocket, (struct sockaddr*)&this->serverAddress, sizeof(this->serverAddress) );
  146. if( res ){
  147. perror( "connect" );
  148. goto l_connectResult;
  149. }
  150. //handshake
  151. res = write( this->netClientSocket, "TANKS", 5 );
  152. if( res != 5 ) goto l_connectResult;
  153. res = recv( this->netClientSocket, buf, 2, MSG_WAITALL );
  154. if( res != 2 ) goto l_connectResult;
  155. buf[2] = 0x00;
  156. if( strcmp(buf, "OK") ) goto l_connectResult;
  157. msg2gui = "0";
  158. l_connectResult:
  159. dropEv = ckalloc( sizeof(*dropEv) );
  160. dropEv->tclEvent.proc = connect2serverResult;
  161. dropEv->tcl = this->tcl;
  162. dropEv->msg = msg2gui;
  163. Tcl_ThreadQueueEvent( this->tclThread, (Tcl_Event*)dropEv, TCL_QUEUE_TAIL );
  164. Tcl_ThreadAlert( this->tclThread );
  165. if( msg2gui[0] != '0' ) goto l_exit;
  166. l_again:
  167. //obj count
  168. res = recv( this->netClientSocket, buf, 1, MSG_WAITALL );
  169. if( res != 1 ) goto l_drop;
  170. ev = ckalloc( sizeof(*ev) );
  171. ev->tclEvent.proc = renderEventHandler;
  172. ev->tcl = this->tcl;
  173. ev->count = buf[0];
  174. ev->avgRender = this->avgRender;
  175. ev->avgIndex = &this->avgIndex;
  176. if( buf[0] ) {
  177. bytes = buf[0] * 2;
  178. ev->data = ckalloc( bytes );
  179. res = recv( this->netClientSocket, ev->data, bytes, MSG_WAITALL );
  180. if( res != bytes ){
  181. ckfree( ev->data );
  182. ckfree( ev );
  183. goto l_drop;
  184. }
  185. }
  186. Tcl_ThreadQueueEvent( this->tclThread, (Tcl_Event*)ev, TCL_QUEUE_TAIL );
  187. Tcl_ThreadAlert( this->tclThread );
  188. goto l_again;
  189. l_drop:
  190. dropEv = ckalloc( sizeof(*dropEv) );
  191. dropEv->tclEvent.proc = allertEventHandler;
  192. dropEv->tcl = this->tcl;
  193. dropEv->msg = "Connection lost.";
  194. Tcl_ThreadQueueEvent( this->tclThread, (Tcl_Event*)dropEv, TCL_QUEUE_TAIL );
  195. Tcl_ThreadAlert( this->tclThread );
  196. l_exit:
  197. pthread_cleanup_pop( 1 );
  198. return NULL;
  199. }
  200. static int benchCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
  201. int i;
  202. char* val;
  203. const char* res;
  204. if( objc < 2 ) return TCL_OK;
  205. val = Tcl_GetString( objv[1] );
  206. if( !val ) return TCL_OK;
  207. for( i = 0; i < 200; i++ ){
  208. res = Tcl_SetVar( tcl, fieldPixelsIds[i], val, TCL_GLOBAL_ONLY );
  209. if( !res ) return TCL_ERROR;
  210. }
  211. return TCL_OK;
  212. }
  213. static int connect2serverCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
  214. int res;
  215. const char* ipStr;
  216. const char* portStr;
  217. unsigned short port;
  218. struct instance* this;
  219. struct timeval socketTimeout;
  220. this = clientData;
  221. socketTimeout.tv_sec = 10;
  222. socketTimeout.tv_usec = 0;
  223. //check already connected
  224. if( this->netClientSocket >= 0 ){
  225. Tcl_SetVar( tcl, "resmsg", "Already connected.", 0 );
  226. return TCL_OK;
  227. }
  228. //get string ip and port values from gui
  229. ipStr = Tcl_GetVar( tcl, "serverIp", TCL_GLOBAL_ONLY );
  230. portStr = Tcl_GetVar( tcl, "serverPort", TCL_GLOBAL_ONLY );
  231. //check ip not null
  232. if( !ipStr ){
  233. Tcl_SetVar( tcl, "resmsg", "Enter server IP.", 0 );
  234. return TCL_OK;
  235. }
  236. //check port not null
  237. if( !portStr ){
  238. Tcl_SetVar( tcl, "resmsg", "Enter server port.", 0 );
  239. return TCL_OK;
  240. }
  241. //set net family
  242. this->serverAddress.sin_family = AF_INET;
  243. //parse and check ip
  244. this->serverAddress.sin_addr.s_addr = inet_addr( ipStr );
  245. if( this->serverAddress.sin_addr.s_addr == -1 ){
  246. Tcl_SetVar( tcl, "resmsg", "Wrong server IP.", 0 );
  247. return TCL_OK;
  248. }
  249. //parse and check port
  250. res = sscanf( portStr, "%hu", &port );
  251. if( res != 1 ){
  252. Tcl_SetVar( tcl, "resmsg", "Wrong server port.", 0 );
  253. return TCL_OK;
  254. }
  255. this->serverAddress.sin_port = htons( port );
  256. //create socket
  257. this->netClientSocket = socket( AF_INET, SOCK_STREAM, 0 );
  258. if( this->netClientSocket < 0 ){
  259. perror( "socket" );
  260. Tcl_SetVar( tcl, "resmsg", "Create socket failed.", 0 );
  261. return TCL_OK;
  262. }
  263. //set SO_RCVTIMEO for socket
  264. res = setsockopt( this->netClientSocket, SOL_SOCKET, SO_RCVTIMEO, &socketTimeout, sizeof(socketTimeout) );
  265. if( res ){
  266. perror( "socket set SO_RCVTIMEO" );
  267. Tcl_SetVar( tcl, "resmsg", "Failed to configure socket.", 0 );
  268. close( this->netClientSocket );
  269. this->netClientSocket = -1;
  270. return TCL_OK;
  271. }
  272. //set SO_SNDTIMEO for socket
  273. res = setsockopt( this->netClientSocket, SOL_SOCKET, SO_SNDTIMEO, &socketTimeout, sizeof(socketTimeout) );
  274. if( res ){
  275. perror( "socket set SO_SNDTIMEO" );
  276. Tcl_SetVar( tcl, "resmsg", "Failed to configure socket.", 0 );
  277. close( this->netClientSocket );
  278. this->netClientSocket = -1;
  279. return TCL_OK;
  280. }
  281. //start network thread
  282. res = pthread_create( &this->netThread, NULL, networkThread, this );
  283. if( res ){
  284. printf( "net pthread_create: %s\n", strerror(res) );
  285. Tcl_SetVar( tcl, "resmsg", "Failed to start network thread.", 0 );
  286. close( this->netClientSocket );
  287. this->netClientSocket = -1;
  288. return TCL_OK;
  289. }
  290. return TCL_OK;
  291. }
  292. static int dropConnectionCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
  293. struct instance* this;
  294. this = clientData;
  295. if( this->netClientSocket < 0 ) return TCL_OK;
  296. pthread_cancel( this->netThread );
  297. pthread_join( this->netThread, NULL );
  298. return TCL_OK;
  299. }
  300. static int tankCmdCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
  301. int res;
  302. struct instance* this;
  303. char* cmd;
  304. char* arg;
  305. char pendingCmd[2];
  306. this = clientData;
  307. if( objc < 3 ) return TCL_OK;
  308. cmd = Tcl_GetString( objv[1] );
  309. arg = Tcl_GetString( objv[2] );
  310. if( !cmd || !arg ) return TCL_OK;
  311. pendingCmd[1] = arg[0];
  312. pendingCmd[0] = cmd[0];
  313. res = write( this->netClientSocket, pendingCmd, 2 );
  314. if( res != 2 ) perror( "socket cmd write" );
  315. return 0;
  316. }
  317. static int tankControlCore( ClientData clientData, Tcl_Interp* tcl, int objc, Tcl_Obj* const objv[] ){
  318. int res;
  319. struct instance* this;
  320. char* key;
  321. char* pressed;
  322. static char oldkey;
  323. static char keys[3];
  324. char moveDirect[2];
  325. this = clientData;
  326. //get function args
  327. if( objc < 3 ) return TCL_OK;
  328. key = Tcl_GetString( objv[1] );
  329. pressed = Tcl_GetString( objv[2] );
  330. if( !key || !pressed ) return TCL_OK;
  331. //update keys array
  332. if( pressed[0] == '1' ){
  333. if( keys[0] != key[0] ){
  334. keys[2] = keys[1];
  335. keys[1] = keys[0];
  336. keys[0] = key[0];
  337. }
  338. }else{
  339. if( keys[0] == key[0] ){
  340. keys[0] = keys[1];
  341. keys[1] = keys[2];
  342. keys[2] = 0x00;
  343. }else if( keys[1] == key[0] ){
  344. keys[1] = keys[2];
  345. keys[2] = 0x00;
  346. }else if( keys[2] == key[0] ){
  347. keys[2] = 0x00;
  348. }
  349. }
  350. //if current key not changed, then done
  351. if( keys[0] == oldkey ) return 0;
  352. //update current key
  353. oldkey = keys[0];
  354. moveDirect[0] = 'g';//means gearbox
  355. moveDirect[1] = oldkey ? oldkey : 0x00;
  356. res = write( this->netClientSocket, moveDirect, 2 );
  357. if( res != 2 ) perror( "socket control write" );
  358. return 0;
  359. }
  360. int main ( int argc, char* argv[] ){
  361. int res;
  362. struct instance this;
  363. prctl( PR_SET_NAME, "main", 0, 0, 0 );
  364. this.tclThread = Tcl_GetCurrentThread();
  365. this.netClientSocket = -1;
  366. //this.pendingCmd[0] = 0x00;
  367. //this.moveDirect[0] = 0x00;
  368. this.avgIndex = 0;
  369. Tcl_FindExecutable( argv[0] );
  370. //create and init tcl/tk
  371. this.tcl = Tcl_CreateInterp();
  372. Tcl_Init( this.tcl );
  373. Tk_Init( this.tcl );
  374. //load main window layout
  375. res = Tcl_EvalFile( this.tcl, "mainWindow.tcl" );
  376. if( res ){
  377. printf( "failed to eval mainWindow.tcl\n" );
  378. goto l_cleanup;
  379. }
  380. //setup callbacks for functions in tcl
  381. Tcl_CreateObjCommand( this.tcl, "bench1_core", benchCore, &this, NULL );
  382. Tcl_CreateObjCommand( this.tcl, "connect2serverCore", connect2serverCore, &this, NULL );
  383. Tcl_CreateObjCommand( this.tcl, "dropConnection", dropConnectionCore, &this, NULL );
  384. Tcl_CreateObjCommand( this.tcl, "tankControl", tankControlCore, &this, NULL );
  385. Tcl_CreateObjCommand( this.tcl, "tankCmd", tankCmdCore, &this, NULL );
  386. //mait gui loop
  387. Tk_MainLoop();
  388. l_cleanup:
  389. Tcl_DeleteInterp( this.tcl );
  390. printf( "Exit.\n" );
  391. return 0;
  392. }