PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/liquidwar/src/sockex.c

#
C | 703 lines | 487 code | 50 blank | 166 comment | 85 complexity | ce7e82b23e1f6edb83546675235d237a MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0
  1. /********************************************************************/
  2. /* */
  3. /* L I QQ U U I DD W W A RR 555 */
  4. /* L I Q Q U U I D D W W A A R R 5 */
  5. /* L I Q Q U U I D D W W W AAA RR 55 */
  6. /* L I Q Q U U I D D WW WW A A R R 5 */
  7. /* LLL I Q Q U I DD W W A A R R 55 */
  8. /* */
  9. /* b */
  10. /* bb y y */
  11. /* b b yyy */
  12. /* bb y */
  13. /* yy */
  14. /* */
  15. /* U U FFF O O TTT */
  16. /* U U F O O O O T */
  17. /* U U TIRET FF O O O O T */
  18. /* U U F O O O O T */
  19. /* U F O O T */
  20. /* */
  21. /********************************************************************/
  22. /*****************************************************************************/
  23. /* Liquid War is a multiplayer wargame */
  24. /* Copyright (C) 1998-2013 Christian Mauduit */
  25. /* */
  26. /* This program is free software; you can redistribute it and/or modify */
  27. /* it under the terms of the GNU General Public License as published by */
  28. /* the Free Software Foundation; either version 2 of the License, or */
  29. /* (at your option) any later version. */
  30. /* */
  31. /* This program is distributed in the hope that it will be useful, */
  32. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  33. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  34. /* GNU General Public License for more details. */
  35. /* */
  36. /* You should have received a copy of the GNU General Public License */
  37. /* along with this program; if not, write to the Free Software */
  38. /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
  39. /* */
  40. /* Liquid War homepage : http://www.ufoot.org/liquidwar/v5 */
  41. /* Contact author : ufoot@ufoot.org */
  42. /*****************************************************************************/
  43. /********************************************************************/
  44. /* name : sockw32.c */
  45. /* content : simple wrappers on the winsock API */
  46. /* last update : April 13th 2001 */
  47. /********************************************************************/
  48. /*==================================================================*/
  49. /* includes */
  50. /*==================================================================*/
  51. #ifdef WIN32
  52. #include <winsock.h>
  53. #else
  54. #include <sys/types.h>
  55. #include <netinet/in.h>
  56. #include <arpa/inet.h>
  57. #include <sys/socket.h>
  58. #include <sys/time.h>
  59. #include <unistd.h>
  60. #include <fcntl.h>
  61. #include <signal.h>
  62. #endif
  63. #include <stdlib.h>
  64. #include <time.h>
  65. #include <string.h>
  66. #include <ctype.h>
  67. #include <errno.h>
  68. #include "sockgen.h"
  69. #include "log.h"
  70. /*==================================================================*/
  71. /* defines */
  72. /*==================================================================*/
  73. #define LW_SOCK_RECV_SEC 8
  74. #define LW_SOCK_RECV_USEC 0
  75. #define LW_SOCK_SEND_SEC 8
  76. #define LW_SOCK_SEND_USEC 0
  77. #define LW_SOCK_SEND_BUFFER_SIZE 100
  78. #define LW_SOCK_RECV_BUFFER_SIZE 200
  79. /*==================================================================*/
  80. /* macros */
  81. /*==================================================================*/
  82. #ifndef MIN
  83. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  84. #endif
  85. #ifndef MAX
  86. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  87. #endif
  88. /*==================================================================*/
  89. /* globals */
  90. /*==================================================================*/
  91. /*==================================================================*/
  92. /* static fonctions */
  93. /*==================================================================*/
  94. static void clean_buffer (char *buffer, int len);
  95. /*==================================================================*/
  96. /* fonctions */
  97. /*==================================================================*/
  98. /*------------------------------------------------------------------*/
  99. /*
  100. * Cleans up a message buffer from all characters which are not
  101. * plain standard ASCII. Used for logging information.
  102. */
  103. static void
  104. clean_buffer (char *buffer, int len)
  105. {
  106. int i;
  107. for (i = 0; i < len; ++i)
  108. {
  109. if (!isalnum (buffer[i]) && buffer[i] != '-' && buffer[i] != '+')
  110. {
  111. buffer[i] = '.';
  112. }
  113. }
  114. }
  115. /*------------------------------------------------------------------*/
  116. /*
  117. * Returns true if the given number bytes is available on the socket
  118. */
  119. int
  120. lw_sock_peek_ex (int *sock, int len)
  121. {
  122. int result = 0;
  123. int res;
  124. fd_set read;
  125. struct timeval tv;
  126. char buffer[LW_SOCK_MESSAGE_SIZE];
  127. int sock_copy;
  128. if ((sock_copy = *sock) >= 0)
  129. {
  130. if (len <= LW_SOCK_MESSAGE_SIZE - 1)
  131. {
  132. FD_ZERO (&read);
  133. FD_SET (sock_copy, &read);
  134. tv.tv_sec = 0;
  135. tv.tv_usec = 0;
  136. res = select (sock_copy + 1, &read, NULL, NULL, &tv);
  137. if (res > 0)
  138. {
  139. if (FD_ISSET (sock_copy, &read))
  140. {
  141. /*
  142. * First we test if there's enough data available
  143. */
  144. if (recv (sock_copy, buffer, len, MSG_PEEK) == len)
  145. {
  146. result = 1;
  147. }
  148. }
  149. }
  150. }
  151. }
  152. return result;
  153. }
  154. /*------------------------------------------------------------------*/
  155. /*
  156. * Sends a string on the network.
  157. * The advantage of this function over a raw "send" is that it does
  158. * a "strlen" automatically to know the length of the string, and
  159. * adds a tailing CR+LF so that the message is "telnet/http compliant"
  160. */
  161. int
  162. lw_sock_send_str_ex (int *sock, char *str)
  163. {
  164. int result = 0;
  165. int len;
  166. char buffer[LW_SOCK_MESSAGE_SIZE];
  167. int sock_copy;
  168. fd_set write;
  169. struct timeval tv;
  170. int res;
  171. int total_sent;
  172. int sent;
  173. #ifdef WIN32
  174. int winerr;
  175. #endif
  176. if ((sock_copy = *sock) >= 0)
  177. {
  178. result = 1;
  179. /*
  180. * We put the string in a buffer, since we'll probably have
  181. * to modify it (cut if it's too long, add a tailing CR+LF).
  182. */
  183. len = strlen (str);
  184. len = MIN (len, LW_SOCK_MESSAGE_SIZE - 3);
  185. strncpy (buffer, str, len);
  186. buffer[len] = '\x0d';
  187. ++len;
  188. buffer[len] = '\x0a';
  189. ++len;
  190. buffer[len] = '\0';
  191. total_sent = 0;
  192. while (total_sent < len && result && (sock_copy = *sock) >= 0)
  193. {
  194. FD_ZERO (&write);
  195. FD_SET (sock_copy, &write);
  196. tv.tv_sec = LW_SOCK_SEND_SEC;
  197. tv.tv_usec = LW_SOCK_SEND_USEC;
  198. errno = 0;
  199. res = select (sock_copy + 1, NULL, &write, NULL, &tv);
  200. switch (res)
  201. {
  202. case -1:
  203. #ifdef WIN32
  204. winerr = WSAGetLastError ();
  205. if (winerr != WSAEINTR && winerr != WSAENOBUFS)
  206. {
  207. result = 0;
  208. }
  209. #else
  210. if (errno != EINTR && errno != ENOBUFS)
  211. {
  212. result = 0;
  213. }
  214. #endif
  215. break;
  216. case 1:
  217. if (FD_ISSET (sock_copy, &write))
  218. {
  219. sent =
  220. send (sock_copy, buffer + total_sent, len - total_sent,
  221. 0);
  222. if (sent > 0 && sent <= len - total_sent)
  223. {
  224. total_sent += sent;
  225. }
  226. else
  227. {
  228. result = 0;
  229. }
  230. }
  231. break;
  232. default:
  233. result = 0;
  234. }
  235. }
  236. if (LW_SOCK_LOG)
  237. {
  238. switch (result)
  239. {
  240. case 1:
  241. log_print_int (sock_copy);
  242. log_print_str (" > \"");
  243. log_print_str (str);
  244. log_print_str ("\"");
  245. log_println ();
  246. log_flush ();
  247. break;
  248. case 0:
  249. log_print_int (sock_copy);
  250. log_print_str (" > timeout!");
  251. log_println ();
  252. break;
  253. default:
  254. log_print_int (sock_copy);
  255. log_print_str (" > unexpected error!");
  256. log_println ();
  257. break;
  258. }
  259. }
  260. }
  261. return result;
  262. }
  263. /*------------------------------------------------------------------*/
  264. /*
  265. * Receives some data from the network.
  266. * A tailing "\n" is expected. The routine handles both chr(10) and chr(13)
  267. * correctly so that the program can be used with telnet under UNIX or
  268. * windows without much trouble.
  269. * This tailing "\n" is removed, so the return string is just the exact
  270. * message which has been send with sock_send.
  271. * Buffer must be able to accept at least LW_SOCK_MESSAGE_SIZE chars.
  272. * Note that the function will not block forever, if there's no incoming
  273. * for more than a #define specified amount of time, it will return
  274. * an error.
  275. */
  276. int
  277. lw_sock_recv_str_ex (int *sock, char *str)
  278. {
  279. int result = 0;
  280. int pos, l;
  281. int cr_found;
  282. char *cr;
  283. fd_set read;
  284. int sock_copy;
  285. struct timeval tv;
  286. int res;
  287. #ifdef WIN32
  288. int winerr;
  289. #endif
  290. str[0] = '\0';
  291. if ((sock_copy = *sock) >= 0)
  292. {
  293. result = 1;
  294. /*
  295. * We keep on trying to get data until
  296. * - we get a '\n' character
  297. * - the size of incoming data exceeds LW_SOCK_MESSAGE_SIZE
  298. * - there's a reception low level error
  299. */
  300. cr_found = 0;
  301. pos = 0;
  302. while (!cr_found && pos < LW_SOCK_MESSAGE_SIZE - 1 && result > 0
  303. && (sock_copy = *sock) >= 0)
  304. {
  305. FD_ZERO (&read);
  306. FD_SET (sock_copy, &read);
  307. tv.tv_sec = LW_SOCK_RECV_SEC;
  308. tv.tv_usec = LW_SOCK_RECV_USEC;
  309. errno = 0;
  310. res = select (sock_copy + 1, &read, NULL, NULL, &tv);
  311. switch (res)
  312. {
  313. case -1:
  314. #ifdef WIN32
  315. winerr = WSAGetLastError ();
  316. if (winerr != WSAEINTR)
  317. {
  318. result = 0;
  319. }
  320. #else
  321. if (errno != EINTR)
  322. {
  323. result = 0;
  324. }
  325. #endif
  326. break;
  327. case 1:
  328. /*
  329. * We check that the event we just received concerns the socket
  330. * we are polling. If the event is not for us, let's consider
  331. * everything is fine...
  332. */
  333. if (!FD_ISSET (sock_copy, &read))
  334. {
  335. result = 1;
  336. }
  337. else
  338. {
  339. /*
  340. * We get the caracters one by one. This is a performance
  341. * killer but we don't care since this routine is only
  342. * used at the very beginning of the game, when the players
  343. * are connecting themselves. And it has the *big* advantage
  344. * that "netkeys" are not eaten up by this routine. More
  345. * precisely, there's used to be a bug because when reading
  346. * the final "OK" message, the clients read some netkeys
  347. * along with it, which caused some network inconsistency
  348. * since the messages had "disappeared".
  349. */
  350. if ((l = recv (sock_copy, str + pos, 1, 0)) <= 0)
  351. {
  352. /*
  353. * OK, now we have received a message on this socket
  354. * but there's no data. In most of the cases this means
  355. * the socket is dead, so we return -1 instead of 0
  356. * so that the caller can make the difference between
  357. * a timeout (0) and a dead socket (-1).
  358. */
  359. result = -1;
  360. }
  361. else
  362. {
  363. /*
  364. * pos is an offset in the buffer. It is used to keep a
  365. * trace of where new data should be appended in case we
  366. * have to call recv several times to retrieve the whole
  367. * message.
  368. */
  369. pos += l;
  370. /*
  371. * We add a tailing '\0' so that the string is "C compliant"
  372. */
  373. str[pos] = 0;
  374. /*
  375. * We seek for character 10, which should be '\n'
  376. */
  377. if ((cr = strchr (str, '\x0a')) != NULL)
  378. {
  379. cr_found = 1;
  380. /*
  381. * We handle the special character '13' for very often,
  382. * especially when using telnet, the strings come
  383. * with char(13)chr(10) at the end. So if it happens
  384. * that after removing the 10 there's still a 13, then
  385. * we remove the 13 as well.
  386. */
  387. if ((cr - str) >= 1 && (*(cr - 1)) == '\x0d')
  388. {
  389. /*
  390. * Let's cut this ugly "ascii 13" character
  391. * along with "ascii 10"
  392. */
  393. (*(cr - 1)) = 0;
  394. }
  395. else
  396. {
  397. /*
  398. * No "ascii 13" in sight, simply remove "ascii 10"
  399. */
  400. (*cr) = 0;
  401. }
  402. }
  403. result = 1;
  404. }
  405. }
  406. break;
  407. default:
  408. result = 0;
  409. }
  410. }
  411. if (LW_SOCK_LOG)
  412. {
  413. switch (result)
  414. {
  415. case 1:
  416. log_print_int (sock_copy);
  417. log_print_str (" < \"");
  418. log_print_str (str);
  419. log_print_str ("\"");
  420. log_println ();
  421. log_flush ();
  422. break;
  423. case 0:
  424. log_print_int (sock_copy);
  425. log_print_str (" < timeout!");
  426. log_println ();
  427. break;
  428. case -1:
  429. log_print_int (sock_copy);
  430. log_print_str (" < closed!");
  431. log_println ();
  432. break;
  433. default:
  434. log_print_int (sock_copy);
  435. log_print_str (" < unexpected error!");
  436. log_println ();
  437. break;
  438. }
  439. }
  440. }
  441. return result;
  442. }
  443. /*------------------------------------------------------------------*/
  444. /*
  445. * Sends a buffer on the network.
  446. * Only a standard send wrapper
  447. */
  448. int
  449. lw_sock_send_buffer_ex (int *sock, char *buffer, int len)
  450. {
  451. int result = 0;
  452. char trace[LW_SOCK_MESSAGE_SIZE];
  453. fd_set write;
  454. struct timeval tv;
  455. int sock_copy;
  456. int res;
  457. int total_sent;
  458. int sent;
  459. #ifdef WIN32
  460. int winerr;
  461. #endif
  462. if ((sock_copy = *sock) >= 0)
  463. {
  464. result = 1;
  465. if (len <= LW_SOCK_MESSAGE_SIZE - 1)
  466. {
  467. total_sent = 0;
  468. while (total_sent < len && result && (sock_copy = *sock) >= 0)
  469. {
  470. FD_ZERO (&write);
  471. FD_SET (sock_copy, &write);
  472. tv.tv_sec = LW_SOCK_SEND_SEC;
  473. tv.tv_usec = LW_SOCK_SEND_USEC;
  474. errno = 0;
  475. res = select (sock_copy + 1, NULL, &write, NULL, &tv);
  476. switch (res)
  477. {
  478. case -1:
  479. #ifdef WIN32
  480. winerr = WSAGetLastError ();
  481. if (winerr != WSAEINTR && winerr != WSAENOBUFS)
  482. {
  483. result = 0;
  484. }
  485. #else
  486. if (errno != EINTR && errno != ENOBUFS)
  487. {
  488. result = 0;
  489. }
  490. #endif
  491. break;
  492. case 1:
  493. if (FD_ISSET (sock_copy, &write))
  494. {
  495. sent = send (sock_copy,
  496. buffer + total_sent,
  497. MIN (len - total_sent,
  498. LW_SOCK_SEND_BUFFER_SIZE), 0);
  499. if (sent > 0 && sent <= len - total_sent)
  500. {
  501. total_sent += sent;
  502. }
  503. else
  504. {
  505. result = 0;
  506. }
  507. }
  508. break;
  509. default:
  510. result = 0;
  511. }
  512. }
  513. if (LW_SOCK_LOG)
  514. {
  515. if (result)
  516. {
  517. strncpy (trace, buffer, len);
  518. trace[len] = '\0';
  519. log_print_int (sock_copy);
  520. log_print_str (" > [");
  521. clean_buffer (trace, len);
  522. log_print_str (trace);
  523. log_print_str ("]");
  524. log_println ();
  525. log_flush ();
  526. }
  527. else
  528. {
  529. log_print_int (sock_copy);
  530. log_print_str (" > timeout!");
  531. log_println ();
  532. }
  533. }
  534. }
  535. else
  536. {
  537. result = 0;
  538. if (LW_SOCK_LOG)
  539. {
  540. log_print_int (sock_copy);
  541. log_print_str (" > message too large!");
  542. log_println ();
  543. }
  544. }
  545. }
  546. return result;
  547. }
  548. /*------------------------------------------------------------------*/
  549. /*
  550. * Receives a buffer on the network.
  551. * Only a standard recv wrapper
  552. */
  553. int
  554. lw_sock_recv_buffer_ex (int *sock, char *buffer, int len)
  555. {
  556. int result = 0;
  557. char trace[LW_SOCK_MESSAGE_SIZE];
  558. int res;
  559. fd_set read;
  560. struct timeval tv;
  561. int sock_copy;
  562. int total_received;
  563. int received;
  564. #ifdef WIN32
  565. int winerr;
  566. #endif
  567. memset (buffer, 0, len);
  568. if ((sock_copy = *sock) >= 0)
  569. {
  570. result = 1;
  571. if (len <= LW_SOCK_MESSAGE_SIZE - 1)
  572. {
  573. total_received = 0;
  574. while (total_received < len && result && (sock_copy = *sock) >= 0)
  575. {
  576. FD_ZERO (&read);
  577. FD_SET (sock_copy, &read);
  578. tv.tv_sec = LW_SOCK_RECV_SEC;
  579. tv.tv_usec = LW_SOCK_RECV_USEC;
  580. errno = 0;
  581. res = select (sock_copy + 1, &read, NULL, NULL, &tv);
  582. switch (res)
  583. {
  584. case -1:
  585. #ifdef WIN32
  586. winerr = WSAGetLastError ();
  587. if (winerr != WSAEINTR)
  588. {
  589. result = 0;
  590. }
  591. #else
  592. if (errno != EINTR)
  593. {
  594. result = 0;
  595. }
  596. #endif
  597. break;
  598. case 1:
  599. if (FD_ISSET (sock_copy, &read))
  600. {
  601. received = recv (sock_copy,
  602. buffer + total_received,
  603. MIN (len - total_received,
  604. LW_SOCK_RECV_BUFFER_SIZE), 0);
  605. if (received > 0 && received <= len - total_received)
  606. {
  607. total_received += received;
  608. }
  609. else
  610. {
  611. result = 0;
  612. }
  613. }
  614. break;
  615. default:
  616. result = 0;
  617. }
  618. }
  619. if (LW_SOCK_LOG)
  620. {
  621. if (result)
  622. {
  623. strncpy (trace, buffer, len);
  624. trace[len] = '\0';
  625. log_print_int (sock_copy);
  626. log_print_str (" < [");
  627. clean_buffer (trace, len);
  628. log_print_str (trace);
  629. log_print_str ("]");
  630. log_println ();
  631. log_flush ();
  632. }
  633. else
  634. {
  635. log_print_int (sock_copy);
  636. log_print_str (" < timeout!");
  637. log_println ();
  638. }
  639. }
  640. }
  641. else
  642. {
  643. result = 0;
  644. if (LW_SOCK_LOG)
  645. {
  646. log_print_int (sock_copy);
  647. log_print_str (" < message too large!");
  648. log_println ();
  649. }
  650. }
  651. }
  652. return result;
  653. }