1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802
|
/*
GameSpy GT2 SDK
Dan "Mr. Pants" Schoenblum
dan@gamespy.com
Copyright 2002 GameSpy Industries, Inc
devsupport@gamespy.com
*/
#include "gt2Message.h"
#include "gt2Buffer.h"
#include "gt2Connection.h"
#include "gt2Socket.h"
#include "gt2Callback.h"
#include "gt2Utility.h"
#include <stdlib.h>
static unsigned short gti2UShortFromBuffer(const GT2Byte * buffer, int pos)
{
unsigned short s;
s = (unsigned short)((buffer[pos] << 8) & 0xFF00);
pos++;
s |= buffer[pos];
return s;
}
static void gti2UShortToBuffer(GT2Byte * buffer, int pos, unsigned short s)
{
buffer[pos++] = (GT2Byte)((s >> 8) & 0xFF);
buffer[pos] = (GT2Byte)(s & 0xFF);
}
static int gti2SNDiff(unsigned short SN1, unsigned short SN2)
{
return (short)(SN1 - SN2);
}
static GT2Bool gti2ConnectionError(GT2Connection connection, GT2Result result, GT2CloseReason reason)
{
// first check if we're still connecting
if(connection->state < GTI2Connected)
{
// check if the local side is the initiator
if(connection->initiated)
{
// mark it as closed
gti2ConnectionClosed(connection);
// call the callback
if(!gti2ConnectedCallback(connection, result, NULL, 0))
return GT2False;
}
else
{
// are we waiting for accept/reject?
if(connection->state == GTI2AwaitingAcceptReject)
connection->freeAtAcceptReject = GT2True;
// mark it as closed
gti2ConnectionClosed(connection);
}
}
// report the close, as long as we're not already closed
else if(connection->state != GTI2Closed)
{
// mark it as closed
gti2ConnectionClosed(connection);
// call the callback
if(!gti2ClosedCallback(connection, reason))
return GT2False;
}
return GT2True;
}
static GT2Bool gti2ConnectionCommunicationError(GT2Connection connection)
{
return gti2ConnectionError(connection, GT2NegotiationError, GT2CommunicationError);
}
static GT2Bool gti2ConnectionMemoryError(GT2Connection connection)
{
// let the other side know
if(!gti2SendClosed(connection))
return GT2False;
return gti2ConnectionError(connection, GT2OutOfMemory, GT2NotEnoughMemory);
}
static GT2Bool gti2HandleESN(GT2Connection connection, unsigned short ESN)
{
int len;
int i;
GTI2OutgoingBufferMessage * message;
int shortenBy;
// get the number of messages in the outgoing queue
len = ArrayLength(connection->outgoingBufferMessages);
if(!len)
return GT2True;
// loop through until we hit one we can't remove
for(i = 0 ; i < len ; i++)
{
// get the message
message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i);
// don't stop until we get to the ESN
if(gti2SNDiff(message->serialNumber, ESN) >= 0)
break;
}
// check for not removing any
if(i == 0)
return GT2True;
// remove the message info structs
while(i--)
ArrayDeleteAt(connection->outgoingBufferMessages, i);
// check how many messages are left
len = ArrayLength(connection->outgoingBufferMessages);
if(!len)
{
// buffer is empty
connection->outgoingBuffer.len = 0;
return GT2True;
}
// figure out how much to move everything forward
message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, 0);
shortenBy = message->start;
// do the move on the info structs
for(i = 0 ; i < len ; i++)
{
message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i);
message->start -= shortenBy;
}
// move the actual data
gti2BufferShorten(&connection->outgoingBuffer, 0, shortenBy);
return GT2True;
}
static GT2Bool gti2HandleAppUnreliable(GT2Connection connection, GT2Byte * message, int len)
{
// check the state
if((connection->state != GTI2Connected) && (connection->state != GTI2Closing))
return GT2True;
// do we need to filter it?
if(ArrayLength(connection->receiveFilters))
{
if(!gti2ReceiveFilterCallback(connection, 0, message, len, GT2False))
return GT2False;
return GT2True;
}
// we received data, call the callback
if(!gti2ReceivedCallback(connection, message, len, GT2False))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleAppReliable(GT2Connection connection, GT2Byte * message, int len)
{
// check the state
if((connection->state != GTI2Connected) && (connection->state != GTI2Closing))
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
}
else
{
// do we need to filter it?
if(ArrayLength(connection->receiveFilters))
{
if(!gti2ReceiveFilterCallback(connection, 0, message, len, GT2True))
return GT2False;
return GT2True;
}
// we received data, call the callback
if(!gti2ReceivedCallback(connection, message, len, GT2True))
return GT2False;
}
return GT2True;
}
static GT2Bool gti2HandleClientChallenge(GT2Connection connection, GT2Byte * message, int len)
{
char response[GTI2_RESPONSE_LEN];
char challenge[GTI2_CHALLENGE_LEN];
// check the state
if(connection->state != GTI2AwaitingClientChallenge)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// make sure the message is long enough
if(len < GTI2_CHALLENGE_LEN)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// generate a response to the challenge
gti2GetResponse((GT2Byte *)response, message);
// generate our own challenge
gti2GetChallenge((GT2Byte *)challenge);
// store what our response will be
gti2GetResponse((GT2Byte *)connection->response, (GT2Byte *)challenge);
// send our own challenge
if(!gti2SendServerChallenge(connection, response, challenge))
return GT2False;
// new state
connection->state = GTI2AwaitingClientResponse;
return GT2True;
}
static GT2Bool gti2HandleServerChallenge(GT2Connection connection, GT2Byte * message, int len)
{
char response[GTI2_RESPONSE_LEN];
// check the state
if(connection->state != GTI2AwaitingServerChallenge)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// make sure the message is long enough
if(len < (GTI2_RESPONSE_LEN + GTI2_CHALLENGE_LEN))
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// check the response
if(!gti2CheckResponse(message, (GT2Byte *)connection->response))
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// generate our response to the server's challenge
gti2GetResponse((GT2Byte *)response, message + GTI2_RESPONSE_LEN);
// send the response, including our intial message
if(!gti2SendClientResponse(connection, response, connection->initialMessage, connection->initialMessageLen))
return GT2False;
// free the initial message
if(connection->initialMessage)
{
gsifree(connection->initialMessage);
connection->initialMessage = NULL;
}
// new state
connection->state = GTI2AwaitingAcceptance;
return GT2True;
}
static GT2Bool gti2HandleClientResponse(GT2Connection connection, GT2Byte * message, int len)
{
int latency;
// check the state
if(connection->state != GTI2AwaitingClientResponse)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// make sure the message is long enough
if(len < (GTI2_RESPONSE_LEN))
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// check the response
if(!gti2CheckResponse(message, (GT2Byte *)connection->response))
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// need to make sure the connection didn't just stop listening
if(!connection->socket->connectAttemptCallback)
{
// send them a closed
if(!gti2SendClosed(connection))
return GT2False;
// mark it as closed
gti2ConnectionClosed(connection);
return GT2True;
}
// new state
connection->state = GTI2AwaitingAcceptReject;
// calculate the approx. latency
latency = (int)(current_time() - connection->challengeTime);
// it's up to the app now
if(!gti2ConnectAttemptCallback(connection->socket, connection, connection->ip, connection->port, latency, message + GTI2_RESPONSE_LEN, len - GTI2_RESPONSE_LEN))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleAccept(GT2Connection connection)
{
// check the state
if(connection->state != GTI2AwaitingAcceptance)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// new state
connection->state = GTI2Connected;
// call the callback
if(!gti2ConnectedCallback(connection, GT2Success, NULL, 0))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleReject(GT2Connection connection, GT2Byte * message, int len)
{
// check the state
if(connection->state != GTI2AwaitingAcceptance)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// mark it as closed
gti2ConnectionClosed(connection);
// send a closed reply
if(!gti2SendClosed(connection))
return GT2False;
// call the callback
if(!gti2ConnectedCallback(connection, GT2Rejected, message, len))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleClose(GT2Connection connection)
{
GT2Bool localClose;
// send a closed reply
if(!gti2SendClosed(connection))
return GT2False;
// were we attempting to close this connection?
localClose = (connection->state == GTI2Closing);
// handle it as an error (so the right callbacks are called)
if(!gti2ConnectionError(connection, GT2Rejected, localClose?GT2LocalClose:GT2RemoteClose))
return GT2False;
return GT2True;
}
static GT2Bool gti2DeliverReliableMessage(GT2Connection connection, GTI2MessageType type, GT2Byte * message, int len)
{
// bump our ESN
connection->expectedSerialNumber++;
if(type == GTI2MsgAppReliable)
{
if(!gti2HandleAppReliable(connection, message, len))
return GT2False;
}
else if(type == GTI2MsgClientChallenge)
{
if(!gti2HandleClientChallenge(connection, message, len))
return GT2False;
}
else if(type == GTI2MsgServerChallenge)
{
if(!gti2HandleServerChallenge(connection, message, len))
return GT2False;
}
else if(type == GTI2MsgClientResponse)
{
if(!gti2HandleClientResponse(connection, message, len))
return GT2False;
}
else if(type == GTI2MsgAccept)
{
if(!gti2HandleAccept(connection))
return GT2False;
}
else if(type == GTI2MsgReject)
{
if(!gti2HandleReject(connection, message, len))
return GT2False;
}
else if(type == GTI2MsgClose)
{
if(!gti2HandleClose(connection))
return GT2False;
}
else if(type == GTI2MsgKeepAlive)
{
// ignore
}
return GT2True;
}
#ifdef WIN32
static int __cdecl gti2IncomingBufferMessageCompare(const void * elem1, const void * elem2)
#else
static int gti2IncomingBufferMessageCompare(const void * elem1, const void * elem2)
#endif
{
const GTI2IncomingBufferMessage * message1 = (GTI2IncomingBufferMessage *)elem1;
const GTI2IncomingBufferMessage * message2 = (GTI2IncomingBufferMessage *)elem2;
return gti2SNDiff(message1->serialNumber, message2->serialNumber);
}
static GT2Bool gti2BufferIncomingMessage(GT2Connection connection, GTI2MessageType type, unsigned short SN, GT2Byte * message, int len, GT2Bool * overflow)
{
GTI2IncomingBufferMessage messageInfo;
GTI2IncomingBufferMessage * bufferedMessage;
int num;
int i;
// check the number of messages being held
num = ArrayLength(connection->incomingBufferMessages);
// check if this message is already buffered
for(i = 0 ; i < num ; i++)
{
// get the message
bufferedMessage = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, i);
// check if this is the same message
if(bufferedMessage->serialNumber == SN)
{
*overflow = GT2False;
return GT2True;
}
// check if we've already past the target SN
if(gti2SNDiff(bufferedMessage->serialNumber, SN) > 0)
break;
}
// check that there's enough space to store the message
if(gti2GetBufferFreeSpace(&connection->incomingBuffer) < len)
{
*overflow = GT2True;
return GT2True;
}
// setup the message info
messageInfo.start = connection->incomingBuffer.len;
messageInfo.len = len;
messageInfo.type = type;
messageInfo.serialNumber = SN;
// add it to the list
ArrayInsertSorted(connection->incomingBufferMessages, &messageInfo, gti2IncomingBufferMessageCompare);
// make sure the length is one more
if(ArrayLength(connection->incomingBufferMessages) != (num + 1))
{
*overflow = GT2True;
return GT2True;
}
// copy the message into the buffer
gti2BufferWriteData(&connection->incomingBuffer, message, len);
// check for sending a nack
// we want to send one when we think a message or messages were probably dropped
if(num == 0)
{
// if we're the only message in the hold, send a nack
if(!gti2SendNack(connection, connection->expectedSerialNumber, (unsigned short)(SN - 1)))
return GT2False;
}
else
{
GTI2IncomingBufferMessage * msg;
// are we the highest message?
msg = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, num);
if(msg->serialNumber == SN)
{
GTI2IncomingBufferMessage * prev;
unsigned short diff;
// if we're not right after the second-highest SN, the ones in between were probably dropped
prev = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, num - 1);
diff = (unsigned short)gti2SNDiff(SN, prev->serialNumber);
if(diff > 1)
{
if(!gti2SendNack(connection, (unsigned short)(prev->serialNumber + 1), (unsigned short)(SN - 1)))
return GT2False;
}
}
}
*overflow = GT2False;
return GT2True;
}
static void gti2RemoveHoldMessage(GT2Connection connection, GTI2IncomingBufferMessage * message, int index)
{
int moveAfter;
int shortenBy;
int moveEnd = 0;
int num;
int i;
// save off info about it
moveAfter = message->start;
shortenBy = message->len;
// delete it
ArrayDeleteAt(connection->incomingBufferMessages, index);
// loop through and fix up message's stored after this one in the buffer
// also figure out exactly how much data we'll need to move
num = ArrayLength(connection->incomingBufferMessages);
for(i = 0 ; i < num ; i++)
{
// check if this message needs to be moved forward
message = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, i);
if(message->start > moveAfter)
{
message->start -= shortenBy;
moveEnd = max(moveEnd, message->start + message->len);
}
}
// fix up the buffer itself
gti2BufferShorten(&connection->incomingBuffer, moveAfter, shortenBy);
}
static GT2Bool gti2DeliverHoldMessages(GT2Connection connection)
{
GTI2IncomingBufferMessage * message;
int num;
int i;
restart:
// loop through the buffered messages, checking if there are any that can now be delivered
// loop through backwards to ease removal
num = ArrayLength(connection->incomingBufferMessages);
for(i = (num - 1) ; i >= 0 ; i--)
{
message = (GTI2IncomingBufferMessage *)ArrayNth(connection->incomingBufferMessages, i);
// we should deliver this if it's what we're expecting
if(message->serialNumber == connection->expectedSerialNumber)
{
// deliver it
if(!gti2DeliverReliableMessage(connection, message->type, connection->incomingBuffer.buffer + message->start, message->len))
return GT2False;
// remove it
gti2RemoveHoldMessage(connection, message, i);
// we need to go through this loop again.
// goto's are evil, but a little evil is good here
goto restart;
}
}
return GT2True;
}
static void gti2SetPendingAck(GT2Connection connection)
{
// if there's not a pending ack, set one
if(!connection->pendingAck)
{
connection->pendingAck = GT2True;
connection->pendingAckTime = current_time();
}
}
static GT2Bool gti2HandleReliableMessage(GT2Connection connection, GTI2MessageType type, GT2Byte * message, int len)
{
unsigned short SN;
unsigned short ESN;
const int headerLength = connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1 + 2 + 2;
GT2Bool overflow;
// check if it's long enough
if(len < (connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1 + 2 + 2)) // magic string + type + SN + ESN
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// get the SN
SN = gti2UShortFromBuffer(message + connection->socket->protocolOffset, GTI2_MAGIC_STRING_LEN + 1);
// get the ESN
ESN = gti2UShortFromBuffer(message + connection->socket->protocolOffset, GTI2_MAGIC_STRING_LEN + 3);
// update the message and length to point to the actual message
if (connection->socket->protocolType == GTI2VdpProtocol && type == GTI2MsgAppReliable)
{
message[connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 3] = message[0];
message[connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 4] = message[1];
message += headerLength - connection->socket->protocolOffset;
len -= headerLength - connection->socket->protocolOffset;
}
else
{
message += headerLength;
len -= headerLength;
}
// handle the ESN
if(!gti2HandleESN(connection, ESN))
return GT2False;
// check if it's the SN we expected
if(SN == connection->expectedSerialNumber)
{
// make sure we ack this message
// do this before delivering, because we might send an ack as part of a reliable reply
gti2SetPendingAck(connection);
// deliver the message
if(!gti2DeliverReliableMessage(connection, type, message, len))
return GT2False;
// check if there are any messages in the hold that can now be delivered
if(!gti2DeliverHoldMessages(connection))
return GT2False;
return GT2True;
}
// check if the message is a duplicate
if(gti2SNDiff(SN, connection->expectedSerialNumber) < 0)
{
// it's a duplicate, ack it again
gti2SetPendingAck(connection);
// ignore it
return GT2True;
}
// we can't deliver this yet, so put it in the hold
if(!gti2BufferIncomingMessage(connection, type, SN, message, len, &overflow))
return GT2False;
// check for a buffer overflow
if(overflow)
{
if(!gti2ConnectionMemoryError(connection))
return GT2False;
}
return GT2True;
}
static GT2Bool gti2HandleAck(GT2Connection connection, const GT2Byte * message, int len)
{
unsigned short ESN;
// make sure it has enough space for the ESN
if(len != 2)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// get the ESN
ESN = gti2UShortFromBuffer(message, 0);
// handle it
if(!gti2HandleESN(connection, ESN))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleNack(GT2Connection connection, const GT2Byte * message, int len)
{
unsigned short SNMin;
unsigned short SNMax;
int num;
int i;
GTI2OutgoingBufferMessage * messageInfo;
// read based on length.
SNMin = gti2UShortFromBuffer(message, 0);
if(len == 2)
{
SNMax = SNMin;
}
else if(len == 4)
{
SNMax = gti2UShortFromBuffer(message, 2);
}
else
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}
// loop through the messages, resending any specified ones
num = ArrayLength(connection->outgoingBufferMessages);
for(i = 0 ; i < num ; i++)
{
messageInfo = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i);
if((gti2SNDiff(messageInfo->serialNumber, SNMin) >= 0) && (gti2SNDiff(messageInfo->serialNumber, SNMax) <= 0))
{
if(!gti2ResendMessage(connection, messageInfo))
return GT2False;
}
}
return GT2True;
}
static GT2Bool gti2HandlePing(GT2Connection connection, GT2Byte * message, int len)
{
// send it right back
return gti2SendPong(connection, message, len);
}
static GT2Bool gti2HandlePong(GT2Connection connection, const GT2Byte * message, int len)
{
gsi_time startTime;
// do we care about this?
if(!connection->callbacks.ping)
return GT2True;
// is this a pong we're interested in?
// "time" + ping-sent-time
if(len != (4 + sizeof(gsi_time)))
return GT2True;
if(memcmp(message, "time", 4) != 0)
return GT2True;
// get the start time
memcpy(&startTime, message + 4, sizeof(gsi_time));
// call the callback
if(!gti2PingCallback(connection, (int)(current_time() - startTime)))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleClosed(GT2Connection connection)
{
GT2Bool localClose;
// are we already closed?
if(connection->state == GTI2Closed)
return GT2True;
// were we attempting to close this connection?
localClose = (connection->state == GTI2Closing);
// handle it as an error (so the right callbacks are called)
if(!gti2ConnectionError(connection, GT2Rejected, localClose?GT2LocalClose:GT2RemoteClose))
return GT2False;
return GT2True;
}
static GT2Bool gti2HandleUnreliableMessage(GT2Connection connection, GTI2MessageType type, GT2Byte * message, int len)
{
int headerLength;
GT2Byte * dataStart;
int dataLen;
// most unreliable messages don't need the header
headerLength = (connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1);
dataStart = (message + headerLength);
dataLen = (len - headerLength);
// handle unreliable messages based on type
if(type == GTI2MsgAck)
{
if(!gti2HandleAck(connection, dataStart, dataLen))
return GT2False;
}
else if(type == GTI2MsgNack)
{
if(!gti2HandleNack(connection, dataStart, dataLen))
return GT2False;
}
else if(type == GTI2MsgPing)
{
if(!gti2HandlePing(connection, message, len))
return GT2False;
}
else if(type == GTI2MsgPong)
{
if(!gti2HandlePong(connection, dataStart, dataLen))
return GT2False;
}
else if(type == GTI2MsgClosed)
{
if(!gti2HandleClosed(connection))
return GT2False;
}
return GT2True;
}
// VDP sockets have data length which needs to be stripped off
static GT2Bool gti2HandleMessage(GT2Socket socket, GT2Byte * message, int len, unsigned int ip, unsigned short port)
{
GT2Connection connection;
GT2Bool magicString;
GT2Result result;
GTI2MessageType type;
GT2Bool handled;
int actualLength = len - socket->protocolOffset;
// VDP messages have 2 byte header which is removed based on protocol
GT2Byte *actualMessage = message + socket->protocolOffset;
// find out if we have an existing connection for this address
connection = gti2SocketFindConnection(socket, ip, port);
// let the dump handle this
if(socket->receiveDumpCallback)
{
if(!gti2DumpCallback(socket, connection, ip, port, GT2False, message, len, GT2False))
return GT2False;
}
// check if the message starts with the magic string
// use greater than for the len compare because it also must have a type
magicString = ((actualLength > GTI2_MAGIC_STRING_LEN) && (memcmp(actualMessage, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN) == 0));
// check if we don't have a connection
if(!connection)
{
// if we don't know who this is from, let the unrecognized message callback have first crack at it
if(!gti2UnrecognizedMessageCallback(socket, ip, port, message, len, &handled))
return GT2False;
// if they handled it, we don't care about it.
if(handled)
return GT2True;
// if this isn't a connection request, tell them the connection is closed
if(!magicString || (actualMessage[GTI2_MAGIC_STRING_LEN] != GTI2MsgClientChallenge))
{
// if this is a closed message, don't send one back (to avoid recursion)
if(!magicString || (actualMessage[GTI2_MAGIC_STRING_LEN] != GTI2MsgClosed))
{
if(!gti2SendClosedOnSocket(socket, ip, port))
return GT2False;
}
return GT2True;
}
// if we're not listening, we just ignore this
if(!socket->connectAttemptCallback)
return GT2True;
// create a connection
result = gti2NewIncomingConnection(socket, &connection, ip, port);
if(result != GT2Success)
{
// as long as this wasn't a duplicate address error, tell them we're closed
// in the case of duplicates, we don't want to close the existing connection
if(result != GT2DuplicateAddress)
{
if(!gti2SendClosedOnSocket(socket, ip, port))
return GT2False;
}
return GT2True;
}
}
// is the connection already closed?
if(connection->state == GTI2Closed)
{
// if this is a closed message, don't send one back (to avoid recursion)
if(!magicString || (actualMessage[GTI2_MAGIC_STRING_LEN] != GTI2MsgClosed))
{
if(!gti2SendClosed(connection))
return GT2False;
}
return GT2True;
}
// check if this is an unreliable app message with a magic string header
if(magicString && ((actualLength >= (GTI2_MAGIC_STRING_LEN * 2)) && (memcmp(actualMessage + GTI2_MAGIC_STRING_LEN, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN) == 0)))
{
message[3] = message[1];
message[2] = message[0];
message = actualMessage;
actualMessage += socket->protocolOffset;
actualLength -= socket->protocolOffset;
len -= GTI2_MAGIC_STRING_LEN;
magicString = GT2False;
}
// if it doesn't have a magic string it's an app unreliable
if(!magicString)
{
// First determine if the connection found has gone throught the internal challenge response
if (connection->state < GTI2Connected)
{
// pass any message that doesn't have a magic string to
// the app so that the SDK doesn't drop them
if(!gti2UnrecognizedMessageCallback(socket, ip, port, message, len, &handled))
return GT2False;
}
else
{
if(!gti2HandleAppUnreliable(connection, message, len))
return GT2False;
}
return GT2True;
}
// get the message type
type = (GTI2MessageType)actualMessage[GTI2_MAGIC_STRING_LEN];
// check for a bad type
/*if(type < 0)
{
if(!gti2ConnectionCommunicationError(connection))
return GT2False;
return GT2True;
}*/
// check if it's reliable
if(type < GTI2NumReliableMessages)
{
// handle it
if(!gti2HandleReliableMessage(connection, type, message, len))
return GT2False;
return GT2True;
}
// handle unreliable messages
if(!gti2HandleUnreliableMessage(connection, type, message, len))
return GT2False;
return GT2True;
}
GT2Bool gti2HandleConnectionReset(GT2Socket socket, unsigned int ip, unsigned short port)
{
GT2Connection connection;
// find the connection for the reset
connection = gti2SocketFindConnection(socket, ip, port);
// let the dump know about this
if(socket->receiveDumpCallback)
{
if(!gti2DumpCallback(socket, connection, ip, port, GT2True, NULL, 0, GT2False))
return GT2False;
}
// there's no connection, so ignore it
if(!connection)
return GT2True;
// are we waiting for a response from the server?
if(connection->state == GTI2AwaitingServerChallenge)
{
// are we still within the timeout time?
if(!connection->timeout || ((current_time() - connection->startTime) < connection->timeout))
return GT2True;
// report this as a timeout
if(!gti2ConnectionError(connection, GT2TimedOut, GT2RemoteClose))
return GT2False;
}
else
{
// report the error
if(!gti2ConnectionError(connection, GT2Rejected, GT2RemoteClose))
return GT2False;
}
return GT2True;
}
GT2Bool gti2HandleHostUnreachable(GT2Socket socket, unsigned int ip, unsigned short port, GT2Bool send)
{
GT2Connection connection;
// find the connection for the reset
connection = gti2SocketFindConnection(socket, ip, port);
// let the dump know about this
if(socket->receiveDumpCallback)
{
if(!gti2DumpCallback(socket, connection, ip, port, GT2True, NULL, 0, send))
return GT2False;
}
// there's no connection, so ignore it
if(!connection)
return GT2True;
// report the error
if(!gti2ConnectionError(connection, GT2TimedOut, GT2RemoteClose))
return GT2False;
return GT2True;
}
#ifdef GSI_ADHOC
// return length if successful
// <=0 on error
gsi_bool _NetworkAdHocSocketRecv(int socket_id,
char *buf,
int bufferlen,
int flags,
char *saddr, //struct SceNetEtherAddr = char[6];
gsi_u16 *sport);
// return 0 if no data, -1 if error, >0 if data to read
int _NetworkAdHocCanReceiveOnSocket(int socket_id);
GT2Bool gti2ReceiveAdHocMessages(GT2Socket socket,char *buffer, int buffersize)
{
int rcode;
SOCKADDR_IN address;
int addressLen;//, datasize;
// check for messages
while (1)
{
int datasize = _NetworkAdHocCanReceiveOnSocket(socket->socket);
if (datasize < 0) // error
{
gti2SocketError(socket);
return GT2False;
}
if (datasize == 0)
break; // no data
{
// We have data to recv
// receive the message
char mac[6];
gsi_u16 port;
//gsi_u32 ip;
addressLen = sizeof(address);
rcode = _NetworkAdHocSocketRecv(socket->socket, buffer,buffersize , 0, mac,&port);
if(rcode < 0) // fatal socket error
{
#if(0) // notes
if(0)//rcode == WSAECONNRESET)
{
// handle the reset
if(!gti2HandleConnectionReset(socket, address.sin_addr.s_addr, ntohs(address.sin_port)))
return GT2False;
}
else
if (rcode == WSAEHOSTUNREACH)
{
if (!gti2HandleHostUnreachable(socket, address.sin_addr.s_addr, ntohs(address.sin_port), GT2False))
return GT2False;
}
else
#endif
{
gti2SocketError(socket);
return GT2False;
}
}
if(rcode == 0) // no data
{
return GT2False;
}
// at this point we have valid data
// change ethernet to IP address
address.sin_addr.s_addr = gt2MacToIp(mac);
address.sin_port = port;
#ifdef RECV_LOG
// log it
gti2LogMessage(address.sin_addr.s_addr, ntohs(address.sin_port),
socket->ip, socket->port,
buffer, rcode);
#endif
// handle the message
if(!gti2HandleMessage(socket, (GT2Byte *)buffer, rcode, address.sin_addr.s_addr, address.sin_port))
return GT2False;
}
}
return GT2True;
}
#endif
GT2Bool gti2ReceiveMessages(GT2Socket socket)
{
int rcode;
SOCKADDR_IN address;
int addressLen;
// avoid overflowing stack
#if (GTI2_STACK_RECV_BUFFER_SIZE > 1600)
static char buffer[GTI2_STACK_RECV_BUFFER_SIZE];
#else
char buffer[GTI2_STACK_RECV_BUFFER_SIZE];
#endif
#ifdef GSI_ADHOC
if(socket->protocolType == GTI2AdHocProtocol)
{
return gti2ReceiveAdHocMessages(socket,buffer,GTI2_STACK_RECV_BUFFER_SIZE);
}
#endif
// check for messages
while (CanReceiveOnSocket(socket->socket))
{
// mj todo: get this plat specific stuff out of here. Belongs in play specific layer.
// abstract recvfrom
// receive the message
addressLen = sizeof(address);
rcode = recvfrom(socket->socket, buffer, sizeof(buffer), 0, (SOCKADDR *)&address, &addressLen);
if (gsiSocketIsError(rcode))
{
rcode = GOAGetLastError(socket->socket);
if(rcode == WSAECONNRESET)
{
// handle the reset
if(!gti2HandleConnectionReset(socket, address.sin_addr.s_addr, ntohs(address.sin_port)))
return GT2False;
}
#ifndef SN_SYSTEMS
else if (rcode == WSAEHOSTUNREACH)
{
if (!gti2HandleHostUnreachable(socket, address.sin_addr.s_addr, ntohs(address.sin_port), GT2False))
return GT2False;
}
#endif
else if(rcode != WSAEMSGSIZE)
{
// fatal socket error
gti2SocketError(socket);
return GT2False;
}
}
else
{
#ifdef RECV_LOG
// log it
gti2LogMessage(address.sin_addr.s_addr, ntohs(address.sin_port),
socket->ip, socket->port,
buffer, rcode);
#endif
// handle the message
if(!gti2HandleMessage(socket, (GT2Byte *)buffer, rcode, address.sin_addr.s_addr, ntohs(address.sin_port)))
return GT2False;
}
}
return GT2True;
}
static GT2Bool gti2StoreOutgoingReliableMessageInfo(GT2Connection connection, unsigned short SN, int len)
{
GTI2OutgoingBufferMessage messageInfo;
int num;
// setup the message info
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.start = connection->outgoingBuffer.len;
messageInfo.len = len;
messageInfo.serialNumber = SN;
messageInfo.lastSend = current_time();
// check the number of messages before we do the add
num = ArrayLength(connection->outgoingBufferMessages);
// add it to the list
ArrayAppend(connection->outgoingBufferMessages, &messageInfo);
// make sure the length is one more
if(ArrayLength(connection->outgoingBufferMessages) != (num + 1))
return GT2False;
return GT2True;
}
static GT2Bool gti2BeginReliableMessage(GT2Connection connection, GTI2MessageType type, int len, GT2Bool * overflow)
{
int freeSpace;
// VDP data length needed in the front of every packet
unsigned short vdpDataLength = (unsigned short)(len - connection->socket->protocolOffset);
// check how much free space is in the outgoing buffer
freeSpace = gti2GetBufferFreeSpace(&connection->outgoingBuffer);
// do we have the space to hold it?
if(freeSpace < len)
{
if(!gti2ConnectionMemoryError(connection))
return GT2False;
*overflow = GT2True;
return GT2True;
}
// store the message's info
if(!gti2StoreOutgoingReliableMessageInfo(connection, connection->serialNumber, len))
{
if(!gti2ConnectionMemoryError(connection))
return GT2False;
*overflow = GT2True;
return GT2True;
}
// setup the header
if (connection->socket->protocolType == GTI2VdpProtocol)
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)&vdpDataLength, connection->socket->protocolOffset);
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN);
gti2BufferWriteByte(&connection->outgoingBuffer, (GT2Byte)type);
gti2BufferWriteUShort(&connection->outgoingBuffer, connection->serialNumber++);
gti2BufferWriteUShort(&connection->outgoingBuffer, connection->expectedSerialNumber);
*overflow = GT2False;
return GT2True;
}
static GT2Bool gti2EndReliableMessage(GT2Connection connection)
{
GTI2OutgoingBufferMessage * message;
int len;
// the message we're sending is the last one
len = ArrayLength(connection->outgoingBufferMessages);
assert(len > 0);
message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, len - 1);
// send it
if(!gti2ConnectionSendData(connection, connection->outgoingBuffer.buffer + message->start, message->len))
return GT2False;
// we just did an ack (as part of the message)
connection->pendingAck = GT2False;
return GT2True;
}
GT2Bool gti2SendAppReliable(GT2Connection connection, const GT2Byte * message, int len)
{
int totalLen;
GT2Bool overflow;
// magic string + type + SN + ESN + message
totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + len);
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgAppReliable, totalLen, &overflow))
return GT2False;
if(overflow)
return GT2True;
// write the message
gti2BufferWriteData(&connection->outgoingBuffer, message, len);
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendClientChallenge(GT2Connection connection, const char challenge[GTI2_CHALLENGE_LEN])
{
// magic string + type + SN + ESN + challenge
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + GTI2_CHALLENGE_LEN);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgClientChallenge, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// write the challenge
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)challenge, GTI2_CHALLENGE_LEN);
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendServerChallenge(GT2Connection connection, const char response[GTI2_RESPONSE_LEN], const char challenge[GTI2_CHALLENGE_LEN])
{
// magic string + type + SN + ESN + response + challenge
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + GTI2_RESPONSE_LEN + GTI2_CHALLENGE_LEN);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgServerChallenge, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// write the response
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)response, GTI2_RESPONSE_LEN);
// write the challenge
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)challenge, GTI2_CHALLENGE_LEN);
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
// save the time
connection->challengeTime = connection->lastSend;
return GT2True;
}
GT2Bool gti2SendClientResponse(GT2Connection connection, const char response[GTI2_RESPONSE_LEN], const char * message, int len)
{
// magic string + type + SN + ESN + response + message
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + GTI2_RESPONSE_LEN + len);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgClientResponse, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// write the response
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)response, GTI2_RESPONSE_LEN);
// write the message
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)message, len);
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendAccept(GT2Connection connection)
{
// magic string + type + SN + ESN
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgAccept, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendReject(GT2Connection connection, const GT2Byte * message, int len)
{
// magic string + type + SN + ESN + message
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2 + len);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgReject, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// write the message
gti2BufferWriteData(&connection->outgoingBuffer, message, len);
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendClose(GT2Connection connection)
{
// magic string + type + SN + ESN
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgClose, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendKeepAlive(GT2Connection connection)
{
// magic string + type + SN + ESN
int totalLen = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2);
GT2Bool overflow;
// begin the message
if(!gti2BeginReliableMessage(connection, GTI2MsgKeepAlive, totalLen + connection->socket->protocolOffset, &overflow))
return GT2False;
if(overflow)
return GT2True;
// end the message
if(!gti2EndReliableMessage(connection))
return GT2False;
return GT2True;
}
GT2Bool gti2SendAppUnreliable(GT2Connection connection, const GT2Byte * message, int len)
{
int freeSpace;
int totalLen;
GT2Byte * start;
// check if we can send it right away (unreliable that doesn't start with the magic string)
if((len < GTI2_MAGIC_STRING_LEN) ||
(memcmp(message + connection->socket->protocolOffset, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN) != 0))
{
if(!gti2ConnectionSendData(connection, message, len))
return GT2False;
return GT2True;
}
// magic string + message
totalLen = (GTI2_MAGIC_STRING_LEN + len);
// check how much free space is in the outgoing buffer
freeSpace = gti2GetBufferFreeSpace(&connection->outgoingBuffer);
// do we have the space to hold it?
if(freeSpace < totalLen)
{
// just drop it
return GT2True;
}
// store the start of the actual message in the buffer
start = (connection->outgoingBuffer.buffer + connection->outgoingBuffer.len);
// Copy the VDP data length if necessary
if (connection->socket->protocolType == GTI2VdpProtocol)
gti2BufferWriteData(&connection->outgoingBuffer, message, 2);
// copy it in, repeating the magic string at the beginning
gti2BufferWriteData(&connection->outgoingBuffer, (const GT2Byte *)GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN);
// copy the data at the starting position + offset based on the protocol
gti2BufferWriteData(&connection->outgoingBuffer, message + connection->socket->protocolOffset,
(int)(len - connection->socket->protocolOffset));
// do the send
if(!gti2ConnectionSendData(connection, start, totalLen))
return GT2False;
// we don't need to save the message
gti2BufferShorten(&connection->outgoingBuffer, -1, totalLen);
return GT2True;
}
GT2Bool gti2SendAck(GT2Connection connection)
{
// always allocate data length + magic string + type + ESN
// part of the buffer may not be used but more efficience to be on stack
char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1 + 2];
int pos = 0;
// write the VDP data length
if (connection->socket->protocolType == GTI2VdpProtocol)
{
short dataLength = (GTI2_MAGIC_STRING_LEN + 1 + 2);
memcpy(buffer, &dataLength, 2);
pos += 2;
}
// write the magic string
memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN);
pos += GTI2_MAGIC_STRING_LEN;
// write the type
buffer[pos++] = GTI2MsgAck;
// write the ESN
gti2UShortToBuffer((GT2Byte *)buffer, pos, connection->expectedSerialNumber);
pos += 2;
// send it
if(!gti2ConnectionSendData(connection, (const GT2Byte *)buffer, pos))
return GT2False;
// we just did an ack
connection->pendingAck = GT2False;
return GT2True;
}
GT2Bool gti2SendNack(GT2Connection connection, unsigned short SNMin, unsigned short SNMax)
{
// data length + magic string + type + SNMin [+ SNMax]
// part of the buffer may not be used but more efficience to be on stack
char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1 + 2 + 2];
int pos = 0;
// write the VDP data length
if (connection->socket->protocolType == GTI2VdpProtocol)
{
short dataLength = (GTI2_MAGIC_STRING_LEN + 1 + 2 + 2);
memcpy(buffer, &dataLength, 2);
pos += 2;
}
// write the magic string
memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN);
pos += GTI2_MAGIC_STRING_LEN;
// write the type
buffer[pos++] = GTI2MsgNack;
// write the SNMin
gti2UShortToBuffer((GT2Byte *)buffer, pos, SNMin);
pos += 2;
// write the SNMax if it's different
if(SNMin != SNMax)
{
gti2UShortToBuffer((GT2Byte *)buffer, pos, SNMax);
pos += 2;
}
// send it
if(!gti2ConnectionSendData(connection, (const GT2Byte *)buffer, pos))
return GT2False;
return GT2True;
}
GT2Bool gti2SendPing(GT2Connection connection)
{
// data length + magic string + type + "time" + current time
// part of the buffer may not be used but more efficience to be on stack
char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1 + 4 + sizeof(gsi_time)];
int pos = 0;
gsi_time now;
// write the VDP data length
if (connection->socket->protocolType == GTI2VdpProtocol)
{
short dataLength = (GTI2_MAGIC_STRING_LEN + 1 + 4 + sizeof(gsi_time));
memcpy(buffer, &dataLength, 2);
pos += 2;
}
// write the magic string
memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN);
pos += GTI2_MAGIC_STRING_LEN;
// write the type
buffer[pos++] = GTI2MsgPing;
// copy the time id
memcpy(buffer + pos, "time", 4);
pos += 4;
// write the current time
now = current_time();
memcpy(buffer + pos, &now, sizeof(gsi_time));
pos += (int)sizeof(gsi_time);
// send it
if(!gti2ConnectionSendData(connection, (const GT2Byte *)buffer, pos))
return GT2False;
return GT2True;
}
GT2Bool gti2SendPong(GT2Connection connection, GT2Byte * message, int len)
{
// change the ping to a pong
message[GTI2_MAGIC_STRING_LEN] = GTI2MsgPong;
// send it
return gti2ConnectionSendData(connection, message, len);
}
GT2Bool gti2SendClosed(GT2Connection connection)
{
// normal close
return gti2SendClosedOnSocket(connection->socket, connection->ip, connection->port);
}
GT2Bool gti2SendClosedOnSocket(GT2Socket socket, unsigned int ip, unsigned short port)
{
// Vdp data length (not including voice) + magic string + type
// part of the buffer may not be used but more efficience to be on stack
char buffer[MAX_PROTOCOL_OFFSET + GTI2_MAGIC_STRING_LEN + 1];
int pos = 0;
// write the data length
if (socket->protocolType == GTI2VdpProtocol)
{
short dataLength = GTI2_MAGIC_STRING_LEN + 1;
memcpy(buffer, &dataLength, 2);
pos += 2;
}
// write the magic string
memcpy(buffer + pos, GTI2_MAGIC_STRING, GTI2_MAGIC_STRING_LEN);
pos += GTI2_MAGIC_STRING_LEN;
// write the type
buffer[pos++] = GTI2MsgClosed;
// send it
if(!gti2SocketSend(socket, ip, port, (const GT2Byte *)buffer, pos))
return GT2False;
return GT2True;
}
GT2Bool gti2ResendMessage(GT2Connection connection, GTI2OutgoingBufferMessage * message)
{
GTI2MessageType type;
int pos;
// replace the ESN (it's after the magic string, the type, and the SN)
pos = (message->start + connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN + 1 + 2);
gti2UShortToBuffer(connection->outgoingBuffer.buffer, pos, connection->expectedSerialNumber);
// send the message
if(!gti2ConnectionSendData(connection, connection->outgoingBuffer.buffer + message->start, message->len))
return GT2False;
// update the last time sent
message->lastSend = connection->lastSend;
// if it was a server challenge, update that time too
type = (GTI2MessageType)connection->outgoingBuffer.buffer[message->start + connection->socket->protocolOffset + GTI2_MAGIC_STRING_LEN];
if(type == GTI2MsgServerChallenge)
connection->challengeTime = connection->lastSend;
return GT2True;
}
GT2Bool gti2Send(GT2Connection connection, const GT2Byte * message, int len, GT2Bool reliable)
{
if (reliable)
return gti2SendAppReliable(connection, message, len);
//send unreliable messages
return gti2SendAppUnreliable(connection, message, len);
}
GT2Bool gti2WasMessageIDConfirmed(const GT2Connection connection, GT2MessageID messageID)
{
GTI2OutgoingBufferMessage * message;
int len;
// if there are no reliable messages waiting confirmation, then this has already been confirmed
len = ArrayLength(connection->outgoingBufferMessages);
if(!len)
return GT2True;
// get the oldest message waiting confirmation
message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, 0);
// if the message id we are looking for is older than the first one waiting confirmation,
// then it has already been confirmed
if(gti2SNDiff(messageID, message->serialNumber) < 0)
return GT2True;
// the message hasn't been confirmed yet
return GT2False;
}
|