You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

439 lines
12 KiB

8 years ago
  1. //#define USE_IPV6
  2. #include <stdlib.h>
  3. #ifdef WIN32
  4. #include <winsock2.h>
  5. #include <ws2tcpip.h>
  6. #include <windows.h>
  7. #define MSG_NOSIGNAL 0
  8. #else
  9. //#include <sys/types.h>
  10. #include <sys/socket.h>
  11. //#include <netinet/in.h>
  12. #endif
  13. #include <errno.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <math.h>
  17. #include "cars.h"
  18. #include "socket.h"
  19. #include "insim.h"
  20. #include "network_worker.h"
  21. #include "queue.h"
  22. #include "outgauge.h"
  23. struct conninfo s_conninfo[256];
  24. struct carinfo s_carinfo[256];
  25. struct insim_buffer {
  26. int state;
  27. uint8_t buffer[65536];
  28. int pos;
  29. int offset;
  30. };
  31. static struct insim_buffer s_insim_tcp;
  32. static struct insim_buffer s_insim_udp;
  33. static struct queue_t *s_send_queue;
  34. static uint8_t *s_send_packet;
  35. static uint8_t s_send_pos;
  36. void insim_queue(const void *buffer, size_t size)
  37. {
  38. uint8_t *packet = malloc(size);
  39. memcpy(packet, buffer, size);
  40. queue_produce(s_send_queue, packet);
  41. }
  42. int insim_dequeue(int fd)
  43. {
  44. if (s_send_packet == NULL) queue_consume(s_send_queue, (void *)&s_send_packet);
  45. if (s_send_packet != NULL)
  46. {
  47. ssize_t s = send(fd, (char *)s_send_packet + s_send_pos, s_send_packet[0] - s_send_pos, MSG_NOSIGNAL);
  48. if (s >= 0) s_send_pos += s;
  49. if (s_send_pos >= s_send_packet[0])
  50. {
  51. free(s_send_packet);
  52. s_send_packet = 0;
  53. s_send_pos = 0;
  54. return 1;
  55. }
  56. }
  57. return 0;
  58. }
  59. void insim_request_info(void)
  60. {
  61. memset(s_conninfo, 0, sizeof s_conninfo);
  62. memset(s_carinfo, 0, sizeof s_carinfo);
  63. struct IS_TINY p;
  64. p.Size = sizeof p;
  65. p.Type = ISP_TINY;
  66. p.ReqI = 2;
  67. p.SubT = TINY_NCN;
  68. insim_queue(&p, sizeof p);
  69. p.Size = sizeof p;
  70. p.Type = ISP_TINY;
  71. p.ReqI = 3;
  72. p.SubT = TINY_NPL;
  73. insim_queue(&p, sizeof p);
  74. }
  75. void insim_handle_tiny(int fd, const void *buffer)
  76. {
  77. const struct IS_TINY *p = buffer;
  78. switch (p->SubT)
  79. {
  80. case TINY_NONE:
  81. {
  82. struct IS_TINY r;
  83. r.Size = sizeof r;
  84. r.Type = ISP_TINY;
  85. r.ReqI = 0;
  86. r.SubT = TINY_NONE;
  87. insim_queue(&r, sizeof r);
  88. break;
  89. }
  90. }
  91. }
  92. static void ltc_duty(const char *uname, int state)
  93. {
  94. int i;
  95. for (i = 0; i < 256; i++) {
  96. if (!strcmp(uname, s_conninfo[i].uname)) {
  97. s_conninfo[i].state = state;
  98. printf("Player %s state %d\n", uname, state);
  99. return;
  100. }
  101. }
  102. }
  103. void insim_handle_ism(int fd, const void *buffer)
  104. {
  105. const struct IS_ISM *p = buffer;
  106. printf("Joined %s\n", p->HName);
  107. insim_request_info();
  108. }
  109. void insim_handle_mso(int fd, const void *buffer)
  110. {
  111. return;
  112. const struct IS_MSO *p = buffer;
  113. printf("%d %d %d %d %s\n", p->UCID, p->PLID, p->UserType, p->TextStart, p->Msg);
  114. char buf[128], *bufp = buf;
  115. strncpy(buf, p->Msg, sizeof buf);
  116. int state = 0;
  117. char *name = NULL;
  118. int i;
  119. for (i = 0; i < 10; i++) {
  120. char *a = strsep(&bufp, " ");
  121. if (a == NULL) return;
  122. if (i == 0 && strcmp(a, "***")) return;
  123. if (i == 1 && (!strcmp(a, "Officer") || !strcmp(a, "Cadet"))) state |= 1;
  124. if (i == 2 && state == 1) name = a;
  125. if (i == 3 && strcmp(a, "has")) return;
  126. if (i == 4 && strcmp(a, "gone")) return;
  127. if (i == 5 && !strcmp(a, "onduty")) ltc_duty(name, 1);
  128. if (i == 5 && !strcmp(a, "offduty")) ltc_duty(name, 0);
  129. }
  130. }
  131. void insim_handle_ncn(int fd, const void *buffer)
  132. {
  133. const struct IS_NCN *p = buffer;
  134. struct conninfo *c = s_conninfo + p->UCID;
  135. memset(c, 0, sizeof *c);
  136. c->active = 1;
  137. strncpy(c->uname, p->UName, sizeof c->uname);
  138. strncpy(c->pname, p->PName, sizeof c->pname);
  139. c->admin = p->Admin;
  140. printf("Know about connection %s (%s) %d\n", c->pname, c->uname, c->admin);
  141. }
  142. void insim_handle_cnl(int fd, const void *buffer)
  143. {
  144. const struct IS_CNL *p = buffer;
  145. struct conninfo *c = s_conninfo + p->UCID;
  146. c->active = 0;
  147. }
  148. void insim_handle_cpr(int fd, const void *buffer)
  149. {
  150. const struct IS_CPR *p = buffer;
  151. struct conninfo *c = s_conninfo + p->UCID;
  152. if (c->active == 0) fprintf(stderr, "Rename of inactive connection\n");
  153. strncpy(c->pname, p->PName, sizeof c->pname);
  154. }
  155. void insim_handle_npl(int fd, const void *buffer)
  156. {
  157. const struct IS_NPL *p = buffer;
  158. struct carinfo *car = s_carinfo + p->PLID;
  159. memset(car, 0, sizeof *car);
  160. car->active = 1;
  161. //strncpy(car->cname, p->CName, sizeof car->cname);
  162. car->ucid = p->UCID;
  163. car->mass = p->H_Mass;
  164. car->intake = p->H_TRes;
  165. strncpy(car->cname, find_car(p->CName, car->intake, car->mass), sizeof car->cname);
  166. printf("Car %d joined (%s) - %s\n", p->PLID, car->cname, s_conninfo[car->ucid].uname);
  167. }
  168. void insim_handle_pll(int fd, const void *buffer)
  169. {
  170. const struct IS_PLL *p = buffer;
  171. struct carinfo *car = s_carinfo + p->PLID;
  172. car->active = 0;
  173. printf("Car %d left - %s\n", p->PLID, s_conninfo[car->ucid].uname);
  174. }
  175. void insim_handle_mci(int fd, const void *buffer)
  176. {
  177. const struct IS_MCI *p = buffer;
  178. int i;
  179. for (i = 0; i < p->NumC; i++)
  180. {
  181. const struct CompCar *c = p->Info + i;
  182. struct carinfo *car = s_carinfo + c->PLID;
  183. car->position = c->Position;
  184. car->info = c->Info;
  185. car->sp3 = c->Sp3;
  186. car->x = c->X;
  187. car->y = c->Y;
  188. car->z = c->Z;
  189. car->speed = c->Speed;
  190. car->direction = c->Direction;
  191. car->heading = c->Heading;
  192. car->angvel = c->AngVel;
  193. car->hist_x[car->hist] = c->X;
  194. car->hist_y[car->hist] = c->Y;
  195. car->hist_s[car->hist] = c->Speed;
  196. car->hist = (car->hist + 1) % CARPATHSIZE;
  197. }
  198. }
  199. typedef void (*insim_handler)(int fd, const void *buffer);
  200. static const insim_handler s_handlers[] =
  201. {
  202. NULL, // ISP_NONE // 0 : not used
  203. NULL, // ISP_ISI // 1 - instruction : insim initialise
  204. NULL, // ISP_VER // 2 - info : version info
  205. insim_handle_tiny, // ISP_TINY // 3 - both ways : multi purpose
  206. NULL, // ISP_SMALL // 4 - both ways : multi purpose
  207. NULL, // ISP_STA // 5 - info : state info
  208. NULL, // ISP_SCH // 6 - instruction : single character
  209. NULL, // ISP_SFP // 7 - instruction : state flags pack
  210. NULL, // ISP_SCC // 8 - instruction : set car camera
  211. NULL, // ISP_CPP // 9 - both ways : cam pos pack
  212. insim_handle_ism, // ISP_ISM // 10 - info : start multiplayer
  213. insim_handle_mso, // ISP_MSO // 11 - info : message out
  214. NULL, // ISP_III // 12 - info : hidden /i message
  215. NULL, // ISP_MST // 13 - instruction : type message or /command
  216. NULL, // ISP_MTC // 14 - instruction : message to a connection
  217. NULL, // ISP_MOD // 15 - instruction : set screen mode
  218. NULL, // ISP_VTN // 16 - info : vote notification
  219. NULL, // ISP_RST // 17 - info : race start
  220. insim_handle_ncn, // ISP_NCN // 18 - info : new connection
  221. insim_handle_cnl, // ISP_CNL // 19 - info : connection left
  222. insim_handle_cpr, // ISP_CPR // 20 - info : connection renamed
  223. insim_handle_npl, // ISP_NPL // 21 - info : new player (joined race)
  224. NULL, // ISP_PLP // 22 - info : player pit (keeps slot in race)
  225. insim_handle_pll, // ISP_PLL // 23 - info : player leave (spectate - loses slot)
  226. NULL, // ISP_LAP // 24 - info : lap time
  227. NULL, // ISP_SPX // 25 - info : split x time
  228. NULL, // ISP_PIT // 26 - info : pit stop start
  229. NULL, // ISP_PSF // 27 - info : pit stop finish
  230. NULL, // ISP_PLA // 28 - info : pit lane enter / leave
  231. NULL, // ISP_CCH // 29 - info : camera changed
  232. NULL, // ISP_PEN // 30 - info : penalty given or cleared
  233. NULL, // ISP_TOC // 31 - info : take over car
  234. NULL, // ISP_FLG // 32 - info : flag (yellow or blue)
  235. NULL, // ISP_PFL // 33 - info : player flags (help flags)
  236. NULL, // ISP_FIN // 34 - info : finished race
  237. NULL, // ISP_RES // 35 - info : result confirmed
  238. NULL, // ISP_REO // 36 - both ways : reorder (info or instruction)
  239. NULL, // ISP_NLP // 37 - info : node and lap packet
  240. insim_handle_mci, // ISP_MCI // 38 - info : multi car info
  241. NULL, // ISP_MSX // 39 - instruction : type message
  242. NULL, // ISP_MSL // 40 - instruction : message to local computer
  243. NULL, // ISP_CRS // 41 - info : car reset
  244. NULL, // ISP_BFN // 42 - both ways : delete buttons / receive button requests
  245. NULL, // ISP_AXI // 43 - info : autocross layout information
  246. NULL, // ISP_AXO // 44 - info : hit an autocross object
  247. NULL, // ISP_BTN // 45 - instruction : show a button on local or remote screen
  248. NULL, // ISP_BTC // 46 - info : sent when a user clicks a button
  249. NULL, // ISP_BTT // 47 - info : sent after typing into a button
  250. NULL, // ISP_RIP // 48 - both ways : replay information packet
  251. NULL, // ISP_SSH // 49 - both ways : screenshot
  252. NULL, // ISP_CON // 50 - info : contact between cars (collision report)
  253. NULL, // ISP_OBH // 51 - info : contact car + object (collision report)
  254. NULL, // ISP_HLV // 52 - info : report incidents that would violate HLVC
  255. NULL, // ISP_PLC // 53 - instruction : player cars
  256. NULL, // ISP_AXM // 54 - both ways : autocross multiple objects
  257. NULL, // ISP_ACR // 55 - info : admin command report
  258. };
  259. void insim_handle(int fd, const uint8_t *buffer)
  260. {
  261. uint8_t type = buffer[1];
  262. if (type <= ISP_ACR && s_handlers[type] != NULL)
  263. {
  264. s_handlers[type](fd, buffer);
  265. }
  266. }
  267. int insim_recv(int fd, int can_write, int can_read, void *arg)
  268. {
  269. struct insim_buffer *buffer = arg;
  270. if (can_write && buffer->state == 1)
  271. {
  272. insim_dequeue(fd);
  273. }
  274. if (can_read)
  275. {
  276. if (buffer->pos >= sizeof buffer->buffer)
  277. {
  278. printf("buffer full\n");
  279. return 0;
  280. }
  281. ssize_t res = recv(fd, (char *)buffer->buffer + buffer->pos, sizeof buffer->buffer - buffer->pos, 0);
  282. if (res == -1)
  283. {
  284. #ifdef WIN32
  285. if (WSAGetLastError() == WSAECONNRESET)
  286. #else
  287. if (errno == ECONNRESET)
  288. #endif
  289. {
  290. printf("connreset\n");
  291. return 0;
  292. }
  293. #ifdef WIN32
  294. else if (WSAGetLastError() != WSAEWOULDBLOCK)
  295. #else
  296. else if (errno != EWOULDBLOCK && errno != EAGAIN)
  297. #endif
  298. {
  299. printf("hmm: %s\n", strerror(errno));
  300. return 0;
  301. }
  302. }
  303. if (res == 0)
  304. {
  305. printf("nothing received\n");
  306. return 0;
  307. }
  308. buffer->pos += res;
  309. while (1)
  310. {
  311. uint8_t size = buffer->buffer[buffer->offset];
  312. if (size % 4 != 0)
  313. {
  314. printf("invalid packet, size is %d\n", size);
  315. return 0;
  316. }
  317. if (buffer->pos - buffer->offset >= size)
  318. {
  319. insim_handle(fd, buffer->buffer + buffer->offset);
  320. }
  321. else
  322. {
  323. break;
  324. }
  325. if (buffer->pos - buffer->offset > size)
  326. {
  327. buffer->offset += size;
  328. }
  329. else
  330. {
  331. buffer->pos = 0;
  332. buffer->offset = 0;
  333. }
  334. }
  335. }
  336. return 1;
  337. }
  338. /*
  339. #ifdef USE_IPV6
  340. static struct sockaddr_in6 serv_addr;
  341. #else
  342. static struct sockaddr_in serv_addr;
  343. #endif
  344. */
  345. extern int g_outgauge_port;
  346. extern int g_insim_port;
  347. static void insim_connect(int fd, void *arg)
  348. {
  349. if (fd == -1)
  350. {
  351. return;
  352. }
  353. s_insim_tcp.state = 1;
  354. s_insim_tcp.pos = 0;
  355. s_insim_tcp.offset = 0;
  356. register_socket(fd, SM_READ | SM_WRITE, &insim_recv, &s_insim_tcp);
  357. fd = network_listen(g_insim_port + 1, 0);
  358. s_insim_udp.state = 2;
  359. s_insim_udp.pos = 0;
  360. s_insim_udp.offset = 0;
  361. register_socket(fd, SM_READ, &insim_recv, &s_insim_udp);
  362. struct IS_ISI p;
  363. memset(&p, 0, sizeof p);
  364. p.Size = sizeof p;
  365. p.Type = ISP_ISI;
  366. p.ReqI = 0;
  367. p.Zero = 0;
  368. p.UDPPort = g_outgauge_port; //g_insim_port + 1;
  369. p.Flags = ISF_LOCAL;
  370. p.Sp0 = 0;
  371. p.Prefix = 0;
  372. p.Interval = 100;
  373. snprintf(p.Admin, sizeof p.Admin, "");
  374. snprintf(p.IName, sizeof p.IName, "LFS Dashboard");
  375. insim_queue(&p, sizeof p);
  376. struct IS_SMALL s;
  377. s.Size = sizeof s;
  378. s.Type = ISP_SMALL;
  379. s.ReqI = 1;
  380. s.SubT = SMALL_SSG;
  381. s.UVal = 1;
  382. insim_queue(&s, sizeof s);
  383. insim_request_info();
  384. }
  385. void insim_init(const char *hostname, int port)
  386. {
  387. s_insim_tcp.state = 0;
  388. s_insim_udp.state = 0;
  389. s_send_queue = queue_new();
  390. network_connect(hostname, port, &insim_connect, NULL);
  391. }