Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | add libwebsockets 2.0.3 (as in Debian 9.7) for undroidwish |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8559fc100523e73fa0f64a343e140b5c |
User & Date: | chw 2019-02-13 18:09:25.699 |
Context
2019-02-13
| ||
18:17 | add tk upstream changes check-in: 788dec3465 user: chw tags: trunk | |
18:09 | add libwebsockets 2.0.3 (as in Debian 9.7) for undroidwish check-in: 8559fc1005 user: chw tags: trunk | |
2019-02-12
| ||
06:15 | improvements in experimental jsmpeg SDL video driver check-in: e7128384f3 user: chw tags: trunk | |
Changes
Added undroid/libwebsockets/Android.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # example Android Native Library makefile # contributed by Gregory Junker <ggjunker@gmail.com> LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libwebsockets LOCAL_CFLAGS := -DLWS_BUILTIN_GETIFADDRS LWS_LIB_PATH := ../../../shared/libwebsockets/lib LOCAL_C_INCLUDES:= $(LOCAL_PATH)/$(LWS_LIB_PATH) LOCAL_SRC_FILES := \ $(LWS_LIB_PATH)/base64-decode.c \ $(LWS_LIB_PATH)/client.c \ $(LWS_LIB_PATH)/client-handshake.c \ $(LWS_LIB_PATH)/client-parser.c \ $(LWS_LIB_PATH)/daemonize.c \ $(LWS_LIB_PATH)/extension.c \ $(LWS_LIB_PATH)/extension-deflate-frame.c \ $(LWS_LIB_PATH)/extension-deflate-stream.c \ $(LWS_LIB_PATH)/getifaddrs.c \ $(LWS_LIB_PATH)/handshake.c \ $(LWS_LIB_PATH)/libwebsockets.c \ $(LWS_LIB_PATH)/md5.c \ $(LWS_LIB_PATH)/output.c \ $(LWS_LIB_PATH)/parsers.c \ $(LWS_LIB_PATH)/sha-1.c include $(BUILD_STATIC_LIBRARY) |
Added undroid/libwebsockets/CMakeLists.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | cmake_minimum_required(VERSION 2.8) if(NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") endif() project(libwebsockets C) set(PACKAGE "libwebsockets") set(CPACK_PACKAGE_NAME "${PACKAGE}") set(CPACK_PACKAGE_VERSION_MAJOR "2") set(CPACK_PACKAGE_VERSION_MINOR "0") set(CPACK_PACKAGE_VERSION_PATCH "3") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") set(CPACK_PACKAGE_VENDOR "andy@warmcat.com") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}") set(SOVERSION "8.1") set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") set(VERSION "${CPACK_PACKAGE_VERSION}") set(LWS_LIBRARY_VERSION ${CPACK_PACKAGE_VERSION}) set(LWS_LIBRARY_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR}) set(LWS_LIBRARY_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR}) set(LWS_LIBRARY_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'") # Try to find the current Git hash. find_package(Git) if(GIT_EXECUTABLE) execute_process( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "${GIT_EXECUTABLE}" describe OUTPUT_VARIABLE GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "whoami" OUTPUT_VARIABLE GIT_USER OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "hostname" OUTPUT_VARIABLE GIT_HOST OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "([^\\])[\\]([^\\])" "\\1\\\\\\\\\\2" GIT_USER ${GIT_USER}) set(LWS_BUILD_HASH ${GIT_USER}@${GIT_HOST}-${GIT_HASH}) message("Git commit hash: ${LWS_BUILD_HASH}") endif() set(LWS_USE_BUNDLED_ZLIB_DEFAULT OFF) if(WIN32) set(LWS_USE_BUNDLED_ZLIB_DEFAULT ON) endif() option(LWS_WITH_STATIC "Build the static version of the library" ON) option(LWS_WITH_SHARED "Build the shared version of the library" ON) option(LWS_WITH_SSL "Include SSL support (default OpenSSL, wolfSSL if LWS_USE_WOLFSSL is set)" ON) option(LWS_USE_CYASSL "Use CyaSSL replacement for OpenSSL. When setting this, you also need to specify LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS" OFF) option(LWS_USE_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this, you also need to specify LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS" OFF) option(LWS_USE_POLARSSL "Use Polarssl (or mbedtls < 2.0) replacement for OpenSSL. When setting this, you also need to specify LWS_POLARSSL_LIBRARIES and LWS_POLARSSL_INCLUDE_DIRS" OFF) option(LWS_USE_MBEDTLS "Use mbedTLS (>=2.0) replacement for OpenSSL. When setting this, you also need to specify LWS_MBEDTLS_LIBRARIES and LWS_MBEDTLS_INCLUDE_DIRS" OFF) option(LWS_WITH_ZLIB "Include zlib support (required for extensions)" ON) option(LWS_WITH_LIBEV "Compile with support for libev" OFF) option(LWS_WITH_LIBUV "Compile with support for libuv" OFF) option(LWS_USE_BUNDLED_ZLIB "Use bundled zlib version (Windows only)" ${LWS_USE_BUNDLED_ZLIB_DEFAULT}) option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-installed CA root certs" ON) option(LWS_WITHOUT_BUILTIN_GETIFADDRS "Don't use the BSD getifaddrs implementation from libwebsockets if it is missing (this will result in a compilation error) ... The default is to assume that your libc provides it. On some systems such as uclibc it doesn't exist." OFF) option(LWS_WITHOUT_BUILTIN_SHA1 "Don't build the lws sha-1 (eg, because openssl will provide it" OFF) option(LWS_WITHOUT_CLIENT "Don't build the client part of the library" OFF) option(LWS_WITHOUT_SERVER "Don't build the server part of the library" OFF) option(LWS_LINK_TESTAPPS_DYNAMIC "Link the test apps to the shared version of the library. Default is to link statically" OFF) option(LWS_WITHOUT_TESTAPPS "Don't build the libwebsocket-test-apps" OFF) option(LWS_WITHOUT_TEST_SERVER "Don't build the test server" OFF) option(LWS_WITHOUT_TEST_SERVER_EXTPOLL "Don't build the test server version that uses external poll" OFF) option(LWS_WITHOUT_TEST_PING "Don't build the ping test application" OFF) option(LWS_WITHOUT_TEST_ECHO "Don't build the echo test application" OFF) option(LWS_WITHOUT_TEST_CLIENT "Don't build the client test application" OFF) option(LWS_WITHOUT_TEST_FRAGGLE "Don't build the ping test application" OFF) option(LWS_WITHOUT_EXTENSIONS "Don't compile with extensions" OFF) option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF) option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" ON) option(LWS_IPV6 "Compile with support for ipv6" OFF) option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket" OFF) option(LWS_WITH_HTTP2 "Compile with support for http2" OFF) option(LWS_MBED3 "Platform is MBED3" OFF) option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF) option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF) option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying" OFF) option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF) option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF) option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF) option(LWS_WITH_SERVER_STATUS "Support json + jscript server monitoring" OFF) if (LWS_WITH_LWSWS) message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV") set(LWS_WITH_PLUGINS 1) set(LWS_WITH_LIBUV 1) set(LWS_WITH_ACCESS_LOG 1) set(LWS_WITH_SERVER_STATUS 1) endif() if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV) message(STATUS "LWS_WITH_PLUGINS --> Enabling LWS_WITH_LIBUV") set(LWS_WITH_LIBUV 1) endif() if (DEFINED YOTTA_WEBSOCKETS_VERSION_STRING) set(LWS_WITH_SHARED OFF) set(LWS_WITH_SSL OFF) set(LWS_WITH_ZLIB OFF) set(LWS_WITHOUT_CLIENT ON) set(LWS_WITHOUT_TESTAPPS ON) set(LWS_WITHOUT_EXTENSIONS ON) set(LWS_WITH_PLUGINS OFF) set(LWS_MBED3 ON) # this implies no pthreads in the lib set(LWS_MAX_SMP 1) endif() if (WIN32) # this implies no pthreads in the lib set(LWS_MAX_SMP 1) endif() if (LWS_WITHOUT_SERVER) set(LWS_WITH_LWSWS OFF) endif() if (LWS_WITH_HTTP_PROXY AND (LWS_WITHOUT_CLIENT OR LWS_WITHOUT_SERVER)) message(FATAL_ERROR "You have to enable both client and server for http proxy") endif() # Allow the user to override installation directories. set(LWS_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") set(LWS_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") set(LWS_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") set(LWS_INSTALL_EXAMPLES_DIR bin CACHE PATH "Installation directory for example files") # Allow the user to use the old CyaSSL options/library in stead of wolfSSL if (LWS_USE_CYASSL AND LWS_USE_WOLFSSL) message(FATAL_ERROR "LWS_USE_CYASSL and LWS_USE_WOLFSSL are mutually exclusive!") endif() if (LWS_USE_CYASSL) # Copy CyaSSL options to the wolfSSL options set(LWS_USE_WOLFSSL ${LWS_USE_CYASSL} CACHE BOOL "Use wolfSSL/CyaSSL instead of OpenSSL" FORCE) set(LWS_WOLFSSL_LIBRARIES ${LWS_CYASSL_LIBRARIES} CACHE PATH "Path to wolfSSL/CyaSSL libraries" FORCE) set(LWS_WOLFSSL_INCLUDE_DIRS ${LWS_CYASSL_INCLUDE_DIRS} CACHE PATH "Path to wolfSSL/CyaSSL header files" FORCE) endif() if (LWS_WITHOUT_CLIENT AND LWS_WITHOUT_SERVER) message(FATAL_ERROR "Makes no sense to compile with neither client nor server.") endif() if (NOT (LWS_WITH_STATIC OR LWS_WITH_SHARED)) message(FATAL_ERROR "Makes no sense to compile with neither static nor shared libraries.") endif() if (NOT LWS_WITHOUT_EXTENSIONS) if (NOT LWS_WITH_ZLIB) message(FATAL_ERROR "zlib is required for extensions.") endif() endif() set(LWS_ZLIB_LIBRARIES CACHE PATH "Path to the zlib library") set(LWS_ZLIB_INCLUDE_DIRS CACHE PATH "Path to the zlib include directory") set(LWS_OPENSSL_LIBRARIES CACHE PATH "Path to the OpenSSL library") set(LWS_OPENSSL_INCLUDE_DIRS CACHE PATH "Path to the OpenSSL include directory") set(LWS_WOLFSSL_LIBRARIES CACHE PATH "Path to the wolfSSL library") set(LWS_WOLFSSL_INCLUDE_DIRS CACHE PATH "Path to the wolfSSL include directory") set(LWS_POLARSSL_LIBRARIES CACHE PATH "Path to the PolarSSL library") set(LWS_POLARSSL_INCLUDE_DIRS CACHE PATH "Path to the PolarSSL include directory") set( CACHE PATH "Path to the libev library") set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory") set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library") set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory") if (NOT LWS_WITH_SSL) set(LWS_WITHOUT_BUILTIN_SHA1 OFF) endif() if (LWS_WITH_SSL AND NOT LWS_USE_WOLFSSL AND NOT LWS_USE_POLARSSL AND NOT LWS_USE_MBEDTLS) if ("${LWS_OPENSSL_LIBRARIES}" STREQUAL "" OR "${LWS_OPENSSL_INCLUDE_DIRS}" STREQUAL "") else() set(OPENSSL_LIBRARIES ${LWS_OPENSSL_LIBRARIES}) set(OPENSSL_INCLUDE_DIRS ${LWS_OPENSSL_INCLUDE_DIRS}) set(OPENSSL_FOUND 1) endif() endif() if (LWS_WITH_SSL AND LWS_USE_WOLFSSL) if ("${LWS_WOLFSSL_LIBRARIES}" STREQUAL "" OR "${LWS_WOLFSSL_INCLUDE_DIRS}" STREQUAL "") if (NOT WOLFSSL_FOUND) if (LWS_USE_CYASSL) message(FATAL_ERROR "You must set LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS when LWS_USE_CYASSL is turned on.") else() message(FATAL_ERROR "You must set LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS when LWS_USE_WOLFSSL is turned on.") endif() endif() else() set(WOLFSSL_LIBRARIES ${LWS_WOLFSSL_LIBRARIES}) set(WOLFSSL_INCLUDE_DIRS ${LWS_WOLFSSL_INCLUDE_DIRS}) set(WOLFSSL_FOUND 1) endif() set(USE_WOLFSSL 1) if (LWS_USE_CYASSL) set(USE_OLD_CYASSL 1) endif() endif() if (LWS_WITH_SSL AND LWS_USE_POLARSSL) if ("${LWS_POLARSSL_LIBRARIES}" STREQUAL "" OR "${LWS_POLARSSL_INCLUDE_DIRS}" STREQUAL "") if (NOT POLARSSL_FOUND) message(FATAL_ERROR "You must set LWS_POLARSSL_LIBRARIES and LWS_POLARSSL_INCLUDE_DIRS when LWS_USE_POLARSSL is turned on.") endif() else() set(POLARSSL_LIBRARIES ${LWS_POLARSSL_LIBRARIES}) set(POLARSSL_INCLUDE_DIRS ${LWS_POLARSSL_INCLUDE_DIRS}) set(POLARSSL_FOUND 1) endif() set(USE_POLARSSL 1) endif() if (LWS_WITH_SSL AND LWS_USE_MBEDTLS) if ("${LWS_MBEDTLS_LIBRARIES}" STREQUAL "" OR "${LWS_MBEDTLS_INCLUDE_DIRS}" STREQUAL "") if (NOT MBEDTLS_FOUND) message(FATAL_ERROR "You must set LWS_MBEDTLS_LIBRARIES and LWS_MBEDTLS_INCLUDE_DIRS when LWS_USE_MBEDTLS is turned on.") endif() else() set(MBEDTLS_LIBRARIES ${LWS_MBEDTLS_LIBRARIES}) set(MBEDTLS_INCLUDE_DIRS ${LWS_MBEDTLS_INCLUDE_DIRS}) set(MBEDTLS_FOUND 1) endif() set(USE_MBEDTLS 1) endif() if (LWS_WITH_ZLIB AND NOT LWS_USE_BUNDLED_ZLIB) if ("${LWS_ZLIB_LIBRARIES}" STREQUAL "" OR "${LWS_ZLIB_INCLUDE_DIRS}" STREQUAL "") else() set(ZLIB_LIBRARIES ${LWS_ZLIB_LIBRARIES}) set(ZLIB_INCLUDE_DIRS ${LWS_ZLIB_INCLUDE_DIRS}) set(ZLIB_FOUND 1) endif() endif() if (LWS_WITH_LIBEV) if ("${LWS_LIBEV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEV_INCLUDE_DIRS}" STREQUAL "") else() set(LIBEV_LIBRARIES ${LWS_LIBEV_LIBRARIES}) set(LIBEV_INCLUDE_DIRS ${LWS_LIBEV_INCLUDE_DIRS}) set(LIBEV_FOUND 1) endif() endif() if (LWS_WITH_LIBUV) if ("${LWS_LIBUV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBUV_INCLUDE_DIRS}" STREQUAL "") else() set(LIBUV_LIBRARIES ${LWS_LIBUV_LIBRARIES}) set(LIBUV_INCLUDE_DIRS ${LWS_LIBUV_INCLUDE_DIRS}) set(LIBUV_FOUND 1) endif() endif() # FIXME: This must be runtime-only option. # The base dir where the test-apps look for the SSL certs. set(LWS_OPENSSL_CLIENT_CERTS ../share CACHE PATH "Server SSL certificate directory") if (WIN32) set(LWS_OPENSSL_CLIENT_CERTS . CACHE PATH "Client SSL certificate directory") if (LWS_IPV6) set(LWS_IPV6 OFF) message(WARNING "IPv6 does not currently work on Windows!") endif() if (LWS_UNIX_SOCK) set(LWS_UNIX_SOCK OFF) message(WARNING "Windows does not support UNIX domain sockets") endif() else() set(LWS_OPENSSL_CLIENT_CERTS /etc/pki/tls/certs/ CACHE PATH "Client SSL certificate directory") endif() if (LWS_WITHOUT_EXTENSIONS) set(LWS_NO_EXTENSIONS 1) endif() if (LWS_WITH_SSL) set(LWS_OPENSSL_SUPPORT 1) endif() if (LWS_SSL_CLIENT_USE_OS_CA_CERTS) set(LWS_SSL_CLIENT_USE_OS_CA_CERTS 1) endif() if (LWS_WITH_LATENCY) set(LWS_LATENCY 1) endif() if (LWS_WITHOUT_DAEMONIZE OR WIN32) set(LWS_NO_DAEMONIZE 1) endif() if (LWS_WITHOUT_SERVER) set(LWS_NO_SERVER 1) endif() if (LWS_WITHOUT_CLIENT) set(LWS_NO_CLIENT 1) endif() if (LWS_WITH_LIBEV) set(LWS_USE_LIBEV 1) endif() if (LWS_WITH_LIBUV) set(LWS_USE_LIBUV 1) endif() if (LWS_IPV6) set(LWS_USE_IPV6 1) endif() if (LWS_UNIX_SOCK) set(LWS_USE_UNIX_SOCK 1) endif() if (LWS_WITH_HTTP2) set(LWS_USE_HTTP2 1) endif() if ("${LWS_MAX_SMP}" STREQUAL "") set(LWS_MAX_SMP 32) endif() #if (LWS_MBED3) # set(CMAKE_C_FLAGS "-D_DEBUG ${CMAKE_C_FLAGS}") #endif() if (MINGW) set(LWS_MINGW_SUPPORT 1) set(CMAKE_C_FLAGS "-D__USE_MINGW_ANSI_STDIO ${CMAKE_C_FLAGS}") endif() if (LWS_SSL_SERVER_WITH_ECDH_CERT) set(LWS_SSL_SERVER_WITH_ECDH_CERT 1) endif() include_directories("${PROJECT_BINARY_DIR}") include(CheckCSourceCompiles) # Check for different inline keyword versions. foreach(KEYWORD "inline" "__inline__" "__inline") set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}") CHECK_C_SOURCE_COMPILES( " #include <stdio.h> static KEYWORD void a() {} int main(int argc, char **argv) { a(); return 0; } " LWS_HAVE_${KEYWORD}) endforeach() if (NOT LWS_HAVE_inline) if (LWS_HAVE___inline__) set(inline __inline__) elseif(LWS_HAVE___inline) set(inline __inline) endif() endif() # Put the libaries and binaries that get built into directories at the # top of the build tree rather than in hard-to-find leaf directories. SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") # Put absolute path of dynamic libraries into the object code. Some # architectures, notably Mac OS X, need this. SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}") include(CheckFunctionExists) include(CheckSymbolExists) include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckTypeSize) if (LWS_WITHOUT_BUILTIN_SHA1) set(LWS_SHA1_USE_OPENSSL_NAME 1) endif() CHECK_FUNCTION_EXISTS(bzero LWS_HAVE_BZERO) CHECK_FUNCTION_EXISTS(fork LWS_HAVE_FORK) CHECK_FUNCTION_EXISTS(getenv LWS_HAVE_GETENV) CHECK_FUNCTION_EXISTS(malloc LWS_HAVE_MALLOC) CHECK_FUNCTION_EXISTS(memset LWS_HAVE_MEMSET) CHECK_FUNCTION_EXISTS(realloc LWS_HAVE_REALLOC) CHECK_FUNCTION_EXISTS(socket LWS_HAVE_SOCKET) CHECK_FUNCTION_EXISTS(strerror LWS_HAVE_STRERROR) CHECK_FUNCTION_EXISTS(vfork LWS_HAVE_VFORK) CHECK_FUNCTION_EXISTS(execvpe LWS_HAVE_EXECVPE) CHECK_FUNCTION_EXISTS(getifaddrs LWS_HAVE_GETIFADDRS) CHECK_FUNCTION_EXISTS(snprintf LWS_HAVE_SNPRINTF) CHECK_FUNCTION_EXISTS(_snprintf LWS_HAVE__SNPRINTF) CHECK_FUNCTION_EXISTS(_vsnprintf LWS_HAVE__VSNPRINTF) CHECK_FUNCTION_EXISTS(getloadavg LWS_HAVE_GETLOADAVG) if (NOT LWS_HAVE_GETIFADDRS) if (LWS_WITHOUT_BUILTIN_GETIFADDRS) message(FATAL_ERROR "No getifaddrs was found on the system. Turn off the LWS_WITHOUT_BUILTIN_GETIFADDRS compile option to use the supplied BSD version.") endif() set(LWS_BUILTIN_GETIFADDRS 1) endif() CHECK_INCLUDE_FILE(dlfcn.h LWS_HAVE_DLFCN_H) CHECK_INCLUDE_FILE(fcntl.h LWS_HAVE_FCNTL_H) CHECK_INCLUDE_FILE(in6addr.h LWS_HAVE_IN6ADDR_H) CHECK_INCLUDE_FILE(inttypes.h LWS_HAVE_INTTYPES_H) CHECK_INCLUDE_FILE(memory.h LWS_HAVE_MEMORY_H) CHECK_INCLUDE_FILE(netinet/in.h LWS_HAVE_NETINET_IN_H) CHECK_INCLUDE_FILE(stdint.h LWS_HAVE_STDINT_H) CHECK_INCLUDE_FILE(stdlib.h LWS_HAVE_STDLIB_H) CHECK_INCLUDE_FILE(strings.h LWS_HAVE_STRINGS_H) CHECK_INCLUDE_FILE(string.h LWS_HAVE_STRING_H) CHECK_INCLUDE_FILE(sys/prctl.h LWS_HAVE_SYS_PRCTL_H) CHECK_INCLUDE_FILE(sys/socket.h LWS_HAVE_SYS_SOCKET_H) CHECK_INCLUDE_FILE(sys/stat.h LWS_HAVE_SYS_STAT_H) CHECK_INCLUDE_FILE(sys/types.h LWS_HAVE_SYS_TYPES_H) CHECK_INCLUDE_FILE(unistd.h LWS_HAVE_UNISTD_H) CHECK_INCLUDE_FILE(vfork.h LWS_HAVE_VFORK_H) if (LWS_WITH_ZLIB AND NOT LWS_USE_BUNDLED_ZLIB) CHECK_INCLUDE_FILE(zlib.h LWS_HAVE_ZLIB_H) endif() # TODO: These can also be tested to see whether they actually work... set(LWS_HAVE_WORKING_FORK LWS_HAVE_FORK) set(LWS_HAVE_WORKING_VFORK LWS_HAVE_VFORK) CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS) # These don't work Cross... #CHECK_TYPE_SIZE(pid_t PID_T_SIZE) #CHECK_TYPE_SIZE(size_t SIZE_T_SIZE) #CHECK_TYPE_SIZE("void *" LWS_SIZEOFPTR LANGUAGE C) if (NOT PID_T_SIZE) set(pid_t int) endif() if (NOT SIZE_T_SIZE) set(size_t "unsigned int") endif() if (NOT LWS_HAVE_MALLOC) set(malloc rpl_malloc) endif() if (NOT LWS_HAVE_REALLOC) set(realloc rpl_realloc) endif() if (MSVC) # Turn off stupid microsoft security warnings. add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) endif(MSVC) include_directories("${PROJECT_SOURCE_DIR}/lib") # Group headers and sources. # Some IDEs use this for nicer file structure. set(HDR_PRIVATE lib/private-libwebsockets.h) set(HDR_PUBLIC "${PROJECT_SOURCE_DIR}/lib/libwebsockets.h" "${PROJECT_BINARY_DIR}/lws_config.h") set(SOURCES lib/base64-decode.c lib/handshake.c lib/libwebsockets.c lib/service.c lib/pollfd.c lib/output.c lib/parsers.c lib/context.c lib/alloc.c lib/header.c) if (NOT LWS_WITHOUT_CLIENT) list(APPEND SOURCES lib/client.c lib/client-handshake.c lib/client-parser.c) endif() if (LWS_WITH_SSL) list(APPEND SOURCES lib/ssl.c) if (NOT LWS_WITHOUT_SERVER) list(APPEND SOURCES lib/ssl-server.c) endif() if (NOT LWS_WITHOUT_CLIENT) list(APPEND SOURCES lib/ssl-client.c) endif() endif() if (NOT LWS_WITHOUT_BUILTIN_SHA1) list(APPEND SOURCES lib/sha-1.c) endif() if (LWS_WITH_HTTP2) list(APPEND SOURCES lib/http2.c lib/hpack.c lib/ssl-http2.c) endif() # select the active platform files if (WIN32) list(APPEND SOURCES lib/lws-plat-win.c) else() if (LWS_MBED3) list(APPEND SOURCES lib/lws-plat-mbed3.cpp lib/lws-plat-mbed3.c) else() list(APPEND SOURCES lib/lws-plat-unix.c) endif() endif() if (NOT LWS_WITHOUT_SERVER) list(APPEND SOURCES lib/server.c lib/server-handshake.c) endif() if (NOT LWS_WITHOUT_EXTENSIONS) list(APPEND HDR_PRIVATE lib/extension-permessage-deflate.h) list(APPEND SOURCES lib/extension.c lib/extension-permessage-deflate.c) endif() if (LWS_WITH_HTTP_PROXY) list(APPEND SOURCES lib/rewrite.c) endif() if (LWS_WITH_LIBEV) list(APPEND SOURCES lib/libev.c) endif() if (LWS_WITH_LIBUV) list(APPEND SOURCES lib/libuv.c) endif() # Add helper files for Windows. if (WIN32) set(WIN32_HELPERS_PATH win32port/win32helpers) include_directories(${WIN32_HELPERS_PATH}) else() # Unix. if (NOT LWS_WITHOUT_DAEMONIZE) list(APPEND SOURCES lib/daemonize.c) endif() endif() if (UNIX) if (NOT LWS_HAVE_GETIFADDRS) list(APPEND HDR_PRIVATE lib/getifaddrs.h) list(APPEND SOURCES lib/getifaddrs.c) endif() endif() if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) include (CheckCCompilerFlag) CHECK_C_COMPILER_FLAG(-fvisibility=hidden LWS_HAVE_VISIBILITY) if (LWS_HAVE_VISIBILITY) set(VISIBILITY_FLAG -fvisibility=hidden) endif() if (UNIX) set(CMAKE_C_FLAGS "-Wall -Werror ${VISIBILITY_FLAG} ${CMAKE_C_FLAGS}" ) else(UNIX) set(CMAKE_C_FLAGS "-Wall ${VISIBILITY_FLAG} ${CMAKE_C_FLAGS}" ) endif(UNIX) endif () if ((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT LWS_WITHOUT_TESTAPPS) if (UNIX) # jeez clang understands -pthread but dies if he sees it at link time! # http://stackoverflow.com/questions/2391194/what-is-gs-pthread-equiv-in-clang set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread" ) endif() endif() if ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) # otherwise osx blows a bunch of openssl deprecated api errors set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations" ) endif() source_group("Headers Private" FILES ${HDR_PRIVATE}) source_group("Headers Public" FILES ${HDR_PUBLIC}) source_group("Sources" FILES ${SOURCES}) # # Create the lib. # set(LWS_LIBRARIES) if (LWS_WITH_STATIC) add_library(websockets STATIC ${HDR_PRIVATE} ${HDR_PUBLIC} ${SOURCES}) list(APPEND LWS_LIBRARIES websockets) if (WIN32) # Windows uses the same .lib ending for static libraries and shared # library linker files, so rename the static library. set_target_properties(websockets PROPERTIES OUTPUT_NAME websockets_static) endif() endif() if (LWS_WITH_SHARED) add_library(websockets_shared SHARED ${HDR_PRIVATE} ${HDR_PUBLIC} ${SOURCES}) list(APPEND LWS_LIBRARIES websockets_shared) # We want the shared lib to be named "libwebsockets" # not "libwebsocket_shared". set_target_properties(websockets_shared PROPERTIES OUTPUT_NAME websockets) if (WIN32) # Compile as DLL (export function declarations) set_property( TARGET websockets_shared PROPERTY COMPILE_DEFINITIONS LWS_DLL LWS_INTERNAL) endif() if (APPLE) set_property(TARGET websockets_shared PROPERTY MACOSX_RPATH YES) endif() endif() # Set the so version of the lib. # Equivalent to LDFLAGS=-version-info x:x:x if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) foreach(lib ${LWS_LIBRARIES}) set_target_properties(${lib} PROPERTIES SOVERSION ${SOVERSION}) endforeach() endif() set(LIB_LIST) # # Find libraries. # # # ZLIB (Only needed for deflate extensions). # if (LWS_WITH_ZLIB) if (LWS_USE_BUNDLED_ZLIB) if (WIN32) set(WIN32_ZLIB_PATH "win32port/zlib") set(ZLIB_SRCS ${WIN32_ZLIB_PATH}/adler32.c ${WIN32_ZLIB_PATH}/compress.c ${WIN32_ZLIB_PATH}/crc32.c ${WIN32_ZLIB_PATH}/deflate.c ${WIN32_ZLIB_PATH}/gzclose.c ${WIN32_ZLIB_PATH}/gzio.c ${WIN32_ZLIB_PATH}/gzlib.c ${WIN32_ZLIB_PATH}/gzread.c ${WIN32_ZLIB_PATH}/gzwrite.c ${WIN32_ZLIB_PATH}/infback.c ${WIN32_ZLIB_PATH}/inffast.c ${WIN32_ZLIB_PATH}/inflate.c ${WIN32_ZLIB_PATH}/inftrees.c ${WIN32_ZLIB_PATH}/trees.c ${WIN32_ZLIB_PATH}/uncompr.c ${WIN32_ZLIB_PATH}/zutil.c) add_library(zlib_internal STATIC ${ZLIB_SRCS}) set(ZLIB_INCLUDE_DIRS ${WIN32_ZLIB_PATH}) get_property(ZLIB_LIBRARIES TARGET zlib_internal PROPERTY LOCATION) set(ZLIB_FOUND 1) # Make sure zlib_internal is compiled before the libs. foreach (lib ${LWS_LIBRARIES}) add_dependencies(${lib} zlib_internal) endforeach() else() message(FATAL_ERROR "Don't have bundled zlib for that platform") endif() elseif (NOT ZLIB_FOUND) find_package(ZLIB REQUIRED) endif() message("zlib include dirs: ${ZLIB_INCLUDE_DIRS}") message("zlib libraries: ${ZLIB_LIBRARIES}") include_directories(${ZLIB_INCLUDE_DIRS}) list(APPEND LIB_LIST ${ZLIB_LIBRARIES}) endif() # # OpenSSL # if (LWS_WITH_SSL) message("Compiling with SSL support") set(chose_ssl 0) if (LWS_USE_WOLFSSL) # Use wolfSSL as OpenSSL replacement. # TODO: Add a find_package command for this also. message("wolfSSL include dir: ${WOLFSSL_INCLUDE_DIRS}") message("wolfSSL libraries: ${WOLFSSL_LIBRARIES}") # Additional to the root directory we need to include # the wolfssl/ subdirectory which contains the OpenSSL # compatibility layer headers. if (LWS_USE_CYASSL) foreach(inc ${WOLFSSL_INCLUDE_DIRS}) include_directories("${inc}" "${inc}/cyassl") endforeach() else() foreach(inc ${WOLFSSL_INCLUDE_DIRS}) include_directories("${inc}" "${inc}/wolfssl") endforeach() endif() list(APPEND LIB_LIST "${WOLFSSL_LIBRARIES}") set(chose_ssl 1) endif() if (LWS_USE_POLARSSL) message("POLARSSL include dir: ${POLARSSL_INCLUDE_DIRS}") message("POLARSSL libraries: ${POLARSSL_LIBRARIES}") foreach(inc ${POLARSSL_INCLUDE_DIRS}) include_directories("${inc}" "${inc}/polarssl") endforeach() list(APPEND LIB_LIST "${POLARSSL_LIBRARIES}") set(chose_ssl 1) endif() if (LWS_USE_MBEDTLS) message("MBEDTLS include dir: ${MBEDTLS_INCLUDE_DIRS}") message("MBEDTLS libraries: ${MBEDTLS_LIBRARIES}") foreach(inc ${MBEDTLS_INCLUDE_DIRS}) include_directories("${inc}" "${inc}/mbedtls") endforeach() list(APPEND LIB_LIST "${MBEDTLS_LIBRARIES}") set(chose_ssl 1) endif() if (NOT chose_ssl) if (NOT OPENSSL_FOUND) # TODO: Add support for STATIC also. find_package(OpenSSL REQUIRED) set(OPENSSL_INCLUDE_DIRS "${OPENSSL_INCLUDE_DIR}") endif() message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIRS}") message("OpenSSL libraries: ${OPENSSL_LIBRARIES}") include_directories("${OPENSSL_INCLUDE_DIRS}") list(APPEND LIB_LIST ${OPENSSL_LIBRARIES}) # older (0.98) Openssl lacks this set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS}) check_include_file(openssl/ecdh.h LWS_HAVE_OPENSSL_ECDH_H) if (LWS_SSL_SERVER_WITH_ECDH_CERT AND NOT LWS_HAVE_OPENSSL_ECDH_H) message(FATAL_ERROR "Missing openssl/ecdh.h, so cannot use LWS_SSL_SERVER_WITH_ECDH_CERT") endif() endif() endif(LWS_WITH_SSL) if (LWS_WITH_LIBEV) if (NOT LIBEV_FOUND) find_path(LIBEV_INCLUDE_DIRS NAMES ev.h) find_library(LIBEV_LIBRARIES NAMES ev) if(LIBEV_INCLUDE_DIRS AND LIBEV_LIBRARIES) set(LIBEV_FOUND 1) endif() endif() message("libev include dir: ${LIBEV_INCLUDE_DIRS}") message("libev libraries: ${LIBEV_LIBRARIES}") include_directories("${LIBEV_INCLUDE_DIRS}") list(APPEND LIB_LIST ${LIBEV_LIBRARIES}) endif(LWS_WITH_LIBEV) if (LWS_WITH_LIBUV) if (NOT LIBUV_FOUND) find_path(LIBUV_INCLUDE_DIRS NAMES uv.h) find_library(LIBUV_LIBRARIES NAMES uv) if(LIBUV_INCLUDE_DIRS AND LIBUV_LIBRARIES) set(LIBUV_FOUND 1) endif() endif() message("libuv include dir: ${LIBUV_INCLUDE_DIRS}") message("libuv libraries: ${LIBUV_LIBRARIES}") include_directories("${LIBUV_INCLUDE_DIRS}") list(APPEND LIB_LIST ${LIBUV_LIBRARIES}) endif() if (LWS_WITH_HTTP_PROXY) find_library(LIBHUBBUB_LIBRARIES NAMES libhubbub) list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} ) endif() # # Platform specific libs. # if (WINCE) list(APPEND LIB_LIST ws2.lib) elseif (WIN32) list(APPEND LIB_LIST ws2_32.lib) endif() if (UNIX) list(APPEND LIB_LIST m) endif() # Setup the linking for all libs. foreach (lib ${LWS_LIBRARIES}) target_link_libraries(${lib} ${LIB_LIST}) endforeach() set (temp ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST}) CHECK_FUNCTION_EXISTS(SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param) CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host) set(CMAKE_REQUIRED_LIBRARIES ${temp}) # Generate the lws_config.h that includes all the public compilation settings. configure_file( "${PROJECT_SOURCE_DIR}/lws_config.h.in" "${PROJECT_BINARY_DIR}/lws_config.h") # Generate the lws_config.h that includes all the private compilation settings. configure_file( "${PROJECT_SOURCE_DIR}/lws_config_private.h.in" "${PROJECT_BINARY_DIR}/lws_config_private.h") # # Test applications # set(TEST_APP_LIST) if (NOT LWS_WITHOUT_TESTAPPS) # # Helper function for adding a test app. # macro(create_test_app TEST_NAME MAIN_SRC S2 S3 S4 S5 S6) set(TEST_SRCS ${MAIN_SRC}) set(TEST_HDR) if ("${S2}" STREQUAL "") else() list(APPEND TEST_SRCS ${S2}) endif() if ("${S3}" STREQUAL "") else() list(APPEND TEST_SRCS ${S3}) endif() if ("${S4}" STREQUAL "") else() list(APPEND TEST_SRCS ${S4}) endif() if ("${S5}" STREQUAL "") else() list(APPEND TEST_SRCS ${S5}) endif() if ("${S6}" STREQUAL "") else() list(APPEND TEST_SRCS ${S6}) endif() if (WIN32) list(APPEND TEST_SRCS ${WIN32_HELPERS_PATH}/getopt.c ${WIN32_HELPERS_PATH}/getopt_long.c ${WIN32_HELPERS_PATH}/gettimeofday.c ) list(APPEND TEST_HDR ${WIN32_HELPERS_PATH}/getopt.h ${WIN32_HELPERS_PATH}/gettimeofday.h ) endif(WIN32) source_group("Headers Private" FILES ${TEST_HDR}) source_group("Sources" FILES ${TEST_SRCS}) add_executable(${TEST_NAME} ${TEST_SRCS} ${TEST_HDR}) if (LWS_LINK_TESTAPPS_DYNAMIC) if (NOT LWS_WITH_SHARED) message(FATAL_ERROR "Build of the shared library is disabled. LWS_LINK_TESTAPPS_DYNAMIC must be combined with LWS_WITH_SHARED.") endif() target_link_libraries(${TEST_NAME} websockets_shared) add_dependencies(${TEST_NAME} websockets_shared) else() if (NOT LWS_WITH_STATIC) message(FATAL_ERROR "Build of the static library is disabled. Disabled LWS_LINK_TESTAPPS_DYNAMIC must be combined with LWS_WITH_STATIC.") endif() target_link_libraries(${TEST_NAME} websockets) add_dependencies(${TEST_NAME} websockets) endif() # Set test app specific defines. set_property(TARGET ${TEST_NAME} PROPERTY COMPILE_DEFINITIONS INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share" ) # Prefix the binary names with libwebsockets. set_target_properties(${TEST_NAME} PROPERTIES OUTPUT_NAME libwebsockets-${TEST_NAME}) # Add to the list of tests. list(APPEND TEST_APP_LIST ${TEST_NAME}) endmacro() if (LWS_WITH_SSL AND NOT LWS_USE_WOLFSSL AND NOT LWS_USE_POLARSSL AND NOT LWS_USE_MBEDTLS) message("Searching for OpenSSL executable and dlls") find_package(OpenSSLbins) message("OpenSSL executable: ${OPENSSL_EXECUTABLE}") endif() if (UNIX AND LWS_WITH_PLUGINS) set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") target_link_libraries(websockets dl) endif() if (NOT LWS_WITHOUT_SERVER) # # test-server # if (NOT LWS_WITHOUT_TEST_SERVER) create_test_app(test-server "test-server/test-server.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c" "test-server/test-server-status.c" "test-server/test-server-echogen.c") if (UNIX) create_test_app(test-fuzxy "test-server/fuzxy.c" "" "" "" "" "") endif() if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))) create_test_app(test-server-pthreads "test-server/test-server-pthreads.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c" "test-server/test-server-status.c" "test-server/test-server-echogen.c") endif() if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_WITH_LIBEV) create_test_app(test-server-libev "test-server/test-server-libev.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c" "test-server/test-server-status.c" "test-server/test-server-echogen.c") endif() if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_WITH_LIBUV) create_test_app(test-server-libuv "test-server/test-server-libuv.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c" "test-server/test-server-status.c" "test-server/test-server-echogen.c") endif() endif() # # test-server-extpoll # if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL) create_test_app(test-server-extpoll "test-server/test-server.c" "test-server/test-server-http.c" "test-server/test-server-dumb-increment.c" "test-server/test-server-mirror.c" "test-server/test-server-status.c" "test-server/test-server-echogen.c") # Set defines for this executable only. set_property( TARGET test-server-extpoll PROPERTY COMPILE_DEFINITIONS EXTERNAL_POLL INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share" ) # We need to link against winsock code. if (WIN32) target_link_libraries(test-server-extpoll ws2_32.lib) endif(WIN32) endif() # # test-server-v2.0 # if (LWS_WITH_PLUGINS) create_test_app( test-server-v2.0 "test-server/test-server-v2.0.c" "" "" "" "" "") endif() # Data files for running the test server. set(TEST_SERVER_DATA "${PROJECT_SOURCE_DIR}/test-server/favicon.ico" "${PROJECT_SOURCE_DIR}/test-server/leaf.jpg" "${PROJECT_SOURCE_DIR}/test-server/libwebsockets.org-logo.png" "${PROJECT_SOURCE_DIR}/test-server/test.html") # Generate self-signed SSL certs for the test-server. if (LWS_WITH_SSL AND OPENSSL_EXECUTABLE AND NOT LWS_WITHOUT_TEST_SERVER) message("Generating SSL Certificates for the test-server...") set(TEST_SERVER_SSL_KEY "${PROJECT_BINARY_DIR}/libwebsockets-test-server.key.pem") set(TEST_SERVER_SSL_CERT "${PROJECT_BINARY_DIR}/libwebsockets-test-server.pem") if (WIN32) if (MINGW) message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -subj \"/C=GB/ST=Erewhon/L=All around/O=libwebsockets-test/CN=localhost\" -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"") execute_process( COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -subj "/C=GB/ST=Erewhon/L=All around/O=libwebsockets-test/CN=localhost" -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}" RESULT_VARIABLE OPENSSL_RETURN_CODE) else() file(WRITE "${PROJECT_BINARY_DIR}/openssl_input.txt" "GB\n" "Erewhon\n" "All around\n" "libwebsockets-test\n" "localhost\n" "none@invalid.org\n\n" ) # The "type" command is a bit picky with paths. file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/openssl_input.txt" OPENSSL_INPUT_WIN_PATH) message("OPENSSL_INPUT_WIN_PATH = ${OPENSSL_INPUT_WIN_PATH}") message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"") execute_process( COMMAND cmd /c type "${OPENSSL_INPUT_WIN_PATH}" COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}" RESULT_VARIABLE OPENSSL_RETURN_CODE OUTPUT_QUIET ERROR_QUIET) message("\n") endif() if (OPENSSL_RETURN_CODE) message(WARNING "!!! Failed to generate SSL certificate for Test Server using cmd.exe !!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}") else() message("SUCCSESFULLY generated SSL certificate") endif() else() # Unix. execute_process( COMMAND printf "GB\\nErewhon\\nAll around\\nlibwebsockets-test\\n\\nlocalhost\\nnone@invalid.org\\n" COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}" RESULT_VARIABLE OPENSSL_RETURN_CODE OUTPUT_QUIET ERROR_QUIET) if (OPENSSL_RETURN_CODE) message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}") else() message("SUCCESSFULLY generated SSL certificate") endif() endif() list(APPEND TEST_SERVER_DATA "${TEST_SERVER_SSL_KEY}" "${TEST_SERVER_SSL_CERT}") endif() add_custom_command(TARGET test-server POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server") # Copy the file needed to run the server so that the test apps can # reach them from their default output location foreach (TEST_FILE ${TEST_SERVER_DATA}) if (EXISTS ${TEST_FILE}) add_custom_command(TARGET test-server POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "${TEST_FILE}" "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server" VERBATIM) endif() endforeach() endif(NOT LWS_WITHOUT_SERVER) if (NOT LWS_WITHOUT_CLIENT) # # test-client # if (NOT LWS_WITHOUT_TEST_CLIENT) create_test_app(test-client "test-server/test-client.c" "" "" "" "" "") endif() # # test-fraggle # if (NOT LWS_WITHOUT_TEST_FRAGGLE) create_test_app(test-fraggle "test-server/test-fraggle.c" "" "" "" "" "") endif() # # test-ping # if (NOT LWS_WITHOUT_TEST_PING) create_test_app(test-ping "test-server/test-ping.c" "" "" "" "" "") endif() # # test-echo # if (NOT LWS_WITHOUT_TEST_ECHO) create_test_app(test-echo "test-server/test-echo.c" "" "" "" "" "") endif() endif(NOT LWS_WITHOUT_CLIENT) if (LWS_WITH_PLUGINS AND LWS_WITH_SHARED) macro(create_plugin PLUGIN_NAME MAIN_SRC) set(PLUGIN_SRCS ${MAIN_SRC}) if (WIN32) list(APPEND PLUGIN_SRCS ${WIN32_HELPERS_PATH}/getopt.c ${WIN32_HELPERS_PATH}/getopt_long.c ${WIN32_HELPERS_PATH}/gettimeofday.c ) list(APPEND PLUGIN_HDR ${WIN32_HELPERS_PATH}/getopt.h ${WIN32_HELPERS_PATH}/gettimeofday.h ) endif(WIN32) source_group("Headers Private" FILES ${PLUGIN_HDR}) source_group("Sources" FILES ${PLUGIN_SRCS}) add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR}) target_link_libraries(${PLUGIN_NAME} websockets_shared) add_dependencies(${PLUGIN_NAME} websockets_shared) # Set test app specific defines. set_property(TARGET ${PLUGIN_NAME} PROPERTY COMPILE_DEFINITIONS INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/plugins" ) # set_target_properties(${PLUGIN_NAME} # PROPERTIES # OUTPUT_NAME ${PLUGIN_NAME}) list(APPEND PLUGINS_LIST ${PLUGIN_NAME}) endmacro() create_plugin(protocol_dumb_increment "plugins/protocol_dumb_increment.c") create_plugin(protocol_lws_mirror "plugins/protocol_lws_mirror.c") create_plugin(protocol_lws_status "plugins/protocol_lws_status.c") if (LWS_WITH_SERVER_STATUS) create_plugin(protocol_lws_server_status "plugins/protocol_lws_server_status.c") endif() endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED) # # Copy OpenSSL dlls to the output directory on Windows. # (Otherwise we'll get an error when trying to run) # if (WIN32 AND LWS_WITH_SSL AND NOT LWS_USE_WOLFSSL) if(OPENSSL_BIN_FOUND) message("OpenSSL dlls found:") message(" Libeay: ${LIBEAY_BIN}") message(" SSLeay: ${SSLEAY_BIN}") foreach(TARGET_BIN ${TEST_APP_LIST}) add_custom_command(TARGET ${TARGET_BIN} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "${LIBEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM) add_custom_command(TARGET ${TARGET_BIN} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "${SSLEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM) endforeach() endif() endif() endif(NOT LWS_WITHOUT_TESTAPPS) if (LWS_WITH_LWSWS) list(APPEND LWSWS_SRCS "lwsws/main.c" "lwsws/lejp.c" "lwsws/conf.c" "lwsws/http.c" ) if (WIN32) list(APPEND LWSWS_SRCS ${WIN32_HELPERS_PATH}/getopt.c ${WIN32_HELPERS_PATH}/getopt_long.c ${WIN32_HELPERS_PATH}/gettimeofday.c ) list(APPEND LWSWS_HDR ${WIN32_HELPERS_PATH}/getopt.h ${WIN32_HELPERS_PATH}/gettimeofday.h ) endif(WIN32) source_group("Headers Private" FILES ${LWSWS_HDR}) source_group("Sources" FILES ${LWSWS_SRCS}) add_executable("lwsws" ${LWSWS_SRCS} ${LWSWS_HDR}) target_link_libraries("lwsws" websockets_shared) add_dependencies("lwsws" websockets_shared) # Set test app specific defines. set_property(TARGET "lwsws" PROPERTY COMPILE_DEFINITIONS INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share" ) endif (LWS_WITH_LWSWS) if (UNIX) # Generate documentation. # TODO: Fix this on Windows. message("Generating API documentation") file(GLOB C_FILES "${PROJECT_SOURCE_DIR}/lib/*.c") list(SORT C_FILES) execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/doc/") execute_process( COMMAND "${PROJECT_SOURCE_DIR}/scripts/kernel-doc" -html ${C_FILES} ${HDR_PUBLIC} OUTPUT_FILE "${PROJECT_BINARY_DIR}/doc/libwebsockets-api-doc.html" ERROR_QUIET) execute_process( COMMAND "${PROJECT_SOURCE_DIR}/scripts/kernel-doc" -text ${C_FILES} ${HDR_PUBLIC} OUTPUT_FILE "${PROJECT_BINARY_DIR}/doc/libwebsockets-api-doc.txt" ERROR_QUIET) # Generate and install pkgconfig. # (This is not indented, because the tabs will be part of the output) file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets.pc" "prefix=\"${CMAKE_INSTALL_PREFIX}\" exec_prefix=\${prefix} libdir=\${exec_prefix}/lib${LIB_SUFFIX} includedir=\${prefix}/include Name: libwebsockets Description: Websockets server and client library Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH} Libs: -L\${libdir} -lwebsockets Cflags: -I\${includedir}" ) install(FILES "${PROJECT_BINARY_DIR}/libwebsockets.pc" DESTINATION lib${LIB_SUFFIX}/pkgconfig) endif(UNIX) # # Installation preparations. # if(WIN32 AND NOT CYGWIN) set(DEF_INSTALL_CMAKE_DIR cmake) else() set(DEF_INSTALL_CMAKE_DIR lib${LIB_SUFFIX}/cmake/libwebsockets) endif() set(LWS_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") # Export targets (This is used for other CMake projects to easily find the libraries and include files). export(TARGETS ${LWS_LIBRARIES} FILE "${PROJECT_BINARY_DIR}/LibwebsocketsTargets.cmake") export(PACKAGE libwebsockets) # Generate the config file for the build-tree. set(LWS__INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/lib" "${PROJECT_BINARY_DIR}") set(LIBWEBSOCKETS_INCLUDE_DIRS ${LWS__INCLUDE_DIRS} CACHE PATH "Libwebsockets include directories") configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in ${PROJECT_BINARY_DIR}/LibwebsocketsConfig.cmake @ONLY) # Generate the config file for the installation tree. get_filename_component(LWS_ABSOLUTE_INSTALL_CMAKE_DIR ${LWS_INSTALL_CMAKE_DIR} ABSOLUTE) get_filename_component(LWS_ABSOLUTE_INSTALL_INCLUDE_DIR ${LWS_INSTALL_INCLUDE_DIR} ABSOLUTE) file(RELATIVE_PATH REL_INCLUDE_DIR "${LWS_ABSOLUTE_INSTALL_CMAKE_DIR}" "${LWS_ABSOLUTE_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the cmake dir. # Note the EVENT_CMAKE_DIR is defined in JanssonConfig.cmake.in, # we escape it here so it's evaluated when it is included instead # so that the include dirs are given relative to where the # config file is located. set(LWS__INCLUDE_DIRS "\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}") configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake @ONLY) # Generate version info for both build-tree and install-tree. configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfigVersion.cmake.in ${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake @ONLY) set_target_properties(${LWS_LIBRARIES} PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}") # # Installation. # # Install libs and headers. install(TARGETS ${LWS_LIBRARIES} EXPORT LibwebsocketsTargets LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT libraries # Windows DLLs PUBLIC_HEADER DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev) set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries") set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files") # Install test apps. if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_CLIENT) install(TARGETS test-client ${TEST_APP_LIST} RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR} COMPONENT examples) set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files") endif() # lwsws if (LWS_WITH_LWSWS) install(TARGETS lwsws RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT lwsws ) endif() # Programs shared files used by the test-server. if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_SERVER) install(FILES ${TEST_SERVER_DATA} DESTINATION share/libwebsockets-test-server COMPONENT examples) if (LWS_WITH_CGI) set(CGI_TEST_SCRIPT "${PROJECT_SOURCE_DIR}/test-server/lws-cgi-test.sh") install(FILES ${CGI_TEST_SCRIPT} PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ DESTINATION share/libwebsockets-test-server COMPONENT examples) endif() endif() # plugins if (LWS_WITH_PLUGINS) install(TARGETS ${PLUGINS_LIST} PERMISSIONS OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ DESTINATION share/libwebsockets-test-server/plugins COMPONENT plugins) if (LWS_WITH_SERVER_STATUS) install(FILES plugins/server-status.html;plugins/lwsws-logo.png DESTINATION share/libwebsockets-test-server/server-status COMPONENT examples) endif() endif() # Install the LibwebsocketsConfig.cmake and LibwebsocketsConfigVersion.cmake install(FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake" "${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake" DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev) # Install exports for the install-tree. install(EXPORT LibwebsocketsTargets DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev) # build subdir is not part of sources set(CPACK_SOURCE_IGNORE_FILES $(CPACK_SOURCE_IGNORE_FILES) ".git" "build" "tgz" "tar.gz") # Most people are more used to "make dist" compared to "make package_source" add_custom_target(dist COMMAND "${CMAKE_MAKE_PROGRAM}" package_source) include(UseRPMTools) if (RPMTools_FOUND) RPMTools_ADD_RPM_TARGETS(libwebsockets libwebsockets.spec) endif() message("---------------------------------------------------------------------") message(" Settings: (For more help do cmake -LH <srcpath>)") message("---------------------------------------------------------------------") message(" LWS_WITH_STATIC = ${LWS_WITH_STATIC}") message(" LWS_WITH_SHARED = ${LWS_WITH_SHARED}") message(" LWS_WITH_SSL = ${LWS_WITH_SSL} (SSL Support)") message(" LWS_SSL_CLIENT_USE_OS_CA_CERTS = ${LWS_SSL_CLIENT_USE_OS_CA_CERTS}") message(" LWS_USE_WOLFSSL = ${LWS_USE_WOLFSSL} (wolfSSL/CyaSSL replacement for OpenSSL)") if (LWS_USE_WOLFSSL) message(" LWS_WOLFSSL_LIBRARIES = ${LWS_WOLFSSL_LIBRARIES}") message(" LWS_WOLFSSL_INCLUDE_DIRS = ${LWS_WOLFSSL_INCLUDE_DIRS}") endif() message(" LWS_USE_POLARSSL = ${LWS_USE_POLARSSL} (PolarSSL replacement for OpenSSL)") message(" LWS_USE_MBEDTLS = ${LWS_USE_MBEDTLS} (mbedtls (nee Polarssl) replacement for OpenSSL)") message(" LWS_WITHOUT_BUILTIN_SHA1 = ${LWS_WITHOUT_BUILTIN_SHA1}") message(" LWS_WITHOUT_BUILTIN_GETIFADDRS = ${LWS_WITHOUT_BUILTIN_GETIFADDRS}") message(" LWS_WITHOUT_CLIENT = ${LWS_WITHOUT_CLIENT}") message(" LWS_WITHOUT_SERVER = ${LWS_WITHOUT_SERVER}") message(" LWS_LINK_TESTAPPS_DYNAMIC = ${LWS_LINK_TESTAPPS_DYNAMIC}") message(" LWS_WITHOUT_TESTAPPS = ${LWS_WITHOUT_TESTAPPS}") message(" LWS_WITHOUT_TEST_SERVER = ${LWS_WITHOUT_TEST_SERVER}") message(" LWS_WITHOUT_TEST_SERVER_EXTPOLL = ${LWS_WITHOUT_TEST_SERVER_EXTPOLL}") message(" LWS_WITHOUT_TEST_PING = ${LWS_WITHOUT_TEST_PING}") message(" LWS_WITHOUT_TEST_ECHO = ${LWS_WITHOUT_TEST_ECHO}") message(" LWS_WITHOUT_TEST_CLIENT = ${LWS_WITHOUT_TEST_CLIENT}") message(" LWS_WITHOUT_TEST_FRAGGLE = ${LWS_WITHOUT_TEST_FRAGGLE}") message(" LWS_WITHOUT_EXTENSIONS = ${LWS_WITHOUT_EXTENSIONS}") message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}") message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}") message(" LWS_USE_LIBEV = ${LWS_USE_LIBEV}") message(" LWS_USE_LIBUV = ${LWS_USE_LIBUV}") message(" LWS_IPV6 = ${LWS_IPV6}") message(" LWS_UNIX_SOCK = ${LWS_UNIX_SOCK}") message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}") message(" LWS_MBED3 = ${LWS_MBED3}") message(" LWS_SSL_SERVER_WITH_ECDH_CERT = ${LWS_SSL_SERVER_WITH_ECDH_CERT}") message(" LWS_MAX_SMP = ${LWS_MAX_SMP}") message(" LWS_WITH_CGI = ${LWS_WITH_CGI}") message(" LWS_HAVE_OPENSSL_ECDH_H = ${LWS_HAVE_OPENSSL_ECDH_H}") message(" LWS_HAVE_SSL_CTX_set1_param = ${LWS_HAVE_SSL_CTX_set1_param}") message(" LWS_WITH_HTTP_PROXY = ${LWS_WITH_HTTP_PROXY}") message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}") message(" PLUGINS = ${PLUGINS_LIST}") message(" LWS_WITH_ACCESS_LOG = ${LWS_WITH_ACCESS_LOG}") message(" LWS_WITH_SERVER_STATUS = ${LWS_WITH_SERVER_STATUS}") message("---------------------------------------------------------------------") # These will be available to parent projects including libwebsockets using add_subdirectory() set(LIBWEBSOCKETS_LIBRARIES ${LWS_LIBRARIES} CACHE STRING "Libwebsocket libraries") if (LWS_WITH_STATIC) set(LIBWEBSOCKETS_LIBRARIES_STATIC websocket CACHE STRING "Libwebsocket static library") endif() if (LWS_WITH_SHARED) set(LIBWEBSOCKETS_LIBRARIES_SHARED websockets_shared CACHE STRING "Libwebsocket shared library") endif() # This must always be last! include(CPack) |
Added undroid/libwebsockets/FindLibWebSockets.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # This module tries to find libWebsockets library and include files # # LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h # LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so # LIBWEBSOCKETS_LIBRARIES, the library to link against # LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets # # This currently works probably only for Linux FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h /usr/local/include /usr/include ) FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets /usr/local/lib /usr/lib ) GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH ) SET ( LIBWEBSOCKETS_FOUND "NO" ) IF ( LIBWEBSOCKETS_INCLUDE_DIR ) IF ( LIBWEBSOCKETS_LIBRARIES ) SET ( LIBWEBSOCKETS_FOUND "YES" ) ENDIF ( LIBWEBSOCKETS_LIBRARIES ) ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR ) MARK_AS_ADVANCED( LIBWEBSOCKETS_LIBRARY_DIR LIBWEBSOCKETS_INCLUDE_DIR LIBWEBSOCKETS_LIBRARIES ) |
Added undroid/libwebsockets/LICENSE.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Libwebsockets and included programs are provided under the terms of the GNU Library General Public License (LGPL) 2.1, with the following exceptions: 1) Static linking of programs with the libwebsockets library does not constitute a derivative work and does not require the author to provide source code for the program, use the shared libwebsockets libraries, or link their program against a user-supplied version of libwebsockets. If you link the program to a modified version of libwebsockets, then the changes to libwebsockets must be provided under the terms of the LGPL in sections 1, 2, and 4. 2) You do not have to provide a copy of the libwebsockets license with programs that are linked to the libwebsockets library, nor do you have to identify the libwebsockets license in your program or documentation as required by section 6 of the LGPL. However, programs must still identify their use of libwebsockets. The following example statement can be included in user documentation to satisfy this requirement: "[program] is based in part on the work of the libwebsockets project (https://libwebsockets.org)" 3) Some sources included have their own, more liberal licenses, or options to get original sources with the liberal terms. Original liberal license retained - lib/sha-1.c - 3-clause BSD license retained, link to original - win32port/zlib - ZLIB license (see zlib.h) Relicensed to libwebsocket license - lib/base64-decode.c - relicensed to LGPL2.1+SLE, link to original - lib/daemonize.c - relicensed from Public Domain to LGPL2.1+SLE, link to original Public Domain version Public Domain (CC-zero) to simplify reuse - test-server/*.c - test-server/*.h 4) lwsws (Libwebsocket web server) is a bundled application that is not part of the libwebsockets library, it's a separate application that uses the library. The related sources are in a separate directory. If you don't distribute lwsws, you do not need to observe its license. - lwsws/lejp.c - LGPL2.1 - lwsws/lejp.h - LGPL2.1 - lwsws/[all else] - GPL2.1 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! |
Added undroid/libwebsockets/README.build.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Introduction to CMake --------------------- CMake is a multi-platform build tool that can generate build files for many different target platforms. See more info at http://www.cmake.org CMake also allows/recommends you to do "out of source"-builds, that is, the build files are separated from your sources, so there is no need to create elaborate clean scripts to get a clean source tree, instead you simply remove your build directory. Libwebsockets has been tested to build successfully on the following platforms with SSL support (both OpenSSL/wolfSSL): - Windows (Visual Studio) - Windows (MinGW) - Linux (x86 and ARM) - OSX - NetBSD Building the library and test apps ---------------------------------- The project settings used by CMake to generate the platform specific build files is called [CMakeLists.txt](CMakeLists.txt). CMake then uses one of its "Generators" to output a Visual Studio project or Make file for instance. To see a list of the available generators for your platform, simply run the "cmake" command. Note that by default OpenSSL will be linked, if you don't want SSL support see below on how to toggle compile options. Building on Unix: ----------------- 1. Install CMake 2.8 or greater: http://cmake.org/cmake/resources/software.html (Most Unix distributions comes with a packaged version also) 2. Install OpenSSL. 3. Generate the build files (default is Make files): ```bash $ cd /path/to/src $ mkdir build $ cd build $ cmake .. ``` (**NOTE**: The `build/`` directory can have any name and be located anywhere on your filesystem, and that the argument `..` given to cmake is simply the source directory of **libwebsockets** containing the [CMakeLists.txt](CMakeLists.txt) project file. All examples in this file assumes you use "..") **NOTE2**: A common option you may want to give is to set the install path, same as --prefix= with autotools. It defaults to /usr/local. You can do this by, eg ```bash $ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. ``` **NOTE3**: On machines that want libraries in lib64, you can also add the following to the cmake line ```bash -DLIB_SUFFIX=64 ``` **NOTE4**: If you are building against a non-distro OpenSSL (eg, in order to get access to ALPN support only in newer OpenSSL versions) the nice way to express that in one cmake command is eg, ```bash $ cmake .. -DOPENSSL_ROOT_DIR=/usr/local/ssl \ -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/usr/local/ssl \ -DLWS_WITH_HTTP2=1 ``` When you run the test apps using non-distro SSL, you have to force them to use your libs, not the distro ones ```bash $ LD_LIBRARY_PATH=/usr/local/ssl/lib libwebsockets-test-server --ssl ``` To get it to build on latest openssl (2016-04-10) it needed this approach ```bash cmake .. -DLWS_WITH_HTTP2=1 -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/include/openssl -DLWS_OPENSSL_LIBRARIES="/usr/local/lib64/libssl.so;/usr/local/lib64/libcrypto.so" ``` **NOTE5**: To build with debug info and _DEBUG for lower priority debug messages compiled in, use ```bash $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG ```` 4. Finally you can build using the generated Makefile: ```bash $ make ``` Quirk of cmake -------------- When changing cmake options, for some reason the only way to get it to see the changes sometimes is delete the contents of your build directory and do the cmake from scratch. Building on Windows (Visual Studio) ----------------------------------- 1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html 2. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html (**NOTE**: Preferably in the default location to make it easier for CMake to find them) **NOTE2**: Be sure that OPENSSL_CONF environment variable is defined and points at <OpenSSL install location>\bin\openssl.cfg 3. Generate the Visual studio project by opening the Visual Studio cmd prompt: ```bash cd <path to src> md build cd build cmake -G "Visual Studio 10" .. ``` (**NOTE**: There is also a cmake-gui available on Windows if you prefer that) **NOTE2**: See this link to find out the version number corresponding to your Visual Studio edition: http://superuser.com/a/194065 4. Now you should have a generated Visual Studio Solution in your `<path to src>/build` directory, which can be used to build. 5. Some additional deps may be needed - iphlpapi.lib - psapi.lib - userenv.lib 6. If you're using libuv, you must make sure to compile libuv with the same multithread-dll / Mtd attributes as libwebsockets itself Building on Windows (MinGW) --------------------------- 1. Install MinGW: http://sourceforge.net/projects/mingw/files (**NOTE**: Preferably in the default location C:\MinGW) 2. Fix up MinGW headers a) Add the following lines to C:\MinGW\include\winsock2.h: ```c #if(_WIN32_WINNT >= 0x0600) typedef struct pollfd { SOCKET fd; SHORT events; SHORT revents; } WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); #endif // (_WIN32_WINNT >= 0x0600) ``` b) Create C:\MinGW\include\mstcpip.h and copy and paste the content from following link into it: http://wine-unstable.sourcearchive.com/documentation/1.1.32/mstcpip_8h-source.html 3. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html 4. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html (**NOTE**: Preferably in the default location to make it easier for CMake to find them) **NOTE2**: Be sure that OPENSSL_CONF environment variable is defined and points at <OpenSSL install location>\bin\openssl.cfg 5. Generate the build files (default is Make files) using MSYS shell: ```bash $ cd /drive/path/to/src $ mkdir build $ cd build $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW .. ``` (**NOTE**: The `build/`` directory can have any name and be located anywhere on your filesystem, and that the argument `..` given to cmake is simply the source directory of **libwebsockets** containing the [CMakeLists.txt](CMakeLists.txt) project file. All examples in this file assumes you use "..") **NOTE2**: To generate build files allowing to create libwebsockets binaries with debug information set the CMAKE_BUILD_TYPE flag to DEBUG: ```bash $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW -DCMAKE_BUILD_TYPE=DEBUG .. ``` 6. Finally you can build using the generated Makefile and get the results deployed into your MinGW installation: ```bash $ make $ make install ``` Setting compile options ----------------------- To set compile time flags you can either use one of the CMake gui applications or do it via command line. Command line ------------ To list avaialable options (ommit the H if you don't want the help text): cmake -LH .. Then to set an option and build (for example turn off SSL support): cmake -DLWS_WITH_SSL=0 .. or cmake -DLWS_WITH_SSL:BOOL=OFF .. Building on mbed3 ----------------- MBED3 is a non-posix embedded OS targeted on Cortex M class chips. https://www.mbed.com/ It's quite unlike any other Posixy platform since the OS is linked statically in with lws to form one binary. At the minute server-only is supported and due to bugs in mbed3 network support, the port is of alpha quality. However it can serve the test html, favicon.ico and logo png and may be able to make ws connections. The binary for that including the OS, test app, lws and all the assets is only 117KB. 0) Today mbed3 only properly works on FRDM K64F $35 Freescale Dev Board with 1MB Flash, 256KB SRAM and Ethernet. http://www.freescale.com/products/arm-processors/kinetis-cortex-m/k-series/k6x-ethernet-mcus/freescale-freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F 1) Get a working mbed3 environment with arm-none-eabi-cs toolchain (available in Fedora, Ubuntu and other distros) 2) Confirm you can build things using yotta by following the getting started guide here https://docs.mbed.com/docs/getting-started-mbed-os/en/latest/ 3) git clone https://github.com/warmcat/lws-test-server and cd into it 4) mkdir -p yotta_modules ; cd yotta_modules 5) git clone https://github.com/warmcat/libwebsockets ; mv libwebsockets websockets ; cd .. 6) yotta target frdm-k64f-gcc 7) yotta install 8) yotta build Unix GUI -------- If you have a curses-enabled build you simply type: (not all packages include this, my debian install does not for example). ccmake Windows GUI ----------- On windows CMake comes with a gui application: Start -> Programs -> CMake -> CMake (cmake-gui) wolfSSL/CyaSSL replacement for OpenSSL -------------------------------------- wolfSSL/CyaSSL is a lightweight SSL library targeted at embedded systems: https://www.wolfssl.com/wolfSSL/Products-wolfssl.html It contains a OpenSSL compatibility layer which makes it possible to pretty much link to it instead of OpenSSL, giving a much smaller footprint. **NOTE**: wolfssl needs to be compiled using the `--enable-opensslextra` flag for this to work. Compiling libwebsockets with wolfSSL ------------------------------------ ```bash cmake .. -DLWS_USE_WOLFSSL=1 \ -DLWS_WOLFSSL_INCLUDE_DIRS=/path/to/wolfssl \ -DLWS_WOLFSSL_LIBRARIES=/path/to/wolfssl/wolfssl.a .. ``` **NOTE**: On windows use the .lib file extension for `LWS_WOLFSSL_LIBRARIES` instead. Compiling libwebsockets with CyaSSL ----------------------------------- ```bash cmake .. -DLWS_USE_CYASSL=1 \ -DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \ -DLWS_CYASSL_LIBRARIES=/path/to/wolfssl/cyassl.a .. ``` **NOTE**: On windows use the .lib file extension for `LWS_CYASSL_LIBRARIES` instead. Compiling libwebsockets with PolarSSL ------------------------------------- Caution... at some point PolarSSL became MbedTLS. But it did not happen all at once. The name changed first then at mbedTLS 2.0 the apis changed. So eg in Fedora 22, there is an "mbedtls" package which is actually using polarssl for the include dir and polarssl apis... this should be treated as polarssl then. Example config for this case is cmake .. -DLWS_USE_POLARSSL=1 -DLWS_POLARSSL_LIBRARIES=/usr/lib64/libmbedtls.so \ -DLWS_POLARSSL_INCLUDE_DIRS=/usr/include/polarssl/ Building plugins outside of lws itself -------------------------------------- The directory ./plugin-standalone/ shows how easy it is to create plugins outside of lws itself. First build lws itself with -DLWS_WITH_PLUGINS, then use the same flow to build the standalone plugin ``` cd ./plugin-standalone mkdir build cd build cmake .. make && sudo make install ``` if you changed the default plugin directory when you built lws, you must also give the same arguments to cmake here (eg, ` -DCMAKE_INSTALL_PREFIX:PATH=/usr/something/else...` ) Otherwise if you run lwsws or libwebsockets-test-server-v2.0, it will now find the additional plugin "libprotocol_example_standalone.so" ``` lwsts[21257]: Plugins: lwsts[21257]: libprotocol_dumb_increment.so lwsts[21257]: libprotocol_example_standalone.so lwsts[21257]: libprotocol_lws_mirror.so lwsts[21257]: libprotocol_lws_server_status.so lwsts[21257]: libprotocol_lws_status.so ``` If you have multiple vhosts, you must enable plugins at the vhost additionally, discovered plugins are not enabled automatically for security reasons. You do this using info->pvo or for lwsws, in the JSON config. Reproducing HTTP2.0 tests ------------------------- You must have built and be running lws against a version of openssl that has ALPN / NPN. Most distros still have older versions. You'll know it's right by seeing ```bash lwsts[4752]: Compiled with OpenSSL support lwsts[4752]: Using SSL mode lwsts[4752]: HTTP2 / ALPN enabled ``` at lws startup. For non-SSL HTTP2.0 upgrade ```bash $ nghttp -nvasu http://localhost:7681/test.htm ``` For SSL / ALPN HTTP2.0 upgrade ``` $ nghttp -nvas https://localhost:7681/test.html ``` Cross compiling --------------- To enable cross-compiling **libwebsockets** using CMake you need to create a "Toolchain file" that you supply to CMake when generating your build files. CMake will then use the cross compilers and build paths specified in this file to look for dependencies and such. **Libwebsockets** includes an example toolchain file [cross-arm-linux-gnueabihf.cmake](cross-arm-linux-gnueabihf.cmake) you can use as a starting point. The commandline to configure for cross with this would look like ```bash $ cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr \ -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake \ -DWITHOUT_EXTENSIONS=1 -DWITH_SSL=0 ``` The example shows how to build with no external cross lib dependencies, you need to provide the cross libraries otherwise. **NOTE**: start from an EMPTY build directory if you had a non-cross build in there before the settings will be cached and your changes ignored. Additional information on cross compilation with CMake: http://www.vtk.org/Wiki/CMake_Cross_Compiling Memory efficiency ----------------- Embedded server-only configuration without extensions (ie, no compression on websocket connections), but with full v13 websocket features and http server, built on ARM Cortex-A9: Update at 8dac94d (2013-02-18) ```bash $ ./configure --without-client --without-extensions --disable-debug --without-daemonize Context Creation, 1024 fd limit[2]: 16720 (includes 12 bytes per fd) Per-connection [3]: 72 bytes, +1328 during headers .text .rodata .data .bss 11512 2784 288 4 ``` This shows the impact of the major configuration with/without options at 13ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES. These are accounting for static allocations from the library elf, there are additional dynamic allocations via malloc. These are a bit old now but give the right idea for relative "expense" of features. Static allocations, ARM9 | | .text | .rodata | .data | .bss | |--------------------------------|---------|---------|-------|------| | All (no without) | 35024 | 9940 | 336 | 4104 | | without client | 25684 | 7144 | 336 | 4104 | | without client, exts | 21652 | 6288 | 288 | 4104 | | without client, exts, debug[1] | 19756 | 3768 | 288 | 4104 | | without server | 30304 | 8160 | 336 | 4104 | | without server, exts | 25382 | 7204 | 288 | 4104 | | without server, exts, debug[1] | 23712 | 4256 | 288 | 4104 | [1] `--disable-debug` only removes messages below `lwsl_notice`. Since that is the default logging level the impact is not noticeable, error, warn and notice logs are all still there. [2] `1024` fd per process is the default limit (set by ulimit) in at least Fedora and Ubuntu. You can make significant savings tailoring this to actual expected peak fds, ie, at a limit of `20`, context creation allocation reduces to `4432 + 240 = 4672`) [3] known header content is freed after connection establishment |
Added undroid/libwebsockets/README.coding.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Daemonization ------------- There's a helper api `lws_daemonize` built by default that does everything you need to daemonize well, including creating a lock file. If you're making what's basically a daemon, just call this early in your init to fork to a headless background process and exit the starting process. Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your daemon is headless, so you'll need to sort out alternative logging, by, eg, syslog. Maximum number of connections ----------------------------- The maximum number of connections the library can deal with is decided when it starts by querying the OS to find out how many file descriptors it is allowed to open (1024 on Fedora for example). It then allocates arrays that allow up to that many connections, minus whatever other file descriptors are in use by the user code. If you want to restrict that allocation, or increase it, you can use ulimit or similar to change the avaiable number of file descriptors, and when restarted **libwebsockets** will adapt accordingly. Libwebsockets is singlethreaded ------------------------------- Directly performing websocket actions from other threads is not allowed. Aside from the internal data being inconsistent in `forked()` processes, the scope of a `wsi` (`struct websocket`) can end at any time during service with the socket closing and the `wsi` freed. Websocket write activities should only take place in the `LWS_CALLBACK_SERVER_WRITEABLE` callback as described below. Only live connections appear in the user callbacks, so this removes any possibility of trying to used closed and freed wsis. If you need to service other socket or file descriptors as well as the websocket ones, you can combine them together with the websocket ones in one poll loop, see "External Polling Loop support" below, and still do it all in one thread / process context. If you insist on trying to use it from multiple threads, take special care if you might simultaneously create more than one context from different threads. SSL_library_init() is called from the context create api and it also is not reentrant. So at least create the contexts sequentially. Only send data when socket writeable ------------------------------------ You should only send data on a websocket connection from the user callback `LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for clients). If you want to send something, do not just send it but request a callback when the socket is writeable using - `lws_callback_on_writable(context, wsi)`` for a specific `wsi`, or - `lws_callback_on_writable_all_protocol(protocol)` for all connections using that protocol to get a callback when next writeable. Usually you will get called back immediately next time around the service loop, but if your peer is slow or temporarily inactive the callback will be delayed accordingly. Generating what to write and sending it should be done in the ...WRITEABLE callback. See the test server code for an example of how to do this. Do not rely on only your own WRITEABLE requests appearing --------------------------------------------------------- Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events if it met network conditions where it had to buffer your send data internally. So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision about what to send, it can't assume that just because the writeable callback came it really is time to send something. It's quite possible you get an 'extra' writeable callback at any time and just need to `return 0` and wait for the expected callback later. Closing connections from the user side -------------------------------------- When you want to close a connection, you do it by returning `-1` from a callback for that connection. You can provoke a callback by calling `lws_callback_on_writable` on the wsi, then notice in the callback you want to close it and just return -1. But usually, the decision to close is made in a callback already and returning -1 is simple. If the socket knows the connection is dead, because the peer closed or there was an affirmitive network error like a FIN coming, then **libwebsockets** will take care of closing the connection automatically. If you have a silently dead connection, it's possible to enter a state where the send pipe on the connection is choked but no ack will ever come, so the dead connection will never become writeable. To cover that, you can use TCP keepalives (see later in this document) Fragmented messages ------------------- To support fragmented messages you need to check for the final frame of a message with `lws_is_final_fragment`. This check can be combined with `libwebsockets_remaining_packet_payload` to gather the whole contents of a message, eg: ``` case LWS_CALLBACK_RECEIVE: { Client * const client = (Client *)user; const size_t remaining = lws_remaining_packet_payload(wsi); if (!remaining && lws_is_final_fragment(wsi)) { if (client->HasFragments()) { client->AppendMessageFragment(in, len, 0); in = (void *)client->GetMessage(); len = client->GetMessageLength(); } client->ProcessMessage((char *)in, len, wsi); client->ResetMessage(); } else client->AppendMessageFragment(in, len, remaining); } break; ``` The test app libwebsockets-test-fraggle sources also show how to deal with fragmented messages. Debug Logging ------------- Also using `lws_set_log_level` api you may provide a custom callback to actually emit the log string. By default, this points to an internal emit function that sends to stderr. Setting it to `NULL` leaves it as it is instead. A helper function `lwsl_emit_syslog()` is exported from the library to simplify logging to syslog. You still need to use `setlogmask`, `openlog` and `closelog` in your user code. The logging apis are made available for user code. - `lwsl_err(...)` - `lwsl_warn(...)` - `lwsl_notice(...)` - `lwsl_info(...)` - `lwsl_debug(...)` The difference between notice and info is that notice will be logged by default whereas info is ignored by default. External Polling Loop support ----------------------------- **libwebsockets** maintains an internal `poll()` array for all of its sockets, but you can instead integrate the sockets into an external polling array. That's needed if **libwebsockets** will cooperate with an existing poll array maintained by another server. Four callbacks `LWS_CALLBACK_ADD_POLL_FD`, `LWS_CALLBACK_DEL_POLL_FD`, `LWS_CALLBACK_SET_MODE_POLL_FD` and `LWS_CALLBACK_CLEAR_MODE_POLL_FD` appear in the callback for protocol 0 and allow interface code to manage socket descriptors in other poll loops. You can pass all pollfds that need service to `lws_service_fd()`, even if the socket or file does not belong to **libwebsockets** it is safe. If **libwebsocket** handled it, it zeros the pollfd `revents` field before returning. So you can let **libwebsockets** try and if `pollfd->revents` is nonzero on return, you know it needs handling by your code. Using with in c++ apps ---------------------- The library is ready for use by C++ apps. You can get started quickly by copying the test server ```bash $ cp test-server/test-server.c test.cpp ``` and building it in C++ like this ```bash $ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets ``` `INSTALL_DATADIR` is only needed because the test server uses it as shipped, if you remove the references to it in your app you don't need to define it on the g++ line either. Availability of header information ---------------------------------- From v1.2 of the library onwards, the HTTP header content is `free()`d as soon as the websocket connection is established. For websocket servers, you can copy interesting headers by handling `LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION` callback, for clients there's a new callback just for this purpose `LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH`. TCP Keepalive ------------- It is possible for a connection which is not being used to send to die silently somewhere between the peer and the side not sending. In this case by default TCP will just not report anything and you will never get any more incoming data or sign the link is dead until you try to send. To deal with getting a notification of that situation, you can choose to enable TCP keepalives on all **libwebsockets** sockets, when you create the context. To enable keepalive, set the ka_time member of the context creation parameter struct to a nonzero value (in seconds) at context creation time. You should also fill ka_probes and ka_interval in that case. With keepalive enabled, the TCP layer will send control packets that should stimulate a response from the peer without affecting link traffic. If the response is not coming, the socket will announce an error at `poll()` forcing a close. Note that BSDs don't support keepalive time / probes / interval per-socket like Linux does. On those systems you can enable keepalive by a nonzero value in `ka_time`, but the systemwide kernel settings for the time / probes/ interval are used, regardless of what nonzero value is in `ka_time`. Optimizing SSL connections -------------------------- There's a member `ssl_cipher_list` in the `lws_context_creation_info` struct which allows the user code to restrict the possible cipher selection at context-creation time. You might want to look into that to stop the ssl peers selecting a cipher which is too computationally expensive. To use it, point it to a string like `"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"` if left `NULL`, then the "DEFAULT" set of ciphers are all possible to select. Async nature of client connections ---------------------------------- When you call `lws_client_connect_info(..)` and get a `wsi` back, it does not mean your connection is active. It just means it started trying to connect. Your client connection is actually active only when you receive `LWS_CALLBACK_CLIENT_ESTABLISHED` for it. There's a 5 second timeout for the connection, and it may give up or die for other reasons, if any of that happens you'll get a `LWS_CALLBACK_CLIENT_CONNECTION_ERROR` callback on protocol 0 instead for the `wsi`. After attempting the connection and getting back a non-`NULL` `wsi` you should loop calling `lws_service()` until one of the above callbacks occurs. As usual, see [test-client.c](test-server/test-client.c) for example code. Lws platform-independent file access apis ----------------------------------------- lws now exposes his internal platform file abstraction in a way that can be both used by user code to make it platform-agnostic, and be overridden or subclassed by user code. This allows things like handling the URI "directory space" as a virtual filesystem that may or may not be backed by a regular filesystem. One example use is serving files from inside large compressed archive storage without having to unpack anything except the file being requested. The test server shows how to use it, basically the platform-specific part of lws prepares a file operations structure that lives in the lws context. The user code can get a pointer to the file operations struct LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * `lws_get_fops`(struct lws_context *context); and then can use helpers to also leverage these platform-independent file handling apis static inline lws_filefd_type `lws_plat_file_open`(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) static inline int `lws_plat_file_close`(struct lws *wsi, lws_filefd_type fd) static inline unsigned long `lws_plat_file_seek_cur`(struct lws *wsi, lws_filefd_type fd, long offset_from_cur_pos) static inline int `lws_plat_file_read`(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) static inline int `lws_plat_file_write`(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) The user code can also override or subclass the file operations, to either wrap or replace them. An example is shown in test server. ECDH Support ------------ ECDH Certs are now supported. Enable the CMake option cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 **and** the info->options flag LWS_SERVER_OPTION_SSL_ECDH to build in support and select it at runtime. SMP / Multithreaded service --------------------------- SMP support is integrated into LWS without any internal threading. It's very simple to use, libwebsockets-test-server-pthread shows how to do it, use -j <n> argument there to control the number of service threads up to 32. Two new members are added to the info struct unsigned int count_threads; unsigned int fd_limit_per_thread; leave them at the default 0 to get the normal singlethreaded service loop. Set count_threads to n to tell lws you will have n simultaneous service threads operating on the context. There is still a single listen socket on one port, no matter how many service threads. When a connection is made, it is accepted by the service thread with the least connections active to perform load balancing. The user code is responsible for spawning n threads running the service loop associated to a specific tsi (Thread Service Index, 0 .. n - 1). See the libwebsockets-test-server-pthread for how to do. If you leave fd_limit_per_thread at 0, then the process limit of fds is shared between the service threads; if you process was allowed 1024 fds overall then each thread is limited to 1024 / n. You can set fd_limit_per_thread to a nonzero number to control this manually, eg the overall supported fd limit is less than the process allowance. You can control the context basic data allocation for multithreading from Cmake using -DLWS_MAX_SMP=, if not given it's set to 32. The serv_buf allocation for the threads (currently 4096) is made at runtime only for active threads. Because lws will limit the requested number of actual threads supported according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to discover how many threads were actually allowed when the context was created. It's required to implement locking in the user code in the same way that libwebsockets-test-server-pthread does it, for the FD locking callbacks. There is no knowledge or dependency in lws itself about pthreads. How the locking is implemented is entirely up to the user code. Libev / Libuv support --------------------- You can select either or both -DLWS_WITH_LIBEV=1 -DLWS_WITH_LIBUV=1 at cmake configure-time. The user application may use one of the context init options flags LWS_SERVER_OPTION_LIBEV LWS_SERVER_OPTION_LIBUV to indicate it will use either of the event libraries. Extension option control from user code --------------------------------------- User code may set per-connection extension options now, using a new api "lws_set_extension_option()". This should be called from the ESTABLISHED callback like this lws_set_extension_option(wsi, "permessage-deflate", "rx_buf_size", "12"); /* 1 << 12 */ If the extension is not active (missing or not negotiated for the connection, or extensions are disabled on the library) the call is just returns -1. Otherwise the connection's extension has its named option changed. The extension may decide to alter or disallow the change, in the example above permessage-deflate restricts the size of his rx output buffer also considering the protocol's rx_buf_size member. Client connections as HTTP[S] rather than WS[S] ----------------------------------------------- You may open a generic http client connection using the same struct lws_client_connect_info used to create client ws[s] connections. To stay in http[s], set the optional info member "method" to point to the string "GET" instead of the default NULL. After the server headers are processed, when payload from the server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP will be made. You can choose whether to process the data immediately, or queue a callback when an outgoing socket is writeable to provide flow control, and process the data in the writable callback. Either way you use the api `lws_http_client_read()` to access the data, eg case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: { char buffer[1024 + LWS_PRE]; char *px = buffer + LWS_PRE; int lenx = sizeof(buffer) - LWS_PRE; lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n"); /* * Often you need to flow control this by something * else being writable. In that case call the api * to get a callback when writable here, and do the * pending client read in the writeable callback of * the output. */ if (lws_http_client_read(wsi, &px, &lenx) < 0) return -1; while (lenx--) putchar(*px++); } break; Using lws v2 vhosts ------------------- If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create your context, it won't create a default vhost using the info struct members for compatibility. Instead you can call lws_create_vhost() afterwards to attach one or more vhosts manually. ``` LWS_VISIBLE struct lws_vhost * lws_create_vhost(struct lws_context *context, struct lws_context_creation_info *info, struct lws_http_mount *mounts); ``` lws_create_vhost() uses the same info struct as lws_create_context(), it ignores members related to context and uses the ones meaningful for vhost (marked with VH in libwebsockets.h). ``` struct lws_context_creation_info { int port; /* VH */ const char *iface; /* VH */ const struct lws_protocols *protocols; /* VH */ const struct lws_extension *extensions; /* VH */ ... ``` When you attach the vhost, if the vhost's port already has a listen socket then both vhosts share it and use SNI (is SSL in use) or the Host: header from the client to select the right one. Or if no other vhost already listening the a new listen socket is created. There are some new members but mainly it's stuff you used to set at context creation time. How lws matches hostname or SNI to a vhost ------------------------------------------ LWS first strips any trailing :port number. Then it tries to find an exact name match for a vhost listening on the correct port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a vhost named abc.com that is listening on port 1234. If there is no exact match, lws will consider wildcard matches, for example if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will accept a vhost "abc.com" listening on port 1234. If there was a better, exact, match, it will have been chosen in preference to this. Connections with SSL will still have the client go on to check the certificate allows wildcards and error out if not. Using lws v2 mounts on a vhost ------------------------------ The last argument to lws_create_vhost() lets you associate a linked list of lws_http_mount structures with that vhost's URL 'namespace', in a similar way that unix lets you mount filesystems into areas of your / filesystem how you like and deal with the contents transparently. ``` struct lws_http_mount { struct lws_http_mount *mount_next; const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */ const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */ const char *def; /* default target, eg, "index.html" */ struct lws_protocol_vhost_options *cgienv; int cgi_timeout; int cache_max_age; unsigned int cache_reusable:1; unsigned int cache_revalidate:1; unsigned int cache_intermediaries:1; unsigned char origin_protocol; unsigned char mountpoint_len; }; ``` The last mount structure should have a NULL mount_next, otherwise it should point to the 'next' mount structure in your list. Both the mount structures and the strings must persist until the context is destroyed, since they are not copied but used in place. `.origin_protocol` should be one of ``` enum { LWSMPRO_HTTP, LWSMPRO_HTTPS, LWSMPRO_FILE, LWSMPRO_CGI, LWSMPRO_REDIR_HTTP, LWSMPRO_REDIR_HTTPS, }; ``` LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and serve it automatically. |
Added undroid/libwebsockets/README.lwsws.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Libwebsockets Web Server ------------------------ lwsws is an implementation of a very lightweight, ws-capable generic web server, which uses libwebsockets to implement everything underneath. Build ----- Just enable -DLWS_WITH_LWSWS=1 at cmake-time. It enables libuv and plugin support automatically. Configuration ------------- lwsws uses JSON config files, they're pure JSON but # may be used to turn the rest of the line into a comment. There is a single file intended for global settings /etc/lwsws/conf ``` # these are the server global settings # stuff related to vhosts should go in one # file per vhost in ../conf.d/ { "global": { "uid": "48", # apache user "gid": "48", # apache user "count-threads": "1", "server-string": "myserver v1", # returned in http headers "init-ssl": "yes" } } ``` and a config directory intended to take one file per vhost /etc/lwsws/conf.d/warmcat.com ``` { "vhosts": [{ "name": "warmcat.com", "port": "443", "interface": "eth0", # optional "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key", # if given enable ssl "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt", "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer", "mounts": [{ # autoserve "mountpoint": "/", "origin": "file:///var/www/warmcat.com", "default": "index.html" }] }] } ``` Vhosts ------ One server can run many vhosts, where SSL is in use SNI is used to match the connection to a vhost and its vhost-specific SSL keys during SSL negotiation. Listing multiple vhosts looks something like this ``` { "vhosts": [ { "name": "localhost", "port": "443", "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", "mounts": [{ "mountpoint": "/", "origin": "file:///var/www/libwebsockets.org", "default": "index.html" }, { "mountpoint": "/testserver", "origin": "file:///usr/local/share/libwebsockets-test-server", "default": "test.html" }], # which protocols are enabled for this vhost, and optional # vhost-specific config options for the protocol # "ws-protocols": [{ "warmcat,timezoom": { "status": "ok" } }] }, { "name": "localhost", "port": "7681", "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", "mounts": [{ "mountpoint": "/", "origin": ">https://localhost" }] }, { "name": "localhost", "port": "80", "mounts": [{ "mountpoint": "/", "origin": ">https://localhost" }] } ] } ``` That sets up three vhosts all called "localhost" on ports 443 and 7681 with SSL, and port 80 without SSL but with a forced redirect to https://localhost Vhost name and port ------------------- The vhost name field is used to match on incoming SNI or Host: header, so it must always be the host name used to reach the vhost externally. - Vhosts may have the same name and different ports, these will each create a listening socket on the appropriate port. - Vhosts may also have the same port and different name: these will be treated as true vhosts on one listening socket and the active vhost decided at SSL negotiation time (via SNI) or if no SSL, then after the Host: header from the client has been parsed. Protocols --------- Vhosts by default have available the union of any initial protocols from context creation time, and any protocols exposed by plugins. Vhosts can select which plugins they want to offer and give them per-vhost settings using this syntax ``` "ws-protocols": [{ "warmcat-timezoom": { "status": "ok" } }] ``` The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options containing the name and value pointers). To indicate that a protocol should be used when no Protocol: header is sent by the client, you can use "default": "1" ``` "ws-protocols": [{ "warmcat-timezoom": { "status": "ok", "default": "1" } }] ``` Other vhost options ------------------- - If the three options `host-ssl-cert`, `host-ssl-ca` and `host-ssl-key` are given, then the vhost supports SSL. Each vhost may have its own certs, SNI is used during the initial connection negotiation to figure out which certs to use by the server name it's asking for from the request DNS name. - `keeplive-timeout` (in secs) defaults to 60 for lwsws, it may be set as a vhost option - `interface` lets you specify which network interface to listen on, if not given listens on all - "`unix-socket`": "1" causes the unix socket specified in the interface option to be used instead of an INET socket - "`sts`": "1" causes lwsws to send a Strict Transport Security header with responses that informs the client he should never accept to connect to this address using http. This is needed to get the A+ security rating from SSL Labs for your server. - "`access-log`": "filepath" sets where apache-compatible access logs will be written - "`ciphers`": "<cipher list>" sets the allowed list of ciphers and key exchange protocols for the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system. If you need to allow weaker ciphers,you can provide an alternative list here per-vhost. - "`ecdh-curve`": "<curve name>" The default ecdh curve is "prime256v1", but you can override it here, per-vhost Mounts ------ Where mounts are given in the vhost definition, then directory contents may be auto-served if it matches the mountpoint. Mount protocols are used to control what kind of translation happens - file:// serve the uri using the remainder of the url past the mountpoint based on the origin directory. Eg, with this mountpoint ``` { "mountpoint": "/", "origin": "file:///var/www/mysite.com", "default": "/" } ``` The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched. - ^http:// or ^https:// these cause any url matching the mountpoint to issue a redirect to the origin url - cgi:// this causes any matching url to be given to the named cgi, eg ``` { "mountpoint": "/git", "origin": "cgi:///var/www/cgi-bin/cgit", "default": "/" }, { "mountpoint": "/cgit-data", "origin": "file:///usr/share/cgit", "default": "/" }, ``` would cause the url /git/myrepo to pass "myrepo" to the cgi /var/www/cgi-bin/cgit and send the results to the client. Note: currently only a fixed set of mimetypes are supported. Other mount options ------------------- 1) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this ``` { "mountpoint": "/git", "origin": "cgi:///var/www/cgi-bin/cgit", "default": "/", "cgi-env": [{ "CGIT_CONFIG": "/etc/cgitrc/libwebsockets.org" }] } ``` This allows you to customize one cgi depending on the mountpoint (and / or vhost). 2) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this ``` "cgi-timeout": "30" ``` 3) Cache policy of the files in the mount can also be set. If no options are given, the content is marked uncacheable. { "mountpoint": "/", "origin": "file:///var/www/mysite.com", "cache-max-age": "60", # seconds "cache-reuse": "1", # allow reuse at client at all "cache-revalidate": "1", # check it with server each time "cache-intermediaries": "1" # allow intermediary caches to hold } 4) You can also define a list of additional mimetypes per-mount "extra-mimetypes": { ".zip": "application/zip", ".doc": "text/evil" } Plugins ------- Protcols and extensions may also be provided from "plugins", these are lightweight dynamic libraries. They are scanned for at init time, and any protocols and extensions found are added to the list given at context creation time. Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction (LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements they can make per-vhost allocations and get hold of the correct pointer from the wsi at the callback. This allows a protocol to choose to strictly segregate data on a per-vhost basis, and also allows the plugin to handle its own initialization and context storage. To help that happen conveniently, there are some new apis - lws_vhost_get(wsi) - lws_protocol_get(wsi) - lws_callback_on_writable_all_protocol_vhost(vhost, protocol) - lws_protocol_vh_priv_zalloc(vhost, protocol, size) - lws_protocol_vh_priv_get(vhost, protocol) dumb increment, mirror and status protocol plugins are provided as examples. Additional plugin search paths ------------------------------ Packages that have their own lws plugins can install them in their own preferred dir and ask lwsws to scan there by using a config fragment like this, in its own conf.d/ file managed by the other package { "global": { "plugin-dir": "/usr/local/share/coherent-timeline/plugins" } } lws-server-status plugin ------------------------ One provided protocol can be used to monitor the server status. Enable the protocol like this on a vhost's ws-protocols section "lws-server-status": { "status": "ok", "update-ms": "5000" } "update-ms" is used to control how often updated JSON is sent on a ws link. And map the provided HTML into the vhost in the mounts section { "mountpoint": "/server-status", "origin": "file:///usr/local/share/libwebsockets-test-server/server-status", "default": "server-status.html" } You might choose to put it on its own vhost which has "interface": "lo", so it's not externally visible. Integration with Systemd ------------------------ lwsws needs a service file like this as `/usr/lib/systemd/system/lwsws.service` ``` [Unit] Description=Libwebsockets Web Server After=syslog.target [Service] ExecStart=/usr/local/bin/lwsws StandardError=null [Install] WantedBy=multi-user.target ``` You can find this prepared in `./lwsws/usr-lib-systemd-system-lwsws.service` Integration with logrotate -------------------------- For correct operation with logrotate, `/etc/logrotate.d/lwsws` (if that's where we're putting the logs) should contain ``` /var/log/lwsws/*log { copytruncate missingok notifempty delaycompress } ``` You can find this prepared in `/lwsws/etc-logrotate.d-lwsws` Prepare the log directory like this ``` sudo mkdir /var/log/lwsws sudo chmod 700 /var/log/lwsws ``` |
Added undroid/libwebsockets/README.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | libwebsockets ------------- This is the libwebsockets C library for lightweight websocket clients and servers. For support, visit https://libwebsockets.org https://github.com/warmcat/libwebsockets and consider joining the project mailing list at https://libwebsockets.org/mailman/listinfo/libwebsockets | News | ------ | We have updated https://libwebsockets.org, if you would like your project using lws featured in the image carousel, send an image, project URL and brief summary to andy@warmcat.com | You can get the latest version of the library from git: - https://github.com/warmcat/libwebsockets - https://libwebsockets.org/git for more information: - [README.build.md](README.build.md) - information on building the library - [README.coding.md](README.coding.md) - information for writing code using the library - [README.test-apps.md](README.test-apps.md) - information about the test apps built with the library After libwebsockets 1.3, tags will be signed using a key corresponding to this public key ``` -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 mQINBFRe35QBEADZA7snW7MoEXkT2deDYZeggVD3694dg1o5G4q36NWjC8Pn/b2V d+L9Nmw8ydKIv8PLJW762rnveQpPYRqCRD8X4bVTYzYz3qsOl5BrYf6cuVn0ZrPB 13TVRg+NZwUaVxc7O+tdOvvEBdA9OCIygctPNK9Nyh53xs5gPHhghZrKVrt0xM1A 2LYsgoHmMBCCY25SHb1nuapvhA3LvuJb4cNNVRCukCoA6yx0uhSEz2AUPJSLqnZ9 XnNBMKq+1a9C+y7jo4O78upTTmuOmRmNEVAu7pxCSUXDrNa87T8n6vFkV/MiW8nv VmhppKJrKPJ0KxJF9b7uG6eKosfoK2PKyE7pAoDN1fuNyBTB0dkFAwyTCN8hmhOg z71QrCltotq/AxSCsKzgFkDBL7D3KUM10QR5kmznjcm8tFWHoSttPR334z/1Yepf ATqH/tfYydW42qeeHgKjfeegnlI65nTDtwYW6lSqZsXg+/ABg0ki9m5HA6l713ig gRbVHSNkiz56O+UOqBtfcJZBc8QZqqixq8rbP2Is0HBBEtD+aFMuKx/sQ3ULkQs2 8dZ5qsGTBT/xHmqpHJsIFX/jwjY5zeEiFbnO5bMH7YLmkjynVsn5zxTyXKQJe29C Uq0Yd9+JpDhHnZoiz/1hIIBsr89Z4Yy6c59YNJ3yJEOast0ODERcKSaUAQARAQAB tC9BbmR5IEdyZWVuIChMaW5hcm8ga2V5KSA8YW5keS5ncmVlbkBsaW5hcm8ub3Jn PokCPQQTAQoAJwUCVF7flAIbAwUJBaOagAULCQgHAwUVCgkICwUWAwIBAAIeAQIX gAAKCRA8ZxoDS3lTexApD/9WT7JWy3tK33OIACYV40XwLEhRam4Xku4rhtsoIeJK P0k/wa7J2PpceX6gKV+QBsOx3UbUfpqZ/Mu7ff3M0J6W87XpKRROAmP43zyiBkmM A6v0pJXozknmCU28p3DuLC8spVDFg9N52xV7Qb+9TDHcTYiVi4swKYuDEuHBC/qa M69+ANgsGbrMFRypxtU7OEhls3AEo3Cq03xD8QvLjFyPpYp1f0vNRFm2Jjgm2CRe YLVsCGxG35Dz7DpJHekHNxje6xsZ2w9Q38M0rLQ0ICOVQ+E1Dir3hwmZQWASzMMi +R0P+MVYpVt5y7KtiLywJ4BzNogS7gY3wQxksJOFA1uuk5h/hO54a361mcdA0Ta5 HHhGKRw87lVjEQSaRjFZmHFClB+Sb8MuWR51JTzVS5HtJlcNqcWhF63vZ8bZ7b6y Aj8cXNjH6ULXyX3QnTUWXX/QU3an3yh8iPONWOGP5d5Hi/qejHGIhP2L5H+h05CP aZQYFLjjebYgEHijuA28eKWsBsoBPFSLpLloHTDkiycgFdV2AkQcxZN9ZElAqURP xUkEIscQg3YhExGiVEtaxBp1/p/WctMxs5HNoi0Oc97ZUcKvSCz9FDGXX9wYBpRf gzjNn055Xn4QyxBDnp5DrYT0ft/8BEnRK0JP6z3gNfnhOxZo4XA+M6w4Hjh3tI2A 3rkCDQRUXt+UARAA0yHmONtW3L1HpvWFR+VgVNHa1HBWWk7lMsI6ajeiUK/lN3F/ +vNbux46bPj/sNT9twbWmYhv6c0yVzCpmv5M5ztefS7mW/zPNLJmCmH32kAvVFr1 Z90R/X+Z1Uh8wCCU72S2pSIXQFza3LF53pbpKi5m1F2icYcx+35egAvvZVZtcrMu TjHUa+N9mFKxa7tb5PI8Lv93nRLwB7aKkp5PKy9Yvse0jACrAAGeIpI73H467/wO ujermKlyPOOv+Lpjd7kedWKdaweitva7FVI20K/afn4AwCI8HJUIqVbil0Yrg9Le M1TRsRydzMQQejsb/cWi3fQ3U3HxvSJijKltckPMqjJaXbqmrLz3FOA5Km0ciIOB WW0Qq0WREcS3rc5FHU29duS9OAieAWFYyLDieug4nQ29KQE6I0lMqLnz8vWYtbmw 6AHk9i2GsXOZiPnztuADgt9o9Os8fm7ZiacA1LISl86P7wpFk+Gf4LRvv8Fk08NV b2K1BY4YC9KP+AynyYQmxmyB1YQCh/dZHiD4ikGKttHAy4ZsMW6IRL5bRP0Z97pA lyBtXP0cGTJtuPt2feh0zaiA7blZ/IDXkB1UqH6jnTa71d1FeNKtVFi8FhPIREN6 Rc5imyRxubZEgsxhdjqGgdT5k6Qr42SewAN391ygutpgGizGQtTwzvmKa0UAEQEA AYkCJQQYAQoADwUCVF7flAIbDAUJBaOagAAKCRA8ZxoDS3lTewuBD/9/rakAMCRC +WmbUVpCbJSWP5ViH87Xko4ku437gq56whcGjQpxfCYt8oeVgS8fZetUOHs2gspJ CEc8TYLUFntfyt2AzKU29oQoizPm33W9S1u7aRGWsVVutd2sqUaQUDsl9z35+Ka9 YcWoATJSWBgnhSAmNcM60OG0P5qrZloTlbRSlDZTSZT3RvY4JWtWCubGsjEpXO4h ZqbKCu3KgV/6NOuTLciriSOZ/iyva3WsCP2S8mRRvma7x04oMTEWX80zozTCK8gG XqqS9eDhCkRbdmMyUQbHIhc/ChYchO5+fQ1o0zMS5cv6xgkhWI3NJRUkNdXolH9a 5F9q4CmCTcdEZkqpnjsLNiQLIENfHbgC0A5IjR6YgN6qAP8ZJ5hBgyTfyKkwB7bW DcCnuoC9R79hkI8nWkoRVou9tdzKxo0bGR6O4CfLj+4d3hpWkv9Rw7Xxygo5JOqN 4cNZGtHkmIFFk9fSXul5rkjfF/XmThIwoI8aHSBZ7j3IMtmkKVkBjNjiTfbgW8RT XIIR+QQdVLOyJqq+NZC/SrKVQITg0ToYJutRTUJViqyz5b3psJo5o2SW6jcexQpE cX6tdPyGz3o0aywfJ9dcN6izleSV1gYmXmIoS0cQyezVqTUkT8C12zeRB7mtWsDa +AWJGq/WfB7N6pPh8S/XMW4e6ptuUodjiA== =HV8t -----END PGP PUBLIC KEY BLOCK----- ``` |
Added undroid/libwebsockets/README.test-apps.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Testing server with a browser ----------------------------- If you run [libwebsockets-test-server](test-server/test-server.c) and point your browser (eg, Chrome) to http://127.0.0.1:7681 It will fetch a script in the form of `test.html`, and then run the script in there on the browser to open a websocket connection. Incrementing numbers should appear in the browser display. By default the test server logs to both stderr and syslog, you can control what is logged using `-d <log level>`, see later. Running test server as a Daemon ------------------------------- You can use the -D option on the test server to have it fork into the background and return immediately. In this daemonized mode all stderr is disabled and logging goes only to syslog, eg, `/var/log/messages` or similar. The server maintains a lockfile at `/tmp/.lwsts-lock` that contains the pid of the master process, and deletes this file when the master process terminates. To stop the daemon, do ```bash $ kill `cat /tmp/.lwsts-lock` ``` If it finds a stale lock (the pid mentioned in the file does not exist any more) it will delete the lock and create a new one during startup. If the lock is valid, the daemon will exit with a note on stderr that it was already running. Using SSL on the server side ---------------------------- To test it using SSL/WSS, just run the test server with ```bash $ libwebsockets-test-server --ssl ``` and use the URL https://127.0.0.1:7681 The connection will be entirely encrypted using some generated certificates that your browser will not accept, since they are not signed by any real Certificate Authority. Just accept the certificates in the browser and the connection will proceed in first https and then websocket wss, acting exactly the same. [test-server.c](test-server/test-server.c) is all that is needed to use libwebsockets for serving both the script html over http and websockets. Testing websocket client support -------------------------------- If you run the test server as described above, you can also connect to it using the test client as well as a browser. ```bash $ libwebsockets-test-client localhost ``` will by default connect to the test server on localhost:7681 and print the dumb increment number from the server at the same time as drawing random circles in the mirror protocol; if you connect to the test server using a browser at the same time you will be able to see the circles being drawn. The test client supports SSL too, use ```bash $ libwebsockets-test-client localhost --ssl -s ``` the -s tells it to accept the default selfsigned cert from the server, otherwise it will strictly fail the connection if there is no CA cert to validate the server's certificate. Choosing between test server variations --------------------------------------- If you will be doing standalone serving with lws, ideally you should avoid making your own server at all, and use lwsws with your own protocol plugins. The second best option is follow test-server-v2.0.c, which uses a mount to autoserve a directory, and lws protocol plugins for ws, without needing any user callback code (other than what's needed in the protocol plugin). For those two options libuv is needed to support the protocol plugins, if that's not possible then the other variations with their own protocol code should be considered. Testing simple echo ------------------- You can test against `echo.websockets.org` as a sanity test like this (the client connects to port `80` by default): ```bash $ libwebsockets-test-echo --client echo.websocket.org ``` This echo test is of limited use though because it doesn't negotiate any protocol. You can run the same test app as a local server, by default on localhost:7681 ```bash $ libwebsockets-test-echo ``` and do the echo test against the local echo server ```bash $ libwebsockets-test-echo --client localhost --port 7681 ``` If you add the `--ssl` switch to both the client and server, you can also test with an encrypted link. Testing SSL on the client side ------------------------------ To test SSL/WSS client action, just run the client test with ```bash $ libwebsockets-test-client localhost --ssl ``` By default the client test applet is set to accept selfsigned certificates used by the test server, this is indicated by the `use_ssl` var being set to `2`. Set it to `1` to reject any server certificate that it doesn't have a trusted CA cert for. Using the websocket ping utility -------------------------------- libwebsockets-test-ping connects as a client to a remote websocket server using 04 protocol and pings it like the normal unix ping utility. ```bash $ libwebsockets-test-ping localhost handshake OK for protocol lws-mirror-protocol Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data. 64 bytes from localhost: req=1 time=0.1ms 64 bytes from localhost: req=2 time=0.1ms 64 bytes from localhost: req=3 time=0.1ms 64 bytes from localhost: req=4 time=0.2ms 64 bytes from localhost: req=5 time=0.1ms 64 bytes from localhost: req=6 time=0.2ms 64 bytes from localhost: req=7 time=0.2ms 64 bytes from localhost: req=8 time=0.1ms ^C --- localhost.localdomain websocket ping statistics --- 8 packets transmitted, 8 received, 0% packet loss, time 7458ms rtt min/avg/max = 0.110/0.185/0.218 ms $ ``` By default it sends 64 byte payload packets using the 04 PING packet opcode type. You can change the payload size using the `-s=` flag, up to a maximum of 125 mandated by the 04 standard. Using the lws-mirror protocol that is provided by the test server, libwebsockets-test-ping can also use larger payload sizes up to 4096 is BINARY packets; lws-mirror will copy them back to the client and they appear as a PONG. Use the `-m` flag to select this operation. The default interval between pings is 1s, you can use the -i= flag to set this, including fractions like `-i=0.01` for 10ms interval. Before you can even use the PING opcode that is part of the standard, you must complete a handshake with a specified protocol. By default lws-mirror-protocol is used which is supported by the test server. But if you are using it on another server, you can specify the protcol to handshake with by `--protocol=protocolname` Fraggle test app ---------------- By default it runs in server mode ```bash $ libwebsockets-test-fraggle libwebsockets test fraggle (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1 Compiled with SSL support, not using it Listening on port 7681 server sees client connect accepted v06 connection Spamming 360 random fragments Spamming session over, len = 371913. sum = 0x2D3C0AE Spamming 895 random fragments Spamming session over, len = 875970. sum = 0x6A74DA1 ... ``` You need to run a second session in client mode, you have to give the `-c` switch and the server address at least: ```bash $ libwebsockets-test-fraggle -c localhost libwebsockets test fraggle (C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1 Client mode Connecting to localhost:7681 denied deflate-stream extension handshake OK for protocol fraggle-protocol client connects to server EOM received 371913 correctly from 360 fragments EOM received 875970 correctly from 895 fragments EOM received 247140 correctly from 258 fragments EOM received 695451 correctly from 692 fragments ... ``` The fraggle test sends a random number up to 1024 fragmented websocket frames each of a random size between 1 and 2001 bytes in a single message, then sends a checksum and starts sending a new randomly sized and fragmented message. The fraggle test client receives the same message fragments and computes the same checksum using websocket framing to see when the message has ended. It then accepts the server checksum message and compares that to its checksum. proxy support ------------- The http_proxy environment variable is respected by the client connection code for both `ws://` and `wss://`. It doesn't support authentication. You use it like this ```bash $ export http_proxy=myproxy.com:3128 $ libwebsockets-test-client someserver.com ``` debug logging ------------- By default logging of severity "notice", "warn" or "err" is enabled to stderr. Again by default other logging is compiled in but disabled from printing. If you want to eliminate the debug logging below notice in severity, use the `--disable-debug` configure option to have it removed from the code by the preprocesser. If you want to see more detailed debug logs, you can control a bitfield to select which logs types may print using the `lws_set_log_level()` api, in the test apps you can use `-d <number>` to control this. The types of logging available are (OR together the numbers to select multiple) - 1 ERR - 2 WARN - 4 NOTICE - 8 INFO - 16 DEBUG - 32 PARSER - 64 HEADER - 128 EXTENSION - 256 CLIENT - 512 LATENCY Websocket version supported --------------------------- The final IETF standard is supported for both client and server, protocol version 13. Latency Tracking ---------------- Since libwebsockets runs using `poll()` and a single threaded approach, any unexpected latency coming from system calls would be bad news. There's now a latency tracking scheme that can be built in with `--with-latency` at configure-time, logging the time taken for system calls to complete and if the whole action did complete that time or was deferred. You can see the detailed data by enabling logging level 512 (eg, `-d 519` on the test server to see that and the usual logs), however even without that the "worst" latency is kept and reported to the logs with NOTICE severity when the context is destroyed. Some care is needed interpreting them, if the action completed the first figure (in us) is the time taken for the whole action, which may have retried through the poll loop many times and will depend on network roundtrip times. High figures here don't indicate a problem. The figure in us reported after "lat" in the logging is the time taken by this particular attempt. High figures here may indicate a problem, or if you system is loaded with another app at that time, such as the browser, it may simply indicate the OS gave preferential treatment to the other app during that call. Autobahn Test Suite ------------------- Lws can be tested against the autobahn websocket fuzzer. 1) pip install autobahntestsuite 2) wstest -m fuzzingserver 3) Run tests like this libwebsockets-test-echo --client localhost --port 9001 -u "/runCase?case=20&agent=libwebsockets" -v -d 65535 -n 1 (this runs test 20) 4) In a browser, go here http://localhost:8080/test_browser.html fill in "libwebsockets" in "User Agent Identifier" and press "Update Reports (Manual)" 5) In a browser go to the directory you ran wstest in (eg, /projects/libwebsockets) file:///projects/libwebsockets/reports/clients/index.html to see the results Autobahn Test Notes ------------------- 1) Autobahn tests the user code + lws implementation. So to get the same results, you need to follow test-echo.c in terms of user implmentation. 2) Some of the tests make no sense for Libwebsockets to support and we fail them. - Tests 2.10 + 2.11: sends multiple pings on one connection. Lws policy is to only allow one active ping in flight on each connection, the rest are dropped. The autobahn test itself admits this is not part of the standard, just someone's random opinion about how they think a ws server should act. So we will fail this by design and it is no problem about RFC6455 compliance. |
Added undroid/libwebsockets/appveyor.yml.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | environment: matrix: - LWS_METHOD: lwsws CMAKE_ARGS: -DLWS_WITH_LWSWS=1 -DLIBUV_INCLUDE_DIRS=C:\assets\libuv\include -DLIBUV_LIBRARIES=C:\assets\libuv\libuv.lib - LWS_METHOD: default - LWS_METHOD: noserver CMAKE_ARGS: -DLWS_WITHOUT_SERVER=ON - LWS_METHOD: noclient CMAKE_ARGS: -DLWS_WITHOUT_CLIENT=ON - LWS_METHOD: noext CMAKE_ARGS: -DLWS_WITHOUT_EXTENSIONS=ON - LWS_METHOD: nossl CMAKE_ARGS: -DLWS_WITH_SSL=OFF install: - appveyor DownloadFile https://libwebsockets.org:444/win-libuv.zip - mkdir c:\assets - mkdir c:\assets\libuv - 7z x -oc:\assets\libuv win-libuv.zip # - appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe - appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2h.exe - Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes - appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe - cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis - SET PATH=C:\Program Files\NSIS\;C:\Program Files (x86)\NSIS\;c:\nsis;%PATH% build: build_script: - md build - cd build - cmake -DCMAKE_BUILD_TYPE=Release %CMAKE_ARGS% .. - cmake --build . --config Release # TODO: Keeps breaking Windows build, should be rewritten using CPack properly instead... #after_build: # - cd .. # - cd win32port # - makensis -DVERSION=%APPVEYOR_BUILD_VERSION% libwebsockets.nsi artifacts: - name: Installer path: 'win32port/libwebsockets-*-install.exe' cache: - C:\OpenSSL-Win32 matrix: fast_finish: true |
Added undroid/libwebsockets/autobahn-test.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/sh N=1 for i in '1.1.1' '1.1.2' '1.1.3' '1.1.4' '1.1.5' '1.1.6' '1.1.7' '1.1.8' '1.2.1' '1.2.2' '1.2.3' '1.2.4' '1.2.5' '1.2.6' '1.2.7' '1.2.8' '2.1' '2.2' '2.3' '2.4' '2.5' '2.6' '2.7' '2.8' '2.9' '2.10' '2.11' '3.1' '3.2' '3.3' '3.4' '3.5' '3.6' '3.7' '4.1.1' '4.1.2' '4.1.3' '4.1.4' '4.1.5' '4.2.1' '4.2.2' '4.2.3' '4.2.4' '4.2.5' '5.1' '5.2' '5.3' '5.4' '5.5' '5.6' '5.7' '5.8' '5.9' '5.10' '5.11' '5.12' '5.13' '5.14' '5.15' '5.16' '5.17' '5.18' '5.19' '5.20' '6.1.1' '6.1.2' '6.1.3' '6.2.1' '6.2.2' '6.2.3' '6.2.4' '6.3.1' '6.3.2' '6.4.1' '6.4.2' '6.4.3' '6.4.4' '6.5.1' '6.5.2' '6.5.3' '6.5.4' '6.5.5' '6.6.1' '6.6.2' '6.6.3' '6.6.4' '6.6.5' '6.6.6' '6.6.7' '6.6.8' '6.6.9' '6.6.10' '6.6.11' '6.7.1' '6.7.2' '6.7.3' '6.7.4' '6.8.1' '6.8.2' '6.9.1' '6.9.2' '6.9.3' '6.9.4' '6.10.1' '6.10.2' '6.10.3' '6.11.1' '6.11.2' '6.11.3' '6.11.4' '6.11.5' '6.12.1' '6.12.2' '6.12.3' '6.12.4' '6.12.5' '6.12.6' '6.12.7' '6.12.8' '6.13.1' '6.13.2' '6.13.3' '6.13.4' '6.13.5' '6.14.1' '6.14.2' '6.14.3' '6.14.4' '6.14.5' '6.14.6' '6.14.7' '6.14.8' '6.14.9' '6.14.10' '6.15.1' '6.16.1' '6.16.2' '6.16.3' '6.17.1' '6.17.2' '6.17.3' '6.17.4' '6.17.5' '6.18.1' '6.18.2' '6.18.3' '6.18.4' '6.18.5' '6.19.1' '6.19.2' '6.19.3' '6.19.4' '6.19.5' '6.20.1' '6.20.2' '6.20.3' '6.20.4' '6.20.5' '6.20.6' '6.20.7' '6.21.1' '6.21.2' '6.21.3' '6.21.4' '6.21.5' '6.21.6' '6.21.7' '6.21.8' '6.22.1' '6.22.2' '6.22.3' '6.22.4' '6.22.5' '6.22.6' '6.22.7' '6.22.8' '6.22.9' '6.22.10' '6.22.11' '6.22.12' '6.22.13' '6.22.14' '6.22.15' '6.22.16' '6.22.17' '6.22.18' '6.22.19' '6.22.20' '6.22.21' '6.22.22' '6.22.23' '6.22.24' '6.22.25' '6.22.26' '6.22.27' '6.22.28' '6.22.29' '6.22.30' '6.22.31' '6.22.32' '6.22.33' '6.22.34' '6.23.1' '6.23.2' '6.23.3' '6.23.4' '6.23.5' '6.23.6' '6.23.7' '7.1.1' '7.1.2' '7.1.3' '7.1.4' '7.1.5' '7.1.6' '7.3.1' '7.3.2' '7.3.3' '7.3.4' '7.3.5' '7.3.6' '7.5.1' '7.7.1' '7.7.2' '7.7.3' '7.7.4' '7.7.5' '7.7.6' '7.7.7' '7.7.8' '7.7.9' '7.7.10' '7.7.11' '7.7.12' '7.7.13' '7.9.1' '7.9.2' '7.9.3' '7.9.4' '7.9.5' '7.9.6' '7.9.7' '7.9.8' '7.9.9' '7.9.10' '7.9.11' '7.9.12' '7.9.13' '7.13.1' '7.13.2' '9.1.1' '9.1.2' '9.1.3' '9.1.4' '9.1.5' '9.1.6' '9.2.1' '9.2.2' '9.2.3' '9.2.4' '9.2.5' '9.2.6' '9.3.1' '9.3.2' '9.3.3' '9.3.4' '9.3.5' '9.3.6' '9.3.7' '9.3.8' '9.3.9' '9.4.1' '9.4.2' '9.4.3' '9.4.4' '9.4.5' '9.4.6' '9.4.7' '9.4.8' '9.4.9' '9.5.1' '9.5.2' '9.5.3' '9.5.4' '9.5.5' '9.5.6' '9.6.1' '9.6.2' '9.6.3' '9.6.4' '9.6.5' '9.6.6' '9.7.1' '9.7.2' '9.7.3' '9.7.4' '9.7.5' '9.7.6' '9.8.1' '9.8.2' '9.8.3' '9.8.4' '9.8.5' '9.8.6' '10.1.1' '12.1.1' '12.1.2' '12.1.3' '12.1.4' '12.1.5' '12.1.6' '12.1.7' '12.1.8' '12.1.9' '12.1.10' '12.1.11' '12.1.12' '12.1.13' '12.1.14' '12.1.15' '12.1.16' '12.1.17' '12.1.18' '12.2.1' '12.2.2' '12.2.3' '12.2.4' '12.2.5' '12.2.6' '12.2.7' '12.2.8' '12.2.9' '12.2.10' '12.2.11' '12.2.12' '12.2.13' '12.2.14' '12.2.15' '12.2.16' '12.2.17' '12.2.18' '12.3.1' '12.3.2' '12.3.3' '12.3.4' '12.3.5' '12.3.6' '12.3.7' '12.3.8' '12.3.9' '12.3.10' '12.3.11' '12.3.12' '12.3.13' '12.3.14' '12.3.15' '12.3.16' '12.3.17' '12.3.18' '12.4.1' '12.4.2' '12.4.3' '12.4.4' '12.4.5' '12.4.6' '12.4.7' '12.4.8' '12.4.9' '12.4.10' '12.4.11' '12.4.12' '12.4.13' '12.4.14' '12.4.15' '12.4.16' '12.4.17' '12.4.18' '12.5.1' '12.5.2' '12.5.3' '12.5.4' '12.5.5' '12.5.6' '12.5.7' '12.5.8' '12.5.9' '12.5.10' '12.5.11' '12.5.12' '12.5.13' '12.5.14' '12.5.15' '12.5.16' '12.5.17' '12.5.18' '13.1.1' '13.1.2' '13.1.3' '13.1.4' '13.1.5' '13.1.6' '13.1.7' '13.1.8' '13.1.9' '13.1.10' '13.1.11' '13.1.12' '13.1.13' '13.1.14' '13.1.15' '13.1.16' '13.1.17' '13.1.18' '13.2.1' '13.2.2' '13.2.3' '13.2.4' '13.2.5' '13.2.6' '13.2.7' '13.2.8' '13.2.9' '13.2.10' '13.2.11' '13.2.12' '13.2.13' '13.2.14' '13.2.15' '13.2.16' '13.2.17' '13.2.18' '13.3.1' '13.3.2' '13.3.3' '13.3.4' '13.3.5' '13.3.6' '13.3.7' '13.3.8' '13.3.9' '13.3.10' '13.3.11' '13.3.12' '13.3.13' '13.3.14' '13.3.15' '13.3.16' '13.3.17' '13.3.18' '13.4.1' '13.4.2' '13.4.3' '13.4.4' '13.4.5' '13.4.6' '13.4.7' '13.4.8' '13.4.9' '13.4.10' '13.4.11' '13.4.12' '13.4.13' '13.4.14' '13.4.15' '13.4.16' '13.4.17' '13.4.18' '13.5.1' '13.5.2' '13.5.3' '13.5.4' '13.5.5' '13.5.6' '13.5.7' '13.5.8' '13.5.9' '13.5.10' '13.5.11' '13.5.12' '13.5.13' '13.5.14' '13.5.15' '13.5.16' '13.5.17' '13.5.18' '13.6.1' '13.6.2' '13.6.3' '13.6.4' '13.6.5' '13.6.6' '13.6.7' '13.6.8' '13.6.9' '13.6.10' '13.6.11' '13.6.12' '13.6.13' '13.6.14' '13.6.15' '13.6.16' '13.6.17' '13.6.18' '13.7.1' '13.7.2' '13.7.3' '13.7.4' '13.7.5' '13.7.6' '13.7.7' '13.7.8' '13.7.9' '13.7.10' '13.7.11' '13.7.12' '13.7.13' '13.7.14' '13.7.15' '13.7.16' '13.7.17' '13.7.18' ; do libwebsockets-test-echo --client localhost --port 9001 -u "/runCase?case=$N&agent=libwebsockets" -v -n 1 & C=99 while [ $C -gt 8 ] ; do C=`ps fax | grep libwebsockets-test-echo | wc -l` if [ $C -gt 8 ] ; then sleep 1s fi done N=$(( $N + 1 )) done echo "waiting for forks to complete..." while [ 1 ] ; do n=`ps fax | grep libwebsocket | grep -v grep | wc -l` echo "$n forks running..." if [ $n -eq 0 ] ; then echo "Completed" exit 0 fi sleep 1s done |
Added undroid/libwebsockets/changelog.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Changelog --------- v2.0.3 ====== NB New api lws_snprintf() -> SONAME bump to 8.1 Fixes ----- 1) Remove duplicate close in one error path 2) Build fix for ecdh and non-openssl 3) Client confirms server cert 4) SNI falls back to match wildcard DNS names (this is later checked against the cert for actual validity at SSL level) 5) Fix one error path on vhost adopt_socket where we are left on timeout list 6) lws_snprintf() - fix critical problem with snprintf not truncating buffer lengths (it truncated the buffer write) as (wrongly) expected v2.0.2 ====== Fixes ----- 1) Fix possible pthread mutex leak 2) Make sure ACCESS_LOG can't touch freed area 3) extra options in lwsws conf for cipher list and ecdh curve 4) extra options in lwsws conf for extra mimetypes 5) fix default rxbuf trimming for output 6) lwsl_timestamp month number was off-by-one 7) fix daemonize.c v2.0.1 ====== Fixes ----- 1) OpenSSL version tests not needed on LibreSSL and BoringSSL 2) Fix IPV6 build breakage 3) Some fixes for WinCE build 4) Additional canned mimetypes for mounts, the full list is .ico image/x-icon .gif image/gif .js text/javascript .png image/png .jpg image/jpeg .gz application/gzip .JPG image/jpeg .html text/html .css text/css .txt text/plain .ttf application/x-font-ttf .woff application/font-woff .xml application/xml 5) Allow per-vhost setting of which protocol should get used when the protocol: header is not sent by the client 6) MINOR: user_space arg was mistakenly NULL on LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER 7) MINOR: treating recv() returning 0 as peer close destroyed throughput on ab tests, reverted 8) MINOR: %3d on URL part was always turned to _... this should only happen in ?na%3dme=x part of the URL 9) MINOR: some malloc escaped check for NULL / OOM 10) MINOR: libuv cleanups and client connections can operate correctly with libuv 11) MINOR: POST used to hang up the connection when the body had all arrived. Change it so you can reply with a 200 directly rather than requiring a redirect 12) MINOR: API docs were a little behind the docs in the code v2.0.0 ====== Summary ------- - There are only api additions, the api is compatible with v1.7.x. But there is necessarily an soname bump to 8. - If you are using lws client, you mainly need to be aware the option LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT is needed at context-creation time if you will use SSL. - If you are using lws for serving, the above is also true but there are many new features to simplify your code (and life). There is a summany online here https://libwebsockets.org/lws-2.0-new-features.html but basically the keywords are vhosts, mounts and plugins. You can now do the web serving part from lws without any user callback code at all. See ./test-server/test-server-v2.0.c for an example, it has no user code for ws either since it uses the protocol plugins... that one C file is all that is needed to do the whole test server function. You now have the option to use a small generic ws-capable webserver "lwsws" and write your ws part as a plugin. That eliminates even cut-and-pasting the test server code and offers more configurable features like control over http cacheability in JSON. Fixes ----- These are already in 1.7.x series 1) MAJOR (Windows-only) fix assert firing 2) MAJOR http:/1.1 connections handled by lws_return_http_status() did not get sent a content-length resulting in the link hanging until the peer closed it. attack.sh updated to add a test for this. 3) MINOR An error about hdr struct in _lws_ws_related is corrected, it's not known to affect anything until after it was fixed 4) MINOR During the close shutdown wait state introduced at v1.7, if something requests callback on writeable for the socket it will busywait until the socket closes 5) MAJOR Although the test server has done it for a few versions already, it is now required for the user code to explicitly call if (lws_http_transaction_completed(wsi)) return -1; when it finishes replying to a transaction in http. Previously the library did it for you, but that disallowed large, long transfers with multiple trips around the event loop (and cgi...). 6) MAJOR connections on ah waiting list that closed did not get removed from the waiting list... 7) MAJOR since we added the ability to hold an ah across http keepalive transactions where more headers had already arrived, we broke the ability to tell if more headers had arrived. Result was if the browser didn't close the keepalive, we retained ah for the lifetime of the keepalive, using up the pool. 8) MAJOR windows-only-POLLHUP was not coming 9) Client should not send ext hdr if no exts Changes ------- 1) MINOR test-server gained some new switches -C <file> use external SSL cert file -K <file> use external SSL key file -A <file> use external SSL CA cert file -u <uid> set effective uid -g <gid> set effective gid together you can use them like this to have the test-server work with the usual purchased SSL certs from an official CA. --ssl -C your.crt -K your.key -A your.cer -u 99 -g 99 2) MINOR the OpenSSL magic to setup ECDH cipher usage is implemented in the library, and the ciphers restricted to use ECDH only. Using this, the lws test server can score an A at SSLLABS test 3) MINOR STS (SSL always) header is added to the test server if you use --ssl. With that, we score A+ at SSLLABS test 4) MINOR daemonize function (disabled at cmake by default) is updated to work with systemd 5) MINOR example systemd .service file now provided for test server (not installed by default) 6) test server html is updated with tabs and a new live server monitoring feature. Input sanitization added to the js. 7) client connections attempted when no ah is free no longer fail, they are just deferred until an ah becomes available. 8) The test client pays attention to if you give it an http:/ or https:// protocol string to its argument in URL format. If so, it stays in http[s] client mode and doesn't upgrade to ws[s], allowing you to do generic http client operations. Receiving transfer-encoding: chunked is supported. 9) If you enable -DLWS_WITH_HTTP_PROXY=1 at cmake, the test server has a new URI path http://localhost:7681/proxytest If you visit here, a client connection to http://example.com:80 is spawned, and the results piped on to your original connection. 10) Also with LWS_WITH_HTTP_PROXY enabled at cmake, lws wants to link to an additional library, "libhubbub". This allows lws to do html rewriting on the fly, adjusting proxied urls in a lightweight and fast way. 11) There's a new context creation flag LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT, this is included automatically if you give any other SSL-related option flag. If you give no SSL-related option flag, nor this one directly, then even though SSL support may be compiled in, it is never initialized nor used for the whole lifetime of the lws context. Conversely in order to prepare the context to use SSL, even though, eg, you are not listening on SSL but will use SSL client connections later, you must give this flag explicitly to make sure SSL is initialized. User API additions ------------------ 1) MINOR APIBREAK There's a new member in struct lws_context_creation_info, ecdh_curve, which lets you set the name of the ECDH curve OpenSSL should use. By default (if you leave ecdh_curve NULL) it will use "prime256v1" 2) MINOR NEWAPI It was already possible to adopt a foreign socket that had not been read from using lws_adopt_socket() since v1.7. Now you can adopt a partially-used socket if you don't need SSL, by passing it what you read so it can drain that before reading from the socket. LWS_VISIBLE LWS_EXTERN struct lws * lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd, const char *readbuf, size_t len); 3) MINOR NEWAPI CGI type "network io" subprocess execution is now possible from a simple api. LWS_VISIBLE LWS_EXTERN int lws_cgi(struct lws *wsi, char * const *exec_array, int script_uri_path_len, int timeout_secs); LWS_VISIBLE LWS_EXTERN int lws_cgi_kill(struct lws *wsi); To use it, you must first set the cmake option $ cmake .. -DLWS_WITH_CGI=1 See test-server-http.c and test server path http://localhost:7681/cgitest stdin gets http body, you can test it with wget $ echo hello > hello.txt $ wget http://localhost:7681/cgitest --post-file=hello.txt -O- --quiet lwstest script read="hello" The test script returns text/html table showing /proc/meminfo. But the cgi support is complete enough to run cgit cgi. 4) There is a helper api for forming logging timestamps LWS_VISIBLE int lwsl_timestamp(int level, char *p, int len) this generates this kind of timestamp for use as logging preamble lwsts[13116]: [2016/01/25 14:52:52:8386] NOTICE: Initial logging level 7 5) struct lws_client_connect_info has a new member const char *method If it's NULL, then everything happens as before, lws_client_connect_via_info() makes a ws or wss connection to the address given. If you set method to a valid http method like "GET", though, then this method is used and the connection remains in http[s], it's not upgraded to ws[s]. So with this, you can perform http[s] client operations as well as ws[s] ones. There are 4 new related callbacks LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP = 44, LWS_CALLBACK_CLOSED_CLIENT_HTTP = 45, LWS_CALLBACK_RECEIVE_CLIENT_HTTP = 46, LWS_CALLBACK_COMPLETED_CLIENT_HTTP = 47, 6) struct lws_client_connect_info has a new member const char *parent_wsi if non-NULL, the client wsi is set to be a child of parent_wsi. This ensures if parent_wsi closes, then the client child is closed just before. 7) If you're using SSL, there's a new context creation-time option flag LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS. If you give this, non-ssl connections to the server listen port are accepted and receive a 301 redirect to / on the same host and port using https:// 8) User code may set per-connection extension options now, using a new api "lws_set_extension_option()". This should be called from the ESTABLISHED callback like this lws_set_extension_option(wsi, "permessage-deflate", "rx_buf_size", "12"); /* 1 << 12 */ If the extension is not active (missing or not negotiated for the connection, or extensions are disabled on the library) the call is just returns -1. Otherwise the connection's extension has its named option changed. The extension may decide to alter or disallow the change, in the example above permessage-deflate restricts the size of his rx output buffer also considering the protocol's rx_buf_size member. New application lwsws --------------------- A libwebsockets-based general webserver is built by default now, lwsws. It's configured by JSON, by default in /etc/lwsws/conf which contains global lws context settings like this { "global": { "uid": "99", "gid": "99", "interface": "eth0", "count-threads": "1" } } /etc/lwsws/conf.d/* which contains zero or more files describing vhosts, like this { "vhosts": [ { "name": "warmcat.com", "port": "443", "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key", "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt", "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer", "mounts": [ { "/": [ { "home": "file:///var/www/warmcat.com" }, { "default": "index.html" } ] } ] } ] } v1.7.0 ====== Extension Changes ----------------- 1) There is now a "permessage-deflate" / RFC7692 implementation. It's very similar to "deflate-frame" we have offered for a long while; deflate-frame is now provided as an alias of permessage-deflate. The main differences are that the new permessage-deflate implementation: - properly performs streaming respecting input and output buffer limits. The old deflate-frame implementation could only work on complete deflate input and produce complete inflate output for each frame. The new implementation only mallocs buffers at initialization. - goes around the event loop after each input package is processed allowing interleaved output processing. The RX flow control api can be used to force compressed input processing to match the rate of compressed output processing (test--echo shows an example of how to do this). - when being "deflate-frame" for compatibility he uses the same default zlib settings as the old "deflate-frame", but instead of exponentially increasing malloc allocations until the whole output will fit, he observes the default input and output chunking buffer sizes of "permessage-deflate", that's 1024 in and 1024 out at a time. 2) deflate-stream has been disabled for many versions (for over a year) and is now removed. Browsers are now standardizing on "permessage-deflate" / RFC7692 3) struct lws_extension is simplified, and lws extensions now have a public api (their callback) for use in user code to compose extensions and options the user code wants. lws_get_internal_exts() is deprecated but kept around as a NOP. The changes allow one extension implementation to go by different names and allows the user client code to control option offers per-ext. The test client and server are updated to use the new way. If you use the old way it should still work, but extensions will be disabled until you update your code. Extensions are now responsible for allocating and per-instance private struct at instance construction time and freeing it when the instance is destroyed. Not needing to know the size means the extension's struct can be opaque to user code. User api additions ------------------ 1) The info struct gained three new members - max_http_header_data: 0 for default (1024) or set the maximum amount of known http header payload that lws can deal with. Payload in unknown http headers is dropped silently. If for some reason you need to send huge cookies or other HTTP-level headers, you can now increase this at context- creation time. - max_http_header_pool: 0 for default (16) or set the maximum amount of http headers that can be tracked by lws in this context. For the server, if the header pool is completely in use then accepts on the listen socket are disabled until one becomes free. For the client, if you simultaneously have pending connects for more than this number of client connections, additional connects will fail until some of the pending connections timeout or complete. - timeout_secs: 0 for default (currently 20s), or set the library's network activity timeout to the given number of seconds HTTP header processing in lws only exists until just after the first main callback after the HTTP handshake... for ws connections that is ESTABLISHED and for HTTP connections the HTTP callback. So these settings are not related to the maximum number of simultaneous connections, but the number of HTTP handshakes that may be expected or ongoing, or have just completed, at one time. The reason it's useful is it changes the memory allocation for header processing to be one-time at context creation instead of every time there is a new connection, and gives you control over the peak allocation. Setting max_http_header_pool to 1 is fine it will just queue incoming connections before the accept as necessary, you can still have as many simultaneous post-header connections as you like. Since the http header processing is completed and the allocation released after ESTABLISHED or the HTTP callback, even with a pool of 1 many connections can be handled rapidly. 2) There is a new callback that allows the user code to get acccess to the optional close code + aux data that may have been sent by the peer. LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: The peer has sent an unsolicited Close WS packet. @in and @len are the optional close code (first 2 bytes, network order) and the optional additional information which is not defined in the standard, and may be a string or non-human- readble data. If you return 0 lws will echo the close and then close the connection. If you return nonzero lws will just close the connection. As usual not handling it does the right thing, if you're not interested in it just ignore it. The test server has "open and close" testing buttons at the bottom, if you open and close that connection, on close it will send a close code 3000 decimal and the string "Bye!" as the aux data. The test server dumb-increment callback handles this callback reason and prints lwsts[15714]: LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: len 6 lwsts[15714]: 0: 0x0B lwsts[15714]: 1: 0xB8 lwsts[15714]: 2: 0x42 lwsts[15714]: 3: 0x79 lwsts[15714]: 4: 0x65 lwsts[15714]: 5: 0x21 3) There is a new API to allow the user code to control the content of the close frame sent when about to return nonzero from the user callback to indicate the connection should close. /** * lws_close_reason - Set reason and aux data to send with Close packet * If you are going to return nonzero from the callback * requesting the connection to close, you can optionally * call this to set the reason the peer will be told if * possible. * * @wsi: The websocket connection to set the close reason on * @status: A valid close status from websocket standard * @buf: NULL or buffer containing up to 124 bytes of auxiliary data * @len: Length of data in @buf to send */ LWS_VISIBLE LWS_EXTERN void lws_close_reason(struct lws *wsi, enum lws_close_status status, unsigned char *buf, size_t len); An extra button is added to the "open and close" test server page that requests that the test server close the connection from his end. The test server code will do so by lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY, (unsigned char *)"seeya", 5); return -1; The browser shows the close code and reason he received websocket connection CLOSED, code: 1001, reason: seeya 4) There's a new context creation time option flag LWS_SERVER_OPTION_VALIDATE_UTF8 if you set it in info->options, then TEXT and CLOSE frames will get checked to confirm that they contain valid UTF-8. If they don't, the connection will get closed by lws. 5) ECDH Certs are now supported. Enable the CMake option cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 **and** the info->options flag LWS_SERVER_OPTION_SSL_ECDH to build in support and select it at runtime. 6) There's a new api lws_parse_uri() that simplifies chopping up https://xxx:yyy/zzz uris into parts nicely. The test client now uses this to allow proper uris as well as the old address style. 7) SMP support is integrated into LWS without any internal threading. It's very simple to use, libwebsockets-test-server-pthread shows how to do it, use -j <n> argument there to control the number of service threads up to 32. Two new members are added to the info struct unsigned int count_threads; unsigned int fd_limit_per_thread; leave them at the default 0 to get the normal singlethreaded service loop. Set count_threads to n to tell lws you will have n simultaneous service threads operating on the context. There is still a single listen socket on one port, no matter how many service threads. When a connection is made, it is accepted by the service thread with the least connections active to perform load balancing. The user code is responsible for spawning n threads running the service loop associated to a specific tsi (Thread Service Index, 0 .. n - 1). See the libwebsockets-test-server-pthread for how to do. If you leave fd_limit_per_thread at 0, then the process limit of fds is shared between the service threads; if you process was allowed 1024 fds overall then each thread is limited to 1024 / n. You can set fd_limit_per_thread to a nonzero number to control this manually, eg the overall supported fd limit is less than the process allowance. You can control the context basic data allocation for multithreading from Cmake using -DLWS_MAX_SMP=, if not given it's set to 32. The serv_buf allocation for the threads (currently 4096) is made at runtime only for active threads. Because lws will limit the requested number of actual threads supported according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to discover how many threads were actually allowed when the context was created. It's required to implement locking in the user code in the same way that libwebsockets-test-server-pthread does it, for the FD locking callbacks. If LWS_MAX_SMP=1, then there is no code related to pthreads compiled in the library. If more than 1, a small amount of pthread mutex code is built into the library. 8) New API LWS_VISIBLE struct lws * lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd) allows foreign sockets accepted by non-lws code to be adopted by lws as if they had just been accepted by lws' own listen socket. 9) X-Real-IP: header has been added as WSI_TOKEN_HTTP_X_REAL_IP 10) Libuv support is added, there are new related user apis typedef void (lws_uv_signal_cb_t)(uv_loop_t *l, uv_signal_t *w, int revents); LWS_VISIBLE LWS_EXTERN int lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint, lws_uv_signal_cb_t *cb); LWS_VISIBLE LWS_EXTERN int lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi); LWS_VISIBLE void lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents); and CMAKE option LWS_WITH_LIBUV User api changes ---------------- 1) LWS_SEND_BUFFER_POST_PADDING is now 0 and deprecated. You can remove it; if you still use it, obviously it does nothing. Old binary code with nonzero LWS_SEND_BUFFER_POST_PADDING is perfectly compatible, the old code just allocated a buffer bigger than the library is going to use. The example apps no longer use LWS_SEND_BUFFER_POST_PADDING. The only path who made use of it was sending with LWS_WRITE_CLOSE ---> 2) Because of lws_close_reason() formalizing handling close frames, LWS_WRITE_CLOSE is removed from libwebsockets.h. It was only of use to send close frames...close frame content should be managed using lws_close_reason() now. 3) We check for invalid CLOSE codes and complain about protocol violation in our close code. But it changes little since we were in the middle of closing anyway. 4) zero-length RX frames and zero length TX frames are now allowed. 5) Pings and close used to be limited to 124 bytes, the correct limit is 125 so that is now also allowed. 6) LWS_PRE is provided as a synonym for LWS_SEND_BUFFER_PRE_PADDING, either is valid to use now. 7) There's generic support for RFC7462 style extension options built into the library now. As a consequence, a field "options" is added to lws_extension. It can be NULL if there are no options on the extension. Extension internal info is part of the public abi because extensions may be implemented outside the library. 8) WSI_TOKEN_PROXY enum was accidentally defined to collide with another token of value 73. That's now corrected and WSI_TOKEN_PROXY moved to his own place at 77. 9) With the addition of libuv support, libev is not the only event loop library in town and his api names must be elaborated with _ev_ Callback typedef: lws_signal_cb ---> lws_ev_signal_cb_t lws_sigint_cfg --> lws_ev_sigint_cfg lws_initloop --> lws_ev_initloop lws_sigint_cb --> lws_ev_sigint_cb 10) Libev support is made compatible with multithreaded service, lws_ev_initloop (was lws_initloop) gets an extra argument for the thread service index (use 0 if you will just have 1 service thread). LWS_VISIBLE LWS_EXTERN int lws_ev_initloop(struct lws_context *context, ev_loop_t *loop, int tsi); v1.6.0-chrome48-firefox42 ======================= Major API improvements ---------------------- v1.6.0 has many cleanups and improvements in the API. Although at first it looks pretty drastic, user code will only need four actions to update it. - Do the three search/replaces in your user code, /libwebsocket_/lws_/, /libwebsockets_/lws_/, and /struct\ libwebsocket/struct\ lws/ - Remove the context parameter from your user callbacks - Remove context as the first parameter from the "Eleven APIS" listed in the User Api Changes section - Add lws_get_context(wsi) as the first parameter on the "Three APIS" listed in the User Api Changes section, and anywhere else you still need context That's it... generally only a handful of the 14 affected APIs are actually in use in your user code and you can find them quickest by compiling and visiting the errors each in turn. And the end results are much cleaner, more predictable and maintainable. User api additions ------------------ 1) lws now exposes his internal platform file abstraction in a way that can be both used by user code to make it platform-agnostic, and be overridden or subclassed by user code. This allows things like handling the URI "directory space" as a virtual filesystem that may or may not be backed by a regular filesystem. One example use is serving files from inside large compressed archive storage without having to unpack anything except the file being requested. The test server shows how to use it, basically the platform-specific part of lws prepares a file operations structure that lives in the lws context. Helpers are provided to also leverage these platform-independent file handling apis static inline lws_filefd_type lws_plat_file_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) static inline int lws_plat_file_close(struct lws *wsi, lws_filefd_type fd) static inline unsigned long lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset) static inline int lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) static inline int lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) The user code can also override or subclass the file operations, to either wrap or replace them. An example is shown in test server. A wsi can be associated with the file activity, allowing per-connection authentication and state to be used when interpreting the file request. 2) A new API void * lws_wsi_user(struct lws *wsi) lets you get the pointer to the user data associated with the wsi, just from the wsi. 3) URI argument handling. Libwebsockets parses and protects URI arguments like test.html?arg1=1&arg2=2, it decodes %xx uriencoding format and reduces path attacks like ../.../../etc/passwd so they cannot go behind the web server's /. There is a list of confirmed attacks we're proof against in ./test-server/attack.sh. There is a new API lws_hdr_copy_fragment that should be used now to access the URI arguments (it returns the fragments length) while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_URI_ARGS, n) > 0) { lwsl_info("URI Arg %d: %s\n", ++n, buf); } For the example above, calling with n=0 will return "arg1=1" and n=1 "arg2=2". All legal uriencodings will have been reduced in those strings. lws_hdr_copy_fragment() returns the length of the x=y fragment, so it's also possible to deal with arguments containing %00. If you don't care about that, the returned string has '\0' appended to simplify processing. User api changes ---------------- 1) Three APIS - lws_callback_on_writable_all_protocol(const struct lws_protocols *protocol) - lws_callback_all_protocol(const struct lws_protocols *protocol) - lws_rx_flow_allow_all_protocol(lws_rx_flow_allow_all_protocol) Now take an additional pointer to the lws_context in their first argument. The reason for this change is struct lws_protocols has been changed to remove members that lws used for private storage: so the protocols struct in now truly const and may be reused serially or simultaneously by different contexts. 2) Eleven APIs LWS_VISIBLE LWS_EXTERN int lws_add_http_header_by_name(struct lws_context *context, struct lws *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int lws_finalize_http_header(struct lws_context *context, struct lws *wsi, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int lws_add_http_header_by_token(struct lws_context *context, struct lws *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int lws_add_http_header_content_length(struct lws_context *context, struct lws *wsi, unsigned long content_length, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int lws_add_http_header_status(struct lws_context *context, struct lws *wsi, unsigned int code, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int lws_serve_http_file(struct lws_context *context, struct lws *wsi, const char *file, const char *content_type, const char *other_headers, int other_headers_len); LWS_VISIBLE LWS_EXTERN int lws_serve_http_file_fragment(struct lws_context *context, struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_return_http_status(struct lws_context *context, struct lws *wsi, unsigned int code, const char *html_body); LWS_VISIBLE LWS_EXTERN int lws_callback_on_writable(const struct lws_context *context, struct lws *wsi); LWS_VISIBLE LWS_EXTERN void lws_get_peer_addresses(struct lws_context *context, struct lws *wsi, lws_sockfd_type fd, char *name, int name_len, char *rip, int rip_len); LWS_VISIBLE LWS_EXTERN int lws_read(struct lws_context *context, struct lws *wsi, unsigned char *buf, size_t len); no longer require their initial struct lws_context * parameter. 3) Several older apis start with libwebsocket_ or libwebsockets_ while newer ones all begin lws_. These apis have been changed to all begin with lws_. To convert, search-replace - libwebsockets_/lws_ - libwebsocket_/lws_ - struct\ libwebsocket/struct\ lws 4) context parameter removed from user callback. Since almost all apis no longer need the context as a parameter, it's no longer provided at the user callback directly. However if you need it, for ALL callbacks wsi is valid and has a valid context pointer you can recover using lws_get_context(wsi). v1.5-chrome47-firefox41 ======================= User api changes ---------------- LWS_CALLBACK_CLIENT_CONNECTION_ERROR may provide an error string if in is non-NULL. If so, the string has length len. LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED is available to relax the requirement for peer certs if you are using the option to require client certs. LWS_WITHOUT_BUILTIN_SHA1 cmake option forces lws to use SHA1() defined externally, eg, byOpenSSL, and disables build of libwebsockets_SHA1() v1.4-chrome43-firefox36 ======================= User api additions ------------------ There's a new member in the info struct used to control context creation, ssl_private_key_password, which allows passing into lws the passphrase on an SSL cetificate There's a new member in struct protocols, id, which is ignored by lws but can be used by the user code to mark the selected protocol by user-defined version or capabliity flag information, for the case multiple versions of a protocol are supported. int lws_is_ssl(wsi) added to allow user code to know if the connection was made over ssl or not. If LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT is used, both ssl and non-ssl connections are possible and may need to be treated differently in the user code. int lws_partial_buffered(wsi) added... should be checked after any libwebsocket_write that will be followed by another libwebsocket_write inside the same writeable callback. If set, you can't do any more writes until the writeable callback is called again. If you only do one write per writeable callback, you can ignore this. HTTP2-related: HTTP2 changes how headers are handled, lws now has new version- agnositic header creation APIs. These do the right thing depending on each connection's HTTP version without the user code having to know or care, except to make sure to use the new APIs for headers (test-server is updated to use them already, so look there for examples) The APIs "render" the headers into a user-provided buffer and bump *p as it is used. If *p reaches end, then the APIs return nonzero for error. LWS_VISIBLE LWS_EXTERN int lws_add_http_header_status(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned int code, unsigned char **p, unsigned char *end); Start a response header reporting status like 200, 500, etc LWS_VISIBLE LWS_EXTERN int lws_add_http_header_by_name(struct libwebsocket_context *context, struct libwebsocket *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end); Add a header like name: value in HTTP1.x LWS_VISIBLE LWS_EXTERN int lws_finalize_http_header(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char **p, unsigned char *end); Finish off the headers, like add the extra \r\n in HTTP1.x LWS_VISIBLE LWS_EXTERN int lws_add_http_header_by_token(struct libwebsocket_context *context, struct libwebsocket *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end); Add a header by using a lws token as the name part. In HTTP2, this can be compressed to one or two bytes. User api removal ---------------- protocols struct member no_buffer_all_partial_tx is removed. Under some conditions like rewriting extension such as compression in use, the built-in partial send buffering is the only way to deal with the problem, so turning it off is deprecated. User api changes ---------------- HTTP2-related: API libwebsockets_serve_http_file() takes an extra parameter at the end now int other_headers_len) If you are providing other headers, they must be generated using the new HTTP-version-agnostic APIs, and you must provide the length of them using this additional parameter. struct lws_context_creation_info now has an additional member SSL_CTX *provided_client_ssl_ctx you may set to an externally-initialized SSL_CTX managed outside lws. Defaulting to zero keeps the existing behaviour of lws managing the context, if you memset the struct to 0 or have as a filescope initialized struct in bss, no need to change anything. v1.3-chrome37-firefox30 ======================= .gitignore | 1 - CMakeLists.txt | 447 +++-- README.build | 35 +- README.coding | 14 + changelog | 66 + cmake/LibwebsocketsConfig.cmake.in | 17 + cmake/LibwebsocketsConfigVersion.cmake.in | 11 + config.h.cmake | 18 + cross-ming.cmake | 31 + cross-openwrt-makefile | 91 + lib/client-handshake.c | 205 ++- lib/client-parser.c | 58 +- lib/client.c | 158 +- lib/context.c | 341 ++++ lib/extension-deflate-frame.c | 2 +- lib/extension.c | 178 ++ lib/handshake.c | 287 +--- lib/lextable.h | 338 ++++ lib/libev.c | 175 ++ lib/libwebsockets.c | 2089 +++-------------------- lib/libwebsockets.h | 253 ++- lib/lws-plat-unix.c | 404 +++++ lib/lws-plat-win.c | 358 ++++ lib/minilex.c | 530 +++--- lib/output.c | 445 ++--- lib/parsers.c | 682 ++++---- lib/pollfd.c | 239 +++ lib/private-libwebsockets.h | 501 +++++- lib/server-handshake.c | 274 +-- lib/server.c | 858 ++++++++-- lib/service.c | 517 ++++++ lib/sha-1.c | 38 +- lib/ssl-http2.c | 78 + lib/ssl.c | 571 +++++++ test-server/attack.sh | 101 +- test-server/test-client.c | 9 +- test-server/test-echo.c | 17 +- test-server/test-fraggle.c | 7 - test-server/test-ping.c | 12 +- test-server/test-server.c | 330 ++-- test-server/test.html | 4 +- win32port/client/client.vcxproj | 259 --- win32port/client/client.vcxproj.filters | 39 - .../libwebsocketswin32.vcxproj.filters | 93 - win32port/server/server.vcxproj | 276 --- win32port/server/server.vcxproj.filters | 51 - win32port/win32helpers/gettimeofday.h | 59 +- win32port/win32helpers/netdb.h | 1 - win32port/win32helpers/strings.h | 0 win32port/win32helpers/sys/time.h | 1 - win32port/win32helpers/unistd.h | 0 win32port/win32helpers/websock-w32.c | 104 -- win32port/win32helpers/websock-w32.h | 62 - win32port/win32port.sln | 100 -- win32port/zlib/gzio.c | 3 +- 55 files changed, 6779 insertions(+), 5059 deletions(-) User api additions ------------------ POST method is supported The protocol 0 / HTTP callback can now get two new kinds of callback, LWS_CALLBACK_HTTP_BODY (in and len are a chunk of the body of the HTTP request) and LWS_CALLBACK_HTTP_BODY_COMPLETION (the expected amount of body has arrived and been passed to the user code already). These callbacks are used with the post method (see the test server for details). The period between the HTTP header completion and the completion of the body processing is protected by a 5s timeout. The chunks are stored in a malloc'd buffer of size protocols[0].rx_buffer_size. New server option you can enable from user code LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT allows non-SSL connections to also be accepted on an SSL listening port. It's disabled unless you enable it explicitly. Two new callbacks are added in protocols[0] that are optional for allowing limited thread access to libwebsockets, LWS_CALLBACK_LOCK_POLL and LWS_CALLBACK_UNLOCK_POLL. If you use them, they protect internal and external poll list changes, but if you want to use external thread access to libwebsocket_callback_on_writable() you have to implement your locking here even if you don't use external poll support. If you will use another thread for this, take a lot of care about managing your list of live wsi by doing it from ESTABLISHED and CLOSED callbacks (with your own locking). If you configure cmake with -DLWS_WITH_LIBEV=1 then the code allowing the libev eventloop instead of the default poll() one will also be compiled in. But to use it, you must also set the LWS_SERVER_OPTION_LIBEV flag on the context creation info struct options member. IPV6 is supported and enabled by default except for Windows, you can disable the support at build-time by giving -DLWS_IPV6=, and disable use of it even if compiled in by making sure the flag LWS_SERVER_OPTION_DISABLE_IPV6 is set on the context creation info struct options member. You can give LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS option flag to guarantee the OS CAs will not be used, even if that support was selected at build-time. Optional "token limits" may be enforced by setting the member "token_limits" in struct lws_context_creation_info to point to a struct lws_token_limits. NULL means no token limits used for compatibility. User api changes ---------------- Extra optional argument to libwebsockets_serve_http_file() allows injecion of HTTP headers into the canned response. Eg, cookies may be added like that without getting involved in having to send the header by hand. A new info member http_proxy_address may be used at context creation time to set the http proxy. If non-NULL, it overrides http_proxy environment var. Cmake supports LWS_SSL_CLIENT_USE_OS_CA_CERTS defaulting to on, which gets the client to use the OS CA Roots. If you're worried somebody with the ability to forge for force creation of a client cert from the root CA in your OS, you should disable this since your selfsigned $0 cert is a lot safer then... v1.23-chrome32-firefox24 ======================== Android.mk | 29 + CMakeLists.txt | 573 ++++++++---- COPYING | 503 ----------- INSTALL | 365 -------- Makefile.am | 13 - README.build | 371 ++------ README.coding | 63 ++ autogen.sh | 1578 --------------------------------- changelog | 69 ++ cmake/FindGit.cmake | 163 ++++ cmake/FindOpenSSLbins.cmake | 15 +- cmake/UseRPMTools.cmake | 176 ++++ config.h.cmake | 25 +- configure.ac | 226 ----- cross-arm-linux-gnueabihf.cmake | 28 + lib/Makefile.am | 89 -- lib/base64-decode.c | 98 +- lib/client-handshake.c | 123 ++- lib/client-parser.c | 19 +- lib/client.c | 145 ++- lib/daemonize.c | 4 +- lib/extension.c | 2 +- lib/getifaddrs.h | 4 +- lib/handshake.c | 76 +- lib/libwebsockets.c | 491 ++++++---- lib/libwebsockets.h | 164 ++-- lib/output.c | 214 ++++- lib/parsers.c | 102 +-- lib/private-libwebsockets.h | 66 +- lib/server-handshake.c | 5 +- lib/server.c | 29 +- lib/sha-1.c | 2 +- libwebsockets-api-doc.html | 249 +++--- libwebsockets.pc.in | 11 - libwebsockets.spec | 14 +- m4/ignore-me | 2 - scripts/FindLibWebSockets.cmake | 33 + scripts/kernel-doc | 1 + test-server/Makefile.am | 131 --- test-server/leaf.jpg | Bin 0 -> 2477518 bytes test-server/test-client.c | 78 +- test-server/test-echo.c | 33 +- test-server/test-fraggle.c | 26 +- test-server/test-ping.c | 15 +- test-server/test-server.c | 197 +++- test-server/test.html | 5 +- win32port/win32helpers/gettimeofday.c | 74 +- win32port/win32helpers/websock-w32.h | 6 +- 48 files changed, 2493 insertions(+), 4212 deletions(-) User api additions ------------------ - You can now call libwebsocket_callback_on_writable() on http connectons, and get a LWS_CALLBACK_HTTP_WRITEABLE callback, the same way you can regulate writes with a websocket protocol connection. - A new member in the context creation parameter struct "ssl_cipher_list" is added, replacing CIPHERS_LIST_STRING. NULL means use the ssl library default list of ciphers. - Not really an api addition, but libwebsocket_service_fd() will now zero the revents field of the pollfd it was called with if it handled the descriptor. So you can tell if it is a non-lws fd by checking revents after the service call... if it's still nonzero, the descriptor belongs to you and you need to take care of it. - libwebsocket_rx_flow_allow_all_protocol(protocol) will unthrottle all connections with the established protocol. It's designed to be called from user server code when it sees it can accept more input and may have throttled connections using the server rx flow apis while it was unable to accept any other input The user server code then does not have to try to track while connections it choked, this will free up all of them in one call. - there's a new, optional callback LWS_CALLBACK_CLOSED_HTTP which gets called when an HTTP protocol socket closes - for LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION callback, the user_space alloc has already been done before the callback happens. That means we can use the user parameter to the callback to contain the user pointer, and move the protocol name to the "in" parameter. The docs for this callback are also updated to reflect how to check headers in there. - libwebsocket_client_connect() is now properly nonblocking and async. See README.coding and test-client.c for information on the callbacks you can rely on controlling the async connection period with. - if your OS does not support the http_proxy environment variable convention (eg, reportedly OSX), you can use a new api libwebsocket_set_proxy() to set the proxy details in between context creation and the connection action. For OSes that support http_proxy, that's used automatically. User api changes ---------------- - the external poll callbacks now get the socket descriptor coming from the "in" parameter. The user parameter provides the user_space for the wsi as it normally does on the other callbacks. LWS_CALLBACK_FILTER_NETWORK_CONNECTION also has the socket descriptor delivered by @in now instead of @user. - libwebsocket_write() now returns -1 for error, or the amount of data actually accepted for send. Under load, the OS may signal it is ready to send new data on the socket, but have only a restricted amount of memory to buffer the packet compared to usual. User api removal ---------------- - libwebsocket_ensure_user_space() is removed from the public api, if you were using it to get user_space, you need to adapt your code to only use user_space inside the user callback. - CIPHERS_LIST_STRING is removed - autotools build has been removed. See README.build for info on how to use CMake for your platform v1.21-chrome26-firefox18 ======================== - Fixes buffer overflow bug in max frame size handling if you used the default protocol buffer size. If you declared rx_buffer_size in your protocol, which is recommended anyway, your code was unaffected. v1.2-chrome26-firefox18 ======================= Diffstat -------- .gitignore | 16 +++ CMakeLists.txt | 544 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 526 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 1 + README | 20 +++ README.build | 258 ++++++++++++++++++++++++++++++++----- README.coding | 52 ++++++++ changelog | 136 ++++++++++++++++++++ cmake/FindOpenSSLbins.cmake | 33 +++++ config.h.cmake | 173 +++++++++++++++++++++++++ configure.ac | 22 +++- lib/Makefile.am | 20 ++- lib/base64-decode.c | 2 +- lib/client-handshake.c | 190 +++++++++++----------------- lib/client-parser.c | 88 +++++++------ lib/client.c | 384 ++++++++++++++++++++++++++++++------------------------- lib/daemonize.c | 32 +++-- lib/extension-deflate-frame.c | 58 +++++---- lib/extension-deflate-stream.c | 19 ++- lib/extension-deflate-stream.h | 4 +- lib/extension.c | 11 +- lib/getifaddrs.c | 315 +++++++++++++++++++++++----------------------- lib/getifaddrs.h | 30 ++--- lib/handshake.c | 124 +++++++++++------- lib/libwebsockets.c | 736 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------- lib/libwebsockets.h | 237 ++++++++++++++++++++++------------ lib/output.c | 192 +++++++++++----------------- lib/parsers.c | 966 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------- lib/private-libwebsockets.h | 225 +++++++++++++++++++++------------ lib/server-handshake.c | 82 ++++++------ lib/server.c | 96 +++++++------- libwebsockets-api-doc.html | 189 ++++++++++++++++++---------- libwebsockets.spec | 17 +-- test-server/attack.sh | 148 ++++++++++++++++++++++ test-server/test-client.c | 125 +++++++++--------- test-server/test-echo.c | 31 +++-- test-server/test-fraggle.c | 32 ++--- test-server/test-ping.c | 52 ++++---- test-server/test-server.c | 129 ++++++++++++------- win32port/libwebsocketswin32/libwebsocketswin32.vcxproj | 279 ---------------------------------------- win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters | 23 +++- 41 files changed, 4398 insertions(+), 2219 deletions(-) User api additions ------------------ - lws_get_library_version() returns a const char * with a string like "1.1 9e7f737", representing the library version from configure.ac and the git HEAD hash the library was built from - TCP Keepalive can now optionally be applied to all lws sockets, on Linux also with controllable timeout, number of probes and probe interval. (On BSD type OS, you can only use system default settings for the timing and retries, although enabling it is supported by setting ka_time to nonzero, the exact value has no meaning.) This enables detection of idle connections which are logically okay, but are in fact dead, due to network connectivity issues at the server, client, or any intermediary. By default it's not enabled, but you can enable it by setting a non-zero timeout (in seconds) at the new ka_time member at context creation time. - Two new optional user callbacks added, LWS_CALLBACK_PROTOCOL_DESTROY which is called one-time per protocol as the context is being destroyed, and LWS_CALLBACK_PROTOCOL_INIT which is called when the context is created and the protocols are added, again it's a one-time affair. This lets you manage per-protocol allocations properly including cleaning up after yourself when the server goes down. User api changes ---------------- - libwebsocket_create_context() has changed from taking a ton of parameters to just taking a pointer to a struct containing the parameters. The struct lws_context_creation_info is in libwebsockets.h, the members are in the same order as when they were parameters to the call previously. The test apps are all updated accordingly so you can see example code there. - Header tokens are now deleted after the websocket connection is established. Not just the header data is saved, but the pointer and length array is also removed from (union) scope saving several hundred bytes per connection once it is established - struct libwebsocket_protocols has a new member rx_buffer_size, this controls rx buffer size per connection of that protocol now. Sources for apps built against older versions of the library won't declare this in their protocols, defaulting it to 0. Zero buffer is legal, it causes a default buffer to be allocated (currently 4096) If you want to receive only atomic frames in your user callback, you should set this to greater than your largest frame size. If a frame comes that exceeds that, no error occurs but the callback happens as soon as the buffer limit is reached, and again if it is reached again or the frame completes. You can detect that has happened by seeing there is still frame content pending using libwebsockets_remaining_packet_payload() By correctly setting this, you can save a lot of memory when your protocol has small frames (see the test server and client sources). - LWS_MAX_HEADER_LEN now defaults to 1024 and is the total amount of known header payload lws can cope with, that includes the GET URL, origin etc. Headers not understood by lws are ignored and their payload not included in this. User api removals ----------------- - The configuration-time option MAX_USER_RX_BUFFER has been replaced by a buffer size chosen per-protocol. For compatibility, there's a default of 4096 rx buffer, but user code should set the appropriate size for the protocol frames. - LWS_INITIAL_HDR_ALLOC and LWS_ADDITIONAL_HDR_ALLOC are no longer needed and have been removed. There's a new header management scheme that handles them in a much more compact way. - libwebsockets_hangup_on_client() is removed. If you want to close the connection you must do so from the user callback and by returning -1 from there. - libwebsocket_close_and_free_session() is now private to the library code only and not exposed for user code. If you want to close the connection, you must do so from the user callback by returning -1 from there. New features ------------ - Cmake project file added, aimed initially at Windows support: this replaces the visual studio project files that were in the tree until now. - CyaSSL now supported in place of OpenSSL (--use-cyassl on configure) - PATH_MAX or MAX_PATH no longer needed - cutomizable frame rx buffer size by protocol - optional TCP keepalive so dead peers can be detected, can be enabled at context-creation time - valgrind-clean: no SSL or CyaSSL: completely clean. With OpenSSL, 88 bytes lost at OpenSSL library init and symptomless reports of uninitialized memory usage... seems to be a known and ignored problem at OpenSSL - By default debug is enabled and the library is built for -O0 -g to faclitate that. Use --disable-debug configure option to build instead with -O4 and no -g (debug info), obviously providing best performance and reduced binary size. - 1.0 introduced some code to try to not deflate small frames, however this seems to break when confronted with a mixture of frames above and below the threshold, so it's removed. Veto the compression extension in your user callback if you will typically have very small frames. - There are many memory usage improvements, both a reduction in malloc/ realloc and architectural changes. A websocket connection now consumes only 296 bytes with SSL or 272 bytes without on x86_64, during header processing an additional 1262 bytes is allocated in a single malloc, but is freed when the websocket connection starts. The RX frame buffer defined by the protocol in user code is also allocated per connection, this represents the largest frame you can receive atomically in that protocol. - On ARM9 build, just http+ws server no extensions or ssl, <12Kbytes .text and 112 bytes per connection (+1328 only during header processing) v1.1-chrome26-firefox18 ======================= Diffstat -------- Makefile.am | 4 + README-test-server | 291 --- README.build | 239 ++ README.coding | 138 ++ README.rst | 72 - README.test-apps | 272 +++ configure.ac | 116 +- lib/Makefile.am | 55 +- lib/base64-decode.c | 5 +- lib/client-handshake.c | 121 +- lib/client-parser.c | 394 ++++ lib/client.c | 807 +++++++ lib/daemonize.c | 212 ++ lib/extension-deflate-frame.c | 132 +- lib/extension-deflate-stream.c | 12 +- lib/extension-x-google-mux.c | 1223 ---------- lib/extension-x-google-mux.h | 96 - lib/extension.c | 8 - lib/getifaddrs.c | 271 +++ lib/getifaddrs.h | 76 + lib/handshake.c | 582 +---- lib/libwebsockets.c | 2493 ++++++--------------- lib/libwebsockets.h | 115 +- lib/md5.c | 217 -- lib/minilex.c | 440 ++++ lib/output.c | 628 ++++++ lib/parsers.c | 2016 +++++------------ lib/private-libwebsockets.h | 284 +-- lib/server-handshake.c | 275 +++ lib/server.c | 377 ++++ libwebsockets-api-doc.html | 300 +-- m4/ignore-me | 2 + test-server/Makefile.am | 111 +- test-server/libwebsockets.org-logo.png | Bin 0 -> 7029 bytes test-server/test-client.c | 45 +- test-server/test-echo.c | 330 +++ test-server/test-fraggle.c | 20 +- test-server/test-ping.c | 22 +- test-server/test-server-extpoll.c | 554 ----- test-server/test-server.c | 349 ++- test-server/test.html | 3 +- win32port/zlib/ZLib.vcxproj | 749 ++++--- win32port/zlib/ZLib.vcxproj.filters | 188 +- win32port/zlib/adler32.c | 348 ++- win32port/zlib/compress.c | 160 +- win32port/zlib/crc32.c | 867 ++++---- win32port/zlib/crc32.h | 882 ++++---- win32port/zlib/deflate.c | 3799 +++++++++++++++----------------- win32port/zlib/deflate.h | 688 +++--- win32port/zlib/gzclose.c | 50 +- win32port/zlib/gzguts.h | 325 ++- win32port/zlib/gzlib.c | 1157 +++++----- win32port/zlib/gzread.c | 1242 ++++++----- win32port/zlib/gzwrite.c | 1096 +++++---- win32port/zlib/infback.c | 1272 ++++++----- win32port/zlib/inffast.c | 680 +++--- win32port/zlib/inffast.h | 22 +- win32port/zlib/inffixed.h | 188 +- win32port/zlib/inflate.c | 2976 +++++++++++++------------ win32port/zlib/inflate.h | 244 +- win32port/zlib/inftrees.c | 636 +++--- win32port/zlib/inftrees.h | 124 +- win32port/zlib/trees.c | 2468 +++++++++++---------- win32port/zlib/trees.h | 256 +-- win32port/zlib/uncompr.c | 118 +- win32port/zlib/zconf.h | 934 ++++---- win32port/zlib/zlib.h | 3357 ++++++++++++++-------------- win32port/zlib/zutil.c | 642 +++--- win32port/zlib/zutil.h | 526 ++--- 69 files changed, 19556 insertions(+), 20145 deletions(-) user api changes ---------------- - libwebsockets_serve_http_file() now takes a context as first argument - libwebsockets_get_peer_addresses() now takes a context and wsi as first two arguments user api additions ------------------ - lwsl_...() logging apis, default to stderr but retargetable by user code; may be used also by user code - lws_set_log_level() set which logging apis are able to emit (defaults to notice, warn, err severities), optionally set the emit callback - lwsl_emit_syslog() helper callback emits to syslog - lws_daemonize() helper code that forks the app into a headless daemon properly, maintains a lock file with pid in suitable for sysvinit etc to control lifecycle - LWS_CALLBACK_HTTP_FILE_COMPLETION callback added since http file transfer is now asynchronous (see test server code) - lws_frame_is_binary() from a wsi pointer, let you know if the received data was sent in BINARY mode user api removals ----------------- - libwebsockets_fork_service_loop() - no longer supported (had intractable problems) arrange your code to act from the user callback instead from same process context as the service loop - libwebsockets_broadcast() - use libwebsocket_callback_on_writable[_all_protocol]() instead from same process context as the service loop. See the test apps for examples. - x-google-mux() removed until someone wants it - pre -v13 (ancient) protocol support removed New features ------------ - echo test server and client compatible with echo.websocket.org added - many new configure options (see README.build) to reduce footprint of the library to what you actually need, eg, --without-client and --without-server - http + websocket server can build to as little as 12K .text for ARM - no more MAX_CLIENTS limitation; adapts to support the max number of fds allowed to the process by ulimit, defaults to 1024 on Fedora and Ubuntu. Use ulimit to control this without needing to configure the library. Code here is smaller and faster. - adaptive ratio of listen socket to connection socket service allows good behaviour under Apache ab test load. Tested with thousands of simultaneous connections - reduction in per-connection memory footprint by moving to a union to hold mutually-exclusive state for the connection - robustness: Out of Memory taken care of for all allocation code now - internal getifaddrs option if your toolchain lacks it (some uclibc) - configurable memory limit for deflate operations - improvements in SSL code nonblocking operation, possible hang solved, some SSL operations broken down into pollable states so there is no library blocking, timeout coverage for SSL_connect - extpoll test server merged into single test server source - robustness: library should deal with all recoverable socket conditions - rx flowcontrol for backpressure notification fixed and implmeneted correctly in the test server - optimal lexical parser added for header processing; all headers in a single 276-byte state table - latency tracking api added (configure --with-latency) - Improved in-tree documentation, REAME.build, README.coding, README.test-apps, changelog - Many small fixes v1.0-chrome25-firefox17 (6cd1ea9b005933f) |
Added undroid/libwebsockets/cmake/FindGit.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ################################################################################ # # Program: 3D Slicer # # Copyright (c) Kitware Inc. # # See COPYRIGHT.txt # or http://www.slicer.org/copyright/copyright.txt for details. # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. # and was partially funded by NIH grant 3P41RR013218-12S1 # # AG 2013-02-18: I got it from here # https://github.com/Slicer/Slicer/blob/master/CMake/FindGit.cmake # license is BSD # ################################################################################ # # The module defines the following variables: # GIT_EXECUTABLE - path to git command line client # GIT_FOUND - true if the command line client was found # # If the command line client executable is found the macro # GIT_WC_INFO(<dir> <var-prefix>) # is defined to extract information of a git working copy at # a given location. # # The macro defines the following variables: # <var-prefix>_WC_REVISION_HASH - Current SHA1 hash # <var-prefix>_WC_REVISION - Current SHA1 hash # <var-prefix>_WC_REVISION_NAME - Name associated with <var-prefix>_WC_REVISION_HASH # <var-prefix>_WC_URL - output of command `git config --get remote.origin.url' # <var-prefix>_WC_ROOT - Same value as working copy URL # <var-prefix>_WC_GITSVN - Set to false # # ... and also the following ones if it's a git-svn repository: # <var-prefix>_WC_GITSVN - Set to True if it is a # <var-prefix>_WC_INFO - output of command `git svn info' # <var-prefix>_WC_URL - url of the associated SVN repository # <var-prefix>_WC_ROOT - root url of the associated SVN repository # <var-prefix>_WC_REVISION - current SVN revision number # <var-prefix>_WC_LAST_CHANGED_AUTHOR - author of last commit # <var-prefix>_WC_LAST_CHANGED_DATE - date of last commit # <var-prefix>_WC_LAST_CHANGED_REV - revision of last commit # <var-prefix>_WC_LAST_CHANGED_LOG - last log of base revision # # Example usage: # find_package(Git) # if(GIT_FOUND) # GIT_WC_INFO(${PROJECT_SOURCE_DIR} Project) # message("Current revision is ${Project_WC_REVISION_HASH}") # message("git found: ${GIT_EXECUTABLE}") # endif() # # Look for 'git' or 'eg' (easy git) # set(git_names git eg) # Prefer .cmd variants on Windows unless running in a Makefile # in the MSYS shell. # if(WIN32) if(NOT CMAKE_GENERATOR MATCHES "MSYS") # Note: Due to a bug in 'git.cmd' preventing it from returning the exit code of 'git', # we excluded it from the list of executables to search. # See http://code.google.com/p/msysgit/issues/detail?id=428 # TODO Check if 'git' exists, get the associated version, if the corresponding version # is known to have a working version of 'git.cmd', use it. set(git_names git eg.cmd eg) endif() endif() find_program(GIT_EXECUTABLE ${git_names} PATHS "C:/Program Files/Git/bin" "C:/Program Files (x86)/Git/bin" DOC "git command line client") mark_as_advanced(GIT_EXECUTABLE) if(GIT_EXECUTABLE) macro(GIT_WC_INFO dir prefix) execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=7 HEAD WORKING_DIRECTORY ${dir} ERROR_VARIABLE GIT_error OUTPUT_VARIABLE ${prefix}_WC_REVISION_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) set(${prefix}_WC_REVISION ${${prefix}_WC_REVISION_HASH}) if(NOT ${GIT_error} EQUAL 0) message(SEND_ERROR "Command \"${GIT_EXECUTBALE} rev-parse --verify -q --short=7 HEAD\" in directory ${dir} failed with output:\n${GIT_error}") else(NOT ${GIT_error} EQUAL 0) execute_process(COMMAND ${GIT_EXECUTABLE} name-rev ${${prefix}_WC_REVISION_HASH} WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE ${prefix}_WC_REVISION_NAME OUTPUT_STRIP_TRAILING_WHITESPACE) endif(NOT ${GIT_error} EQUAL 0) execute_process(COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE ${prefix}_WC_URL OUTPUT_STRIP_TRAILING_WHITESPACE) set(${prefix}_WC_GITSVN False) # Check if this git is likely to be a git-svn repository execute_process(COMMAND ${GIT_EXECUTABLE} config --get-regexp "^svn-remote" WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE git_config_output OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT "${git_config_output}" STREQUAL "") # In case git-svn is used, attempt to extract svn info execute_process(COMMAND ${GIT_EXECUTABLE} svn info WORKING_DIRECTORY ${dir} TIMEOUT 3 ERROR_VARIABLE git_svn_info_error OUTPUT_VARIABLE ${prefix}_WC_INFO RESULT_VARIABLE git_svn_info_result OUTPUT_STRIP_TRAILING_WHITESPACE) if(${git_svn_info_result} EQUAL 0) set(${prefix}_WC_GITSVN True) string(REGEX REPLACE "^(.*\n)?URL: ([^\n]+).*" "\\2" ${prefix}_WC_URL "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Revision: ([^\n]+).*" "\\2" ${prefix}_WC_REVISION "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Repository Root: ([^\n]+).*" "\\2" ${prefix}_WC_ROOT "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Last Changed Author: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_AUTHOR "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Last Changed Rev: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_REV "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Last Changed Date: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_DATE "${${prefix}_WC_INFO}") endif(${git_svn_info_result} EQUAL 0) endif(NOT "${git_config_output}" STREQUAL "") # If there is no 'remote.origin', default to "NA" value and print a warning message. if(NOT ${prefix}_WC_URL) message(WARNING "No remote origin set for git repository: ${dir}" ) set( ${prefix}_WC_URL "NA" ) else() set(${prefix}_WC_ROOT ${${prefix}_WC_URL}) endif() endmacro(GIT_WC_INFO) endif(GIT_EXECUTABLE) # Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE) |
Added undroid/libwebsockets/cmake/FindOpenSSLbins.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | if(OPENSSL_FOUND) find_program(OPENSSL_EXECUTABLE openssl openssl.exe bin/openssl.exe HINTS ${_OPENSSL_ROOT_HINTS} PATH /usr/bin/ bin/ DOC "Openssl executable") mark_as_advanced(OPENSSL_EXECUTABLE) # On Windows, we need to copy the OpenSSL dlls # to the output directory. if(WIN32) set(OPENSSL_BIN_FOUND 0) find_file(LIBEAY_BIN NAMES libeay32.dll HINTS ${_OPENSSL_ROOT_HINTS} PATH_SUFFIXES bin) find_file(SSLEAY_BIN NAMES ssleay32.dll HINTS ${_OPENSSL_ROOT_HINTS} PATH_SUFFIXES bin) if(LIBEAY_BIN) if(SSLEAY_BIN) set(OPENSSL_BIN_FOUND 1) endif(SSLEAY_BIN) endif(LIBEAY_BIN) endif(WIN32) endif(OPENSSL_FOUND) |
Added undroid/libwebsockets/cmake/LibwebsocketsConfig.cmake.in.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # - Config file for the Libevent package # It defines the following variables # LIBWEBSOCKETS_INCLUDE_DIRS - include directories for FooBar # LIBWEBSOCKETS_LIBRARIES - libraries to link against # Get the path of the current file. get_filename_component(LWS_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) # Set the include directories. set(LIBWEBSOCKETS_INCLUDE_DIRS "@LWS__INCLUDE_DIRS@") # Include the project Targets file, this contains definitions for IMPORTED targets. include(${LWS_CMAKE_DIR}/LibwebsocketsTargets.cmake) # IMPORTED targets from LibwebsocketsTargets.cmake set(LIBWEBSOCKETS_LIBRARIES websockets websockets_shared) |
Added undroid/libwebsockets/cmake/LibwebsocketsConfigVersion.cmake.in.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | set(PACKAGE_VERSION "@CPACK_PACKAGE_VERSION@") # Check whether the requested PACKAGE_FIND_VERSION is compatible if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT TRUE) endif() endif() |
Added undroid/libwebsockets/cmake/UseRPMTools.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # # - Find tools needed for building RPM Packages # on Linux systems and defines macro that helps to # build source or binary RPM, the MACRO assumes # CMake 2.4.x which includes CPack support. # CPack is used to build tar.gz source tarball # which may be used by a custom user-made spec file. # # - Define RPMTools_ADD_RPM_TARGETS which defines # two (top-level) CUSTOM targets for building # source and binary RPMs # # Those CMake macros are provided by the TSP Developer Team # https://savannah.nongnu.org/projects/tsp # IF (WIN32) MESSAGE(STATUS "RPM tools not available on Win32 systems") ENDIF(WIN32) IF (UNIX) # Look for RPM builder executable FIND_PROGRAM(RPMTools_RPMBUILD_EXECUTABLE NAMES rpmbuild PATHS "/usr/bin;/usr/lib/rpm" PATH_SUFFIXES bin DOC "The RPM builder tool") IF (RPMTools_RPMBUILD_EXECUTABLE) MESSAGE(STATUS "Looking for RPMTools... - found rpmuild is ${RPMTools_RPMBUILD_EXECUTABLE}") SET(RPMTools_RPMBUILD_FOUND "YES") GET_FILENAME_COMPONENT(RPMTools_BINARY_DIRS ${RPMTools_RPMBUILD_EXECUTABLE} PATH) ELSE (RPMTools_RPMBUILD_EXECUTABLE) SET(RPMTools_RPMBUILD_FOUND "NO") MESSAGE(STATUS "Looking for RPMTools... - rpmbuild NOT FOUND") ENDIF (RPMTools_RPMBUILD_EXECUTABLE) # Detect if CPack was included or not IF (NOT DEFINED "CPACK_PACKAGE_NAME") MESSAGE(FATAL_ERROR "CPack was not included, you should include CPack before Using RPMTools") ENDIF (NOT DEFINED "CPACK_PACKAGE_NAME") IF (RPMTools_RPMBUILD_FOUND) SET(RPMTools_FOUND TRUE) # # - first arg (ARGV0) is RPM name # - second arg (ARGV1) is the RPM spec file path [optional] # - third arg (ARGV2) is the RPM ROOT DIRECTORY used to build RPMs [optional] # MACRO(RPMTools_ADD_RPM_TARGETS RPMNAME) # # If no spec file is provided create a minimal one # IF ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${CMAKE_BINARY_DIR}/${RPMNAME}.spec") ELSE ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${ARGV1}") ENDIF("${ARGV1}" STREQUAL "") # Verify whether if RPM_ROOTDIR was provided or not IF("${ARGV2}" STREQUAL "") SET(RPM_ROOTDIR ${CMAKE_BINARY_DIR}/RPM) ELSE ("${ARGV2}" STREQUAL "") SET(RPM_ROOTDIR "${ARGV2}") ENDIF("${ARGV2}" STREQUAL "") MESSAGE(STATUS "RPMTools:: Using RPM_ROOTDIR=${RPM_ROOTDIR}") # Prepare RPM build tree FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/tmp) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/BUILD) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/RPMS) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SOURCES) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SPECS) FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SRPMS) # # We check whether if the provided spec file is # to be configure or not. # IF ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec") SET(SPECFILE_NAME "${RPMNAME}.spec") MESSAGE(STATUS "No Spec file given generate a minimal one --> ${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec") FILE(WRITE ${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec "# -*- rpm-spec -*- Summary: ${RPMNAME} Name: ${RPMNAME} Version: ${CPACK_PACKAGE_VERSION} Release: 1 License: Unknown Group: Unknown Source: ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{CPACK_PACKAGE_VERSION}-1-root BuildRequires: cmake %define prefix /opt/${RPMNAME}-%{version} %define rpmprefix $RPM_BUILD_ROOT%{prefix} %define srcdirname %{name}-%{version} %description ${RPMNAME} : No description for now %prep %setup -q -n %{srcdirname} %build cd .. rm -rf build_tree mkdir build_tree cd build_tree cmake -DCMAKE_INSTALL_PREFIX=%{rpmprefix} ../%{srcdirname} make %install cd ../build_tree make install %clean rm -rf %{srcdirname} rm -rf build_tree %files %defattr(-,root,root,-) %dir %{prefix} %{prefix}/* %changelog * Wed Feb 28 2007 Erk <eric.noulard@gmail.com> Generated by CMake UseRPMTools macros" ) ELSE ("${ARGV1}" STREQUAL "") SET(SPECFILE_PATH "${ARGV1}") GET_FILENAME_COMPONENT(SPECFILE_EXT ${SPECFILE_PATH} EXT) IF ("${SPECFILE_EXT}" STREQUAL ".spec") # This is a 'ready-to-use' spec file which does not need to be CONFIGURED GET_FILENAME_COMPONENT(SPECFILE_NAME ${SPECFILE_PATH} NAME) MESSAGE(STATUS "Simple copy spec file <${SPECFILE_PATH}> --> <${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}>") CONFIGURE_FILE( ${SPECFILE_PATH} ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} COPYONLY) ELSE ("${SPECFILE_EXT}" STREQUAL ".spec") # This is a to-be-configured spec file GET_FILENAME_COMPONENT(SPECFILE_NAME ${SPECFILE_PATH} NAME_WE) SET(SPECFILE_NAME "${SPECFILE_NAME}.spec") MESSAGE(STATUS "Configuring spec file <${SPECFILE_PATH}> --> <${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}>") CONFIGURE_FILE( ${SPECFILE_PATH} ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} @ONLY) ENDIF ("${SPECFILE_EXT}" STREQUAL ".spec") ENDIF("${ARGV1}" STREQUAL "") ADD_CUSTOM_TARGET(${RPMNAME}_srpm COMMAND cpack -G TGZ --config CPackSourceConfig.cmake COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ${RPM_ROOTDIR}/SOURCES COMMAND ${RPMTools_RPMBUILD_EXECUTABLE} -bs --define=\"_topdir ${RPM_ROOTDIR}\" --buildroot=${RPM_ROOTDIR}/tmp ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} ) ADD_CUSTOM_TARGET(${RPMNAME}_rpm COMMAND cpack -G TGZ --config CPackSourceConfig.cmake COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ${RPM_ROOTDIR}/SOURCES COMMAND ${RPMTools_RPMBUILD_EXECUTABLE} -bb --define=\"_topdir ${RPM_ROOTDIR}\" --buildroot=${RPM_ROOTDIR}/tmp ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME} ) ENDMACRO(RPMTools_ADD_RPM_TARGETS) ELSE (RPMTools_RPMBUILD_FOUND) SET(RPMTools FALSE) ENDIF (RPMTools_RPMBUILD_FOUND) ENDIF (UNIX) |
Added undroid/libwebsockets/contrib/abi/README.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ABI Compatility Tracking ======================== This directory contains files that can be used to generate an ABI compatibility timeline for libwebsockets. This gives users an idea of where the library has changed and can be used by the developers to see when incompatible changes have been introduced and either increase the library SO version or fix the changes. The tools used are the abi-\* family available at https://github.com/lvc/ and some example output is here: http://abi-laboratory.pro/tracker/timeline/libuv/ The tools download existing source tarballs and git repository to generate this data, so past versions are compared and in-development code can be compared as well. Although the application is not being included here, FYI the license is dual LGPL2 / GPL2 at your choice. Installation ------------ The author provides an easy way to install the various tools he provides: git clone https://github.com/lvc/installer cd installer make prefix=/usr/local target=abi-tracker It will also list any dependencies that you need to install through normal means. (Although in the case of needing "elfutils-libelf-devel", it may crash during install of vtable-dumper without giving a nice list) Generating the output --------------------- Use the `lws-abi-update.sh` script to download the source files, build them and generate the output html. The output can be deployed to a directory on a web server for example. Modify the commented line in lws-abi-update.sh to do this. As it is configured, lws-abi-update.sh will only download new source - ones that it hasn't built before - so is suitable for use with a cron job. Viewing the output ------------------ The best place to start looking at the data is the `timeline/libwebsockets` directory. If your path is on a web server, navigate there, otherwise you could try: lynx timeline/libwebsockets/ |
Added undroid/libwebsockets/contrib/abi/libwebsockets.json.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | { "Name": "libwebsockets", "SourceUrl": "https://github.com/warmcat/libwebsockets/releases", "Git": "https://github.com/warmcat/libwebsockets", "Versions": [ { "Number": "current", "Installed": "installed/libwebsockets/current", "Source": "src/libwebsockets/current", "Changelog": "On", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.7.4", "Installed": "installed/libwebsockets/1.7.4", "Source": "src/libwebsockets/1.7.4/libwebsockets-1.7.4.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.7.3", "Installed": "installed/libwebsockets/1.7.3", "Source": "src/libwebsockets/1.7.3/libwebsockets-1.7.3.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.7.2", "Installed": "installed/libwebsockets/1.7.2", "Source": "src/libwebsockets/1.7.2/libwebsockets-1.7.2.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.7.1", "Installed": "installed/libwebsockets/1.7.1", "Source": "src/libwebsockets/1.7.1/libwebsockets-1.7.1.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.7.0", "Installed": "installed/libwebsockets/1.7.0", "Source": "src/libwebsockets/1.7.0/libwebsockets-1.7.0.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.6.3", "Installed": "installed/libwebsockets/1.6.3", "Source": "src/libwebsockets/1.6.3/libwebsockets-1.6.3.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.6.2", "Installed": "installed/libwebsockets/1.6.2", "Source": "src/libwebsockets/1.6.2/libwebsockets-1.6.2.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.6.1", "Installed": "installed/libwebsockets/1.6.1", "Source": "src/libwebsockets/1.6.1/libwebsockets-1.6.1.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }, { "Number": "1.5.1", "Installed": "installed/libwebsockets/1.5.1", "Source": "src/libwebsockets/1.5.1/libwebsockets-1.5.1.tar.gz", "Changelog": "Off", "HeadersDiff": "On", "PkgDiff": "Off", "ABIView": "Off", "ABIDiff": "Off" }] } |
Added undroid/libwebsockets/contrib/abi/lws-abi-update.sh.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/bin/sh if [ ! -z "$1" ] ; then OUT=$1 else OUT="/tmp/lws-abi-track-htdocs" fi D=`dirname $0` if [ ! -z "$D" ] ; then D=$D/ fi J=$D"libwebsockets.json" abi-monitor -get -build-new $J abi-tracker -build $J abi-tracker -deploy $OUT $J |
Added undroid/libwebsockets/contrib/android-make-script.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/bash # # Build libwebsockets static library for Android # # requires debian package xutils-dev for makedepend (openssl make depend) # # This is based on http://stackoverflow.com/questions/11929773/compiling-the-latest-openssl-for-android/ # via https://github.com/warmcat/libwebsockets/pull/502 # path to NDK export NDK=/opt/Android/SDK/ndk-bundle set -e # Download packages libz, openssl and libwebsockets [ ! -f zlib-1.2.8.tar.gz ] && { wget http://prdownloads.sourceforge.net/libpng/zlib-1.2.8.tar.gz } [ ! -f openssl-1.0.2g.tar.gz ] && { wget https://openssl.org/source/openssl-1.0.2g.tar.gz } [ ! -f libwebsockets.tar.gz ] && { git clone https://github.com/warmcat/libwebsockets.git tar caf libwebsockets.tar.gz libwebsockets } # Clean then Unzip [ -d zlib-1.2.8 ] && rm -fr zlib-1.2.8 [ -d openssl-1.0.2g ] && rm -fr openssl-1.0.2g [ -d libwebsockets ] && rm -fr libwebsockets [ -d android-toolchain-arm ] && rm -fr android-toolchain-arm tar xf zlib-1.2.8.tar.gz tar xf openssl-1.0.2g.tar.gz tar xf libwebsockets.tar.gz # create a local android toolchain $NDK/build/tools/make-standalone-toolchain.sh \ --platform=android-9 \ --toolchain=arm-linux-androideabi-4.9 \ --install-dir=`pwd`/android-toolchain-arm # setup environment to use the gcc/ld from the android toolchain export TOOLCHAIN_PATH=`pwd`/android-toolchain-arm/bin export TOOL=arm-linux-androideabi export NDK_TOOLCHAIN_BASENAME=${TOOLCHAIN_PATH}/${TOOL} export CC=$NDK_TOOLCHAIN_BASENAME-gcc export CXX=$NDK_TOOLCHAIN_BASENAME-g++ export LINK=${CXX} export LD=$NDK_TOOLCHAIN_BASENAME-ld export AR=$NDK_TOOLCHAIN_BASENAME-ar export RANLIB=$NDK_TOOLCHAIN_BASENAME-ranlib export STRIP=$NDK_TOOLCHAIN_BASENAME-strip # setup buildflags export ARCH_FLAGS="-mthumb" export ARCH_LINK= export CPPFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 " export CXXFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions " export CFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 " export LDFLAGS=" ${ARCH_LINK} " # configure and build zlib [ ! -f ./android-toolchain-arm/lib/libz.a ] && { cd zlib-1.2.8 PATH=$TOOLCHAIN_PATH:$PATH ./configure --static --prefix=$TOOLCHAIN_PATH/.. PATH=$TOOLCHAIN_PATH:$PATH make PATH=$TOOLCHAIN_PATH:$PATH make install cd .. } # configure and build openssl [ ! -f ./android-toolchain-arm/lib/libssl.a ] && { PREFIX=$TOOLCHAIN_PATH/.. cd openssl-1.0.2g ./Configure android --prefix=${PREFIX} no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp PATH=$TOOLCHAIN_PATH:$PATH make depend PATH=$TOOLCHAIN_PATH:$PATH make PATH=$TOOLCHAIN_PATH:$PATH make install_sw cd .. } # configure and build libwebsockets [ ! -f ./android-toolchain-arm/lib/libwebsockets.a ] && { cd libwebsockets [ ! -d build ] && mkdir build cd build PATH=$TOOLCHAIN_PATH:$PATH cmake \ -DCMAKE_C_COMPILER=$CC \ -DCMAKE_AR=$AR \ -DCMAKE_RANLIB=$RANLIB \ -DCMAKE_C_FLAGS="$CFLAGS" \ -DCMAKE_INSTALL_PREFIX=$TOOLCHAIN_PATH/.. \ -DLWS_WITH_SHARED=OFF \ -DLWS_WITH_STATIC=ON \ -DLWS_WITHOUT_DAEMONIZE=ON \ -DLWS_WITHOUT_TESTAPPS=ON \ -DLWS_IPV6=OFF \ -DLWS_USE_BUNDLED_ZLIB=OFF \ -DLWS_WITH_SSL=ON \ -DLWS_WITH_HTTP2=ON \ -DLWS_OPENSSL_LIBRARIES="$TOOLCHAIN_PATH/../lib/libssl.a;$TOOLCHAIN_PATH/../lib/libcrypto.a" \ -DLWS_OPENSSL_INCLUDE_DIRS=$TOOLCHAIN_PATH/../include \ -DCMAKE_BUILD_TYPE=Debug \ .. PATH=$TOOLCHAIN_PATH:$PATH make PATH=$TOOLCHAIN_PATH:$PATH make install cd ../.. } |
Added undroid/libwebsockets/cross-arm-linux-gnueabihf.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # # CMake Toolchain file for crosscompiling on ARM. # # This can be used when running cmake in the following way: # cd build/ # cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake # set(CROSS_PATH /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2013.02-01-20130221_linux) # Target operating system name. set(CMAKE_SYSTEM_NAME Linux) # Name of C compiler. set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-gcc") set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-g++") # Where to look for the target environment. (More paths can be added here) set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") # Adjust the default behavior of the FIND_XXX() commands: # search programs in the host environment only. set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Search headers and libraries in the target environment only. set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
Added undroid/libwebsockets/cross-ming.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # # CMake Toolchain file for crosscompiling on MingW. # # This can be used when running cmake in the following way: # cd build/ # cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-ming.cmake # set(CROSS_PATH /usr/bin) # Target operating system name. set(CMAKE_SYSTEM_NAME Windows) set(BUILD_SHARED_LIBS OFF) # Name of C compiler. set(CMAKE_C_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-gcc") #set(CMAKE_CXX_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-g++") set(CMAKE_RC_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-windres") set(CMAKE_C_FLAGS "-Wno-error") # Where to look for the target environment. (More paths can be added here) set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") # Adjust the default behavior of the FIND_XXX() commands: # search programs in the host environment only. set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Search headers and libraries in the target environment only. set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
Added undroid/libwebsockets/cross-openwrt-makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # # libwebsockets makefile for openwrt # include $(TOPDIR)/rules.mk PKG_NAME:=libwebsockets PKG_VERSION:=2014-03-01 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/warmcat/libwebsockets.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_VERSION:=388dc7d201d8d123841869fb49ec4d94d6dd7f54 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz CMAKE_INSTALL:=1 include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/cmake.mk CMAKE_OPTIONS += -DLWS_OPENSSL_CLIENT_CERTS=/etc/ssl/certs CMAKE_OPTIONS += -DLWS_OPENSSL_SUPPORT=ON CMAKE_OPTIONS += -DLWS_WITH_SSL=ON CMAKE_OPTIONS += -DLWS_WITHOUT_TESTAPPS=$(if $(CONFIG_PACKAGE_libwebsockets-examples),"OFF","ON") # for wolfssl, define these in addition to LWS_OPENSSL_SUPPORT and # edit package/libs/wolfssl/Makefile to include --enable-opensslextra # CMAKE_OPTIONS += -DLWS_USE_WOLFSSL=ON # CMAKE_OPTIONS += -DLWS_WOLFSSL_LIBRARIES=$(STAGING_DIR)/usr/lib/libwolfssl.so # CMAKE_OPTIONS += -DLWS_WOLFSSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include # for cyassl, define these in addition to LWS_OPENSSL_SUPPORT and # edit package/libs/wolfssl/Makefile to include --enable-opensslextra # CMAKE_OPTIONS += -DLWS_USE_CYASSL=ON # CMAKE_OPTIONS += -DLWS_CYASSL_LIBRARIES=$(STAGING_DIR)/usr/lib/libcyassl.so # CMAKE_OPTIONS += -DLWS_CYASSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include # other options worth noting # CMAKE_OPTIONS += -DLWS_WITHOUT_EXTENSIONS=ON # CMAKE_OPTIONS += -DLWS_WITHOUT_DAEMONIZE=ON # CMAKE_OPTIONS += -DLWS_WITHOUT_SERVER=ON # CMAKE_OPTIONS += -DLWS_WITHOUT_DEBUG=ON define Package/libwebsockets/Default SECTION:=libs CATEGORY:=Libraries TITLE:=libwebsockets DEPENDS:=+zlib +libopenssl endef define Package/libwebsockets $(call Package/libwebsockets/Default) TITLE+= (libraries) endef define Package/libwebsockets/description libwebsockets This package contains libwebsocket libraries endef define Package/libwebsockets-examples $(call Package/libwebsockets/Default) DEPENDS:=libwebsockets TITLE+= (examples) endef define Package/libwebsockets-examples/description libwebsockets examples This package contains libwebsockets examples endef define Package/libwebsockets/install $(INSTALL_DIR) $(1)/usr/lib $(CP) $(PKG_INSTALL_DIR)/usr/lib/libwebsockets.so* $(1)/usr/lib/ endef define Package/libwebsockets-examples/install $(INSTALL_DIR) $(1)/usr/bin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-client $(1)/usr/bin/ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-echo $(1)/usr/bin/ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-fraggle $(1)/usr/bin/ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-ping $(1)/usr/bin/ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server $(1)/usr/bin/ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server-extpoll $(1)/usr/bin/ $(INSTALL_DIR) $(1)/usr/share/libwebsockets-test-server $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/favicon.ico $(1)/usr/share/libwebsockets-test-server/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/leaf.jpg $(1)/usr/share/libwebsockets-test-server/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets.org-logo.png $(1)/usr/share/libwebsockets-test-server/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.key.pem $(1)/usr/share/libwebsockets-test-server/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.pem $(1)/usr/share/libwebsockets-test-server/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/test.html $(1)/usr/share/libwebsockets-test-server/ endef $(eval $(call BuildPackage,libwebsockets)) $(eval $(call BuildPackage,libwebsockets-examples)) |
Added undroid/libwebsockets/lib/alloc.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" static void *_realloc(void *ptr, size_t size) { if (size) return realloc(ptr, size); else if (ptr) free(ptr); return NULL; } void *(*_lws_realloc)(void *ptr, size_t size) = _realloc; void *lws_realloc(void *ptr, size_t size) { return _lws_realloc(ptr, size); } void *lws_zalloc(size_t size) { void *ptr = _lws_realloc(NULL, size); if (ptr) memset(ptr, 0, size); return ptr; } void lws_set_allocator(void *(*cb)(void *ptr, size_t size)) { _lws_realloc = cb; } |
Added undroid/libwebsockets/lib/base64-decode.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This code originally came from here * * http://base64.sourceforge.net/b64.c * * with the following license: * * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the * Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall * be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * VERSION HISTORY: * Bob Trower 08/04/01 -- Create Version 0.00.00B * * I cleaned it up quite a bit to match the (linux kernel) style of the rest * of libwebsockets; this version is under LGPL2.1 + SLE like the rest of lws * since he explicitly allows sublicensing, but I give the URL above so you can * get the original with Bob's super-liberal terms directly if you prefer. */ #include <stdio.h> #include <string.h> #include "private-libwebsockets.h" static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789+/"; static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW" "$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; LWS_VISIBLE int lws_b64_encode_string(const char *in, int in_len, char *out, int out_size) { unsigned char triple[3]; int i; int len; int line = 0; int done = 0; while (in_len) { len = 0; for (i = 0; i < 3; i++) { if (in_len) { triple[i] = *in++; len++; in_len--; } else triple[i] = 0; } if (done + 4 >= out_size) return -1; *out++ = encode[triple[0] >> 2]; *out++ = encode[((triple[0] & 0x03) << 4) | ((triple[1] & 0xf0) >> 4)]; *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) | ((triple[2] & 0xc0) >> 6)] : '='); *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '='); done += 4; line += 4; } if (done + 1 >= out_size) return -1; *out++ = '\0'; return done; } /* * returns length of decoded string in out, or -1 if out was too small * according to out_size */ LWS_VISIBLE int lws_b64_decode_string(const char *in, char *out, int out_size) { int len; int i, c; int done = 0; unsigned char v; unsigned char quad[4]; while (*in) { len = 0; for (i = 0; i < 4 && *in; i++) { v = 0; c = 0; while (*in && !v) { c = v = *in++; v = (v < 43 || v > 122) ? 0 : decode[v - 43]; if (v) v = (v == '$') ? 0 : v - 61; } if (c) { len++; if (v) quad[i] = v - 1; } else quad[i] = 0; } if (out_size < (done + len - 1)) /* out buffer is too small */ return -1; if (len >= 2) *out++ = quad[0] << 2 | quad[1] >> 4; if (len >= 3) *out++ = quad[1] << 4 | quad[2] >> 2; if (len >= 4) *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; done += len - 1; } if (done + 1 >= out_size) return -1; *out++ = '\0'; return done; } #if 0 int lws_b64_selftest(void) { char buf[64]; unsigned int n; unsigned int test; static const char * const plaintext[] = { "sanity check base 64" }; static const char * const coded[] = { "c2FuaXR5IGNoZWNrIGJhc2UgNjQ=" }; for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) { buf[sizeof(buf) - 1] = '\0'; n = lws_b64_encode_string(plaintext[test], strlen(plaintext[test]), buf, sizeof buf); if (n != strlen(coded[test]) || strcmp(buf, coded[test])) { lwsl_err("Failed lws_b64 encode selftest " "%d result '%s' %d\n", test, buf, n); return -1; } buf[sizeof(buf) - 1] = '\0'; n = lws_b64_decode_string(coded[test], buf, sizeof buf); if (n != strlen(plaintext[test]) || strcmp(buf, plaintext[test])) { lwsl_err("Failed lws_b64 decode selftest " "%d result '%s' %d\n", test, buf, n); return -1; } } return 0; } #endif |
Added undroid/libwebsockets/lib/client-handshake.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" struct lws * lws_client_connect_2(struct lws *wsi) { #ifdef LWS_USE_IPV6 struct sockaddr_in6 server_addr6; struct addrinfo hints, *result; #endif struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; struct sockaddr_in server_addr4; struct lws_pollfd pfd; struct sockaddr *v; int n, plen = 0; const char *ads; lwsl_client("%s\n", __func__); /* proxy? */ if (wsi->vhost->http_proxy_port) { plen = sprintf((char *)pt->serv_buf, "CONNECT %s:%u HTTP/1.0\x0d\x0a" "User-agent: libwebsockets\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS), wsi->u.hdr.c_port); if (wsi->vhost->proxy_basic_auth_token[0]) plen += sprintf((char *)pt->serv_buf + plen, "Proxy-authorization: basic %s\x0d\x0a", wsi->vhost->proxy_basic_auth_token); plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a"); ads = wsi->vhost->http_proxy_address; #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { memset(&server_addr6, 0, sizeof(struct sockaddr_in6)); server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port); } else #endif server_addr4.sin_port = htons(wsi->vhost->http_proxy_port); } else { ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS); #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { memset(&server_addr6, 0, sizeof(struct sockaddr_in6)); server_addr6.sin6_port = htons(wsi->u.hdr.c_port); } else #endif server_addr4.sin_port = htons(wsi->u.hdr.c_port); } /* * prepare the actual connection (to the proxy, if any) */ lwsl_client("%s: address %s\n", __func__, ads); #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { memset(&hints, 0, sizeof(struct addrinfo)); #if !defined(__ANDROID__) hints.ai_family = AF_INET6; hints.ai_flags = AI_V4MAPPED; #endif n = getaddrinfo(ads, NULL, &hints, &result); if (n) { #ifdef _WIN32 lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n)); #else lwsl_err("getaddrinfo: %s\n", gai_strerror(n)); #endif goto oom4; } server_addr6.sin6_family = AF_INET6; switch (result->ai_family) { #if defined(__ANDROID__) case AF_INET: /* map IPv4 to IPv6 */ bzero((char *)&server_addr6.sin6_addr, sizeof(struct in6_addr)); server_addr6.sin6_addr.s6_addr[10] = 0xff; server_addr6.sin6_addr.s6_addr[11] = 0xff; memcpy(&server_addr6.sin6_addr.s6_addr[12], &((struct sockaddr_in *)result->ai_addr)->sin_addr, sizeof(struct in_addr)); break; #endif case AF_INET6: memcpy(&server_addr6.sin6_addr, &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr, sizeof(struct in6_addr)); break; default: lwsl_err("Unknown address family\n"); freeaddrinfo(result); goto oom4; } freeaddrinfo(result); } else #endif { struct addrinfo ai, *res, *result; void *p = NULL; memset (&ai, 0, sizeof ai); ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; ai.ai_flags = AI_CANONNAME; if (getaddrinfo(ads, NULL, &ai, &result)) { lwsl_err("getaddrinfo failed\n"); goto oom4; } res = result; while (!p && res) { switch (res->ai_family) { case AF_INET: p = &((struct sockaddr_in *)res->ai_addr)->sin_addr; break; } res = res->ai_next; } if (!p) { lwsl_err("Couldn't identify address\n"); freeaddrinfo(result); goto oom4; } server_addr4.sin_family = AF_INET; server_addr4.sin_addr = *((struct in_addr *)p); bzero(&server_addr4.sin_zero, 8); freeaddrinfo(result); } if (!lws_socket_is_valid(wsi->sock)) { #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) wsi->sock = socket(AF_INET6, SOCK_STREAM, 0); else #endif wsi->sock = socket(AF_INET, SOCK_STREAM, 0); if (!lws_socket_is_valid(wsi->sock)) { lwsl_warn("Unable to open socket\n"); goto oom4; } if (lws_plat_set_socket_options(wsi->vhost, wsi->sock)) { lwsl_err("Failed to set wsi socket options\n"); compatible_close(wsi->sock); goto oom4; } wsi->mode = LWSCM_WSCL_WAITING_CONNECT; lws_libev_accept(wsi, wsi->sock); lws_libuv_accept(wsi, wsi->sock); if (insert_wsi_socket_into_fds(context, wsi)) { compatible_close(wsi->sock); goto oom4; } /* * past here, we can't simply free the structs as error * handling as oom4 does. We have to run the whole close flow. */ if (!wsi->protocol) wsi->protocol = &wsi->vhost->protocols[0]; wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE, wsi->user_space, NULL, 0); lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, AWAITING_TIMEOUT); n = lws_socket_bind(wsi->vhost, wsi->sock, 0, wsi->vhost->iface); if (n < 0) goto failed; } #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { v = (struct sockaddr *)&server_addr6; n = sizeof(struct sockaddr_in6); } else #endif { v = (struct sockaddr *)&server_addr4; n = sizeof(struct sockaddr); } if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) { if (LWS_ERRNO == LWS_EALREADY || LWS_ERRNO == LWS_EINPROGRESS || LWS_ERRNO == LWS_EWOULDBLOCK #ifdef _WIN32 || LWS_ERRNO == WSAEINVAL #endif ) { lwsl_client("nonblocking connect retry\n"); /* * must do specifically a POLLOUT poll to hear * about the connect completion */ if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) goto failed; return wsi; } if (LWS_ERRNO != LWS_EISCONN) { lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO); goto failed; } } lwsl_client("connected\n"); /* we are connected to server, or proxy */ if (wsi->vhost->http_proxy_port) { /* * OK from now on we talk via the proxy, so connect to that * * (will overwrite existing pointer, * leaving old string/frag there but unreferenced) */ if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, wsi->vhost->http_proxy_address)) goto failed; wsi->u.hdr.c_port = wsi->vhost->http_proxy_port; n = send(wsi->sock, (char *)pt->serv_buf, plen, MSG_NOSIGNAL); if (n < 0) { lwsl_debug("ERROR writing to proxy socket\n"); goto failed; } lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT); wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY; return wsi; } /* * provoke service to issue the handshake directly * we need to do it this way because in the proxy case, this is the * next state and executed only if and when we get a good proxy * response inside the state machine... but notice in SSL case this * may not have sent anything yet with 0 return, and won't until some * many retries from main loop. To stop that becoming endless, * cover with a timeout. */ lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT); wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE; pfd.fd = wsi->sock; pfd.events = LWS_POLLIN; pfd.revents = LWS_POLLIN; n = lws_service_fd(context, &pfd); if (n < 0) goto failed; if (n) /* returns 1 on failure after closing wsi */ return NULL; return wsi; oom4: /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; //lwsl_err("%d\n", wsi->mode); if (wsi->mode == LWSCM_HTTP_CLIENT) wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); /* take care that we might be inserted in fds already */ if (wsi->position_in_fds_table != -1) goto failed; lws_header_table_detach(wsi, 0); lws_free(wsi); return NULL; failed: lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return NULL; } /** * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect) * this only works if still in HTTP, ie, not upgraded yet * wsi: connection to reset * address: network address of the new server * port: port to connect to * path: uri path to connect to on the new server * host: host header to send to the new server */ LWS_VISIBLE struct lws * lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host) { if (wsi->u.hdr.redirects == 3) { lwsl_err("%s: Too many redirects\n", __func__); return NULL; } wsi->u.hdr.redirects++; #ifdef LWS_OPENSSL_SUPPORT wsi->use_ssl = ssl; #else if (ssl) { lwsl_err("%s: not configured for ssl\n", __func__); return NULL; } #endif lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path); if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address)) return NULL; if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path)) return NULL; if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host)) return NULL; compatible_close(wsi->sock); remove_wsi_socket_from_fds(wsi); wsi->sock = LWS_SOCK_INVALID; wsi->state = LWSS_CLIENT_UNCONNECTED; wsi->protocol = NULL; wsi->pending_timeout = NO_PENDING_TIMEOUT; wsi->u.hdr.c_port = port; return lws_client_connect_2(wsi); } #ifdef LWS_WITH_HTTP_PROXY static hubbub_error html_parser_cb(const hubbub_token *token, void *pw) { struct lws_rewrite *r = (struct lws_rewrite *)pw; char buf[1024], *start = buf + LWS_PRE, *p = start, *end = &buf[sizeof(buf) - 1]; size_t i; switch (token->type) { case HUBBUB_TOKEN_DOCTYPE: p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ", (int) token->data.doctype.name.len, token->data.doctype.name.ptr, token->data.doctype.force_quirks ? "(force-quirks) " : ""); if (token->data.doctype.public_missing) printf("\tpublic: missing\n"); else p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n", (int) token->data.doctype.public_id.len, token->data.doctype.public_id.ptr); if (token->data.doctype.system_missing) printf("\tsystem: missing\n"); else p += lws_snprintf(p, end - p, " \"%.*s\">\n", (int) token->data.doctype.system_id.len, token->data.doctype.system_id.ptr); break; case HUBBUB_TOKEN_START_TAG: p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len, token->data.tag.name.ptr); /* (token->data.tag.self_closing) ? "(self-closing) " : "", (token->data.tag.n_attributes > 0) ? "attributes:" : ""); */ for (i = 0; i < token->data.tag.n_attributes; i++) { if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) || !hstrcmp(&token->data.tag.attributes[i].name, "action", 6) || !hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) { const char *pp = (const char *)token->data.tag.attributes[i].value.ptr; int plen = (int) token->data.tag.attributes[i].value.len; if (!hstrcmp(&token->data.tag.attributes[i].value, r->from, r->from_len)) { pp += r->from_len; plen -= r->from_len; } p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"", (int) token->data.tag.attributes[i].name.len, token->data.tag.attributes[i].name.ptr, r->to, plen, pp); } else p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"", (int) token->data.tag.attributes[i].name.len, token->data.tag.attributes[i].name.ptr, (int) token->data.tag.attributes[i].value.len, token->data.tag.attributes[i].value.ptr); } p += lws_snprintf(p, end - p, ">\n"); break; case HUBBUB_TOKEN_END_TAG: p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len, token->data.tag.name.ptr); /* (token->data.tag.self_closing) ? "(self-closing) " : "", (token->data.tag.n_attributes > 0) ? "attributes:" : ""); */ for (i = 0; i < token->data.tag.n_attributes; i++) { p += lws_snprintf(p, end - p, " %.*s='%.*s'\n", (int) token->data.tag.attributes[i].name.len, token->data.tag.attributes[i].name.ptr, (int) token->data.tag.attributes[i].value.len, token->data.tag.attributes[i].value.ptr); } p += lws_snprintf(p, end - p, ">\n"); break; case HUBBUB_TOKEN_COMMENT: p += lws_snprintf(p, end - p, "<!-- %.*s -->\n", (int) token->data.comment.len, token->data.comment.ptr); break; case HUBBUB_TOKEN_CHARACTER: p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len, token->data.character.ptr); break; case HUBBUB_TOKEN_EOF: p += lws_snprintf(p, end - p, "\n"); break; } if (user_callback_handle_rxflow(r->wsi->protocol->callback, r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ, r->wsi->user_space, start, p - start)) return -1; return HUBBUB_OK; } #endif /** * lws_client_connect_via_info() - Connect to another websocket server * @i:pointer to lws_client_connect_info struct * * This function creates a connection to a remote server */ LWS_VISIBLE struct lws * lws_client_connect_via_info(struct lws_client_connect_info *i) { struct lws *wsi; int v = SPEC_LATEST_SUPPORTED; if (i->context->requested_kill) return NULL; wsi = lws_zalloc(sizeof(struct lws)); if (wsi == NULL) goto bail; wsi->context = i->context; /* assert the mode and union status (hdr) clearly */ lws_union_transition(wsi, LWSCM_HTTP_CLIENT); wsi->sock = LWS_SOCK_INVALID; /* 1) fill up the wsi with stuff from the connect_info as far as it * can go. It's because not only is our connection async, we might * not even be able to get ahold of an ah at this point. */ /* -1 means just use latest supported */ if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one) v = i->ietf_version_or_minus_one; wsi->ietf_spec_revision = v; wsi->user_space = NULL; wsi->state = LWSS_CLIENT_UNCONNECTED; wsi->protocol = NULL; wsi->pending_timeout = NO_PENDING_TIMEOUT; wsi->position_in_fds_table = -1; wsi->u.hdr.c_port = i->port; wsi->vhost = i->vhost; if (!wsi->vhost) wsi->vhost = i->context->vhost_list; wsi->protocol = &wsi->vhost->protocols[0]; if (wsi && !wsi->user_space && i->userdata) { wsi->user_space_externally_allocated = 1; wsi->user_space = i->userdata; } else /* if we stay in http, we can assign the user space now, * otherwise do it after the protocol negotiated */ if (i->method) if (lws_ensure_user_space(wsi)) goto bail; #ifdef LWS_OPENSSL_SUPPORT wsi->use_ssl = i->ssl_connection; #else if (i->ssl_connection) { lwsl_err("libwebsockets not configured for ssl\n"); goto bail; } #endif /* 2) stash the things from connect_info that we can't process without * an ah. Because if no ah, we will go on the ah waiting list and * process those things later (after the connect_info and maybe the * things pointed to have gone out of scope. */ wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash)); if (!wsi->u.hdr.stash) { lwsl_err("%s: OOM\n", __func__); goto bail; } wsi->u.hdr.stash->origin[0] = '\0'; wsi->u.hdr.stash->protocol[0] = '\0'; wsi->u.hdr.stash->method[0] = '\0'; strncpy(wsi->u.hdr.stash->address, i->address, sizeof(wsi->u.hdr.stash->address) - 1); strncpy(wsi->u.hdr.stash->path, i->path, sizeof(wsi->u.hdr.stash->path) - 1); strncpy(wsi->u.hdr.stash->host, i->host, sizeof(wsi->u.hdr.stash->host) - 1); if (i->origin) strncpy(wsi->u.hdr.stash->origin, i->origin, sizeof(wsi->u.hdr.stash->origin) - 1); if (i->protocol) strncpy(wsi->u.hdr.stash->protocol, i->protocol, sizeof(wsi->u.hdr.stash->protocol) - 1); if (i->method) strncpy(wsi->u.hdr.stash->method, i->method, sizeof(wsi->u.hdr.stash->method) - 1); wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0'; wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0'; wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0'; wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0'; wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0'; wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0'; /* if we went on the waiting list, no probs just return the wsi * when we get the ah, now or later, he will call * lws_client_connect_via_info2() below. */ if (lws_header_table_attach(wsi, 0) < 0) return NULL; if (i->parent_wsi) { lwsl_info("%s: created child %p of parent %p\n", __func__, wsi, i->parent_wsi); wsi->parent = i->parent_wsi; wsi->sibling_list = i->parent_wsi->child_list; i->parent_wsi->child_list = wsi; } #ifdef LWS_WITH_HTTP_PROXY if (i->uri_replace_to) wsi->rw = lws_rewrite_create(wsi, html_parser_cb, i->uri_replace_from, i->uri_replace_to); #endif return wsi; bail: lws_free(wsi); return NULL; } struct lws * lws_client_connect_via_info2(struct lws *wsi) { struct client_info_stash *stash = wsi->u.hdr.stash; if (!stash) return wsi; /* * we're not necessarily in a position to action these right away, * stash them... we only need during connect phase so u.hdr is fine */ if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, stash->address)) goto bail1; /* these only need u.hdr lifetime as well */ if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path)) goto bail1; if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host)) goto bail1; if (stash->origin[0]) if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, stash->origin)) goto bail1; /* * this is a list of protocols we tell the server we're okay with * stash it for later when we compare server response with it */ if (stash->protocol[0]) if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, stash->protocol)) goto bail1; if (stash->method[0]) if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD, stash->method)) goto bail1; lws_free_set_NULL(wsi->u.hdr.stash); /* * Check with each extension if it is able to route and proxy this * connection for us. For example, an extension like x-google-mux * can handle this and then we don't need an actual socket for this * connection. */ if (lws_ext_cb_all_exts(wsi->context, wsi, LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION, (void *)stash->address, wsi->u.hdr.c_port) > 0) { lwsl_client("lws_client_connect: ext handling conn\n"); lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, AWAITING_TIMEOUT); wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT; return wsi; } lwsl_client("lws_client_connect: direct conn\n"); wsi->context->count_wsi_allocated++; return lws_client_connect_2(wsi); bail1: lws_free_set_NULL(wsi->u.hdr.stash); return NULL; } /** * lws_client_connect_extended() - Connect to another websocket server * DEPRECATED use lws_client_connect_via_info * @context: Websocket context * @address: Remote server address, eg, "myserver.com" * @port: Port to connect to on the remote server, eg, 80 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self * signed certs * @path: Websocket path on server * @host: Hostname on server * @origin: Socket origin name * @protocol: Comma-separated list of protocols being asked for from * the server, or just one. The server will pick the one it * likes best. * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest * protocol supported, or the specific protocol ordinal * @userdata: Pre-allocated user data * * This function creates a connection to a remote server */ LWS_VISIBLE struct lws * lws_client_connect_extended(struct lws_context *context, const char *address, int port, int ssl_connection, const char *path, const char *host, const char *origin, const char *protocol, int ietf_version_or_minus_one, void *userdata) { struct lws_client_connect_info i; memset(&i, 0, sizeof(i)); i.context = context; i.address = address; i.port = port; i.ssl_connection = ssl_connection; i.path = path; i.host = host; i.origin = origin; i.protocol = protocol; i.ietf_version_or_minus_one = ietf_version_or_minus_one; i.userdata = userdata; return lws_client_connect_via_info(&i); } /** * lws_client_connect_info() - Connect to another websocket server * DEPRECATED use lws_client_connect_via_info * @context: Websocket context * @address: Remote server address, eg, "myserver.com" * @port: Port to connect to on the remote server, eg, 80 * @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self * signed certs * @path: Websocket path on server * @host: Hostname on server * @origin: Socket origin name * @protocol: Comma-separated list of protocols being asked for from * the server, or just one. The server will pick the one it * likes best. If you don't want to specify a protocol, which is * legal, use NULL here. * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest * protocol supported, or the specific protocol ordinal * * This function creates a connection to a remote server */ LWS_VISIBLE struct lws * lws_client_connect(struct lws_context *context, const char *address, int port, int ssl_connection, const char *path, const char *host, const char *origin, const char *protocol, int ietf_version_or_minus_one) { struct lws_client_connect_info i; memset(&i, 0, sizeof(i)); i.context = context; i.address = address; i.port = port; i.ssl_connection = ssl_connection; i.path = path; i.host = host; i.origin = origin; i.protocol = protocol; i.ietf_version_or_minus_one = ietf_version_or_minus_one; i.userdata = NULL; return lws_client_connect_via_info(&i); } |
Added undroid/libwebsockets/lib/client-parser.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" int lws_client_rx_sm(struct lws *wsi, unsigned char c) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; int callback_action = LWS_CALLBACK_CLIENT_RECEIVE; int handled, n, m, rx_draining_ext = 0; unsigned short close_code; struct lws_tokens eff_buf; unsigned char *pp; if (wsi->u.ws.rx_draining_ext) { struct lws **w = &pt->rx_draining_ext_list; lwsl_ext("%s: RX EXT DRAINING: Removing from list\n", __func__, c); assert(!c); eff_buf.token = NULL; eff_buf.token_len = 0; wsi->u.ws.rx_draining_ext = 0; /* remove us from context draining ext list */ while (*w) { if (*w == wsi) { *w = wsi->u.ws.rx_draining_ext_list; break; } w = &((*w)->u.ws.rx_draining_ext_list); } wsi->u.ws.rx_draining_ext_list = NULL; rx_draining_ext = 1; goto drain_extension; } switch (wsi->lws_rx_parse_state) { case LWS_RXPS_NEW: /* control frames (PING) may interrupt checkable sequences */ wsi->u.ws.defeat_check_utf8 = 0; switch (wsi->ietf_spec_revision) { case 13: wsi->u.ws.opcode = c & 0xf; /* revisit if an extension wants them... */ switch (wsi->u.ws.opcode) { case LWSWSOPC_TEXT_FRAME: wsi->u.ws.rsv_first_msg = (c & 0x70); wsi->u.ws.continuation_possible = 1; wsi->u.ws.check_utf8 = lws_check_opt( wsi->context->options, LWS_SERVER_OPTION_VALIDATE_UTF8); wsi->u.ws.utf8 = 0; break; case LWSWSOPC_BINARY_FRAME: wsi->u.ws.rsv_first_msg = (c & 0x70); wsi->u.ws.check_utf8 = 0; wsi->u.ws.continuation_possible = 1; break; case LWSWSOPC_CONTINUATION: if (!wsi->u.ws.continuation_possible) { lwsl_info("disordered continuation\n"); return -1; } break; case LWSWSOPC_CLOSE: wsi->u.ws.check_utf8 = 0; wsi->u.ws.utf8 = 0; break; case 3: case 4: case 5: case 6: case 7: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: lwsl_info("illegal opcode\n"); return -1; default: wsi->u.ws.defeat_check_utf8 = 1; break; } wsi->u.ws.rsv = (c & 0x70); /* revisit if an extension wants them... */ if ( #ifndef LWS_NO_EXTENSIONS !wsi->count_act_ext && #endif wsi->u.ws.rsv) { lwsl_info("illegal rsv bits set\n"); return -1; } wsi->u.ws.final = !!((c >> 7) & 1); lwsl_ext("%s: This RX frame Final %d\n", __func__, wsi->u.ws.final); if (wsi->u.ws.owed_a_fin && (wsi->u.ws.opcode == LWSWSOPC_TEXT_FRAME || wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME)) { lwsl_info("hey you owed us a FIN\n"); return -1; } if ((!(wsi->u.ws.opcode & 8)) && wsi->u.ws.final) { wsi->u.ws.continuation_possible = 0; wsi->u.ws.owed_a_fin = 0; } if ((wsi->u.ws.opcode & 8) && !wsi->u.ws.final) { lwsl_info("control message cannot be fragmented\n"); return -1; } if (!wsi->u.ws.final) wsi->u.ws.owed_a_fin = 1; switch (wsi->u.ws.opcode) { case LWSWSOPC_TEXT_FRAME: case LWSWSOPC_BINARY_FRAME: wsi->u.ws.frame_is_binary = wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME; break; } wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; break; default: lwsl_err("unknown spec version %02d\n", wsi->ietf_spec_revision); break; } break; case LWS_RXPS_04_FRAME_HDR_LEN: wsi->u.ws.this_frame_masked = !!(c & 0x80); switch (c & 0x7f) { case 126: /* control frames are not allowed to have big lengths */ if (wsi->u.ws.opcode & 8) goto illegal_ctl_length; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2; break; case 127: /* control frames are not allowed to have big lengths */ if (wsi->u.ws.opcode & 8) goto illegal_ctl_length; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8; break; default: wsi->u.ws.rx_packet_length = c; if (wsi->u.ws.this_frame_masked) wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; else { if (c) wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; else { wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } } break; } break; case LWS_RXPS_04_FRAME_HDR_LEN16_2: wsi->u.ws.rx_packet_length = c << 8; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; break; case LWS_RXPS_04_FRAME_HDR_LEN16_1: wsi->u.ws.rx_packet_length |= c; if (wsi->u.ws.this_frame_masked) wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; else { if (wsi->u.ws.rx_packet_length) wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; else { wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } } break; case LWS_RXPS_04_FRAME_HDR_LEN64_8: if (c & 0x80) { lwsl_warn("b63 of length must be zero\n"); /* kill the connection */ return -1; } #if defined __LP64__ wsi->u.ws.rx_packet_length = ((size_t)c) << 56; #else wsi->u.ws.rx_packet_length = 0; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7; break; case LWS_RXPS_04_FRAME_HDR_LEN64_7: #if defined __LP64__ wsi->u.ws.rx_packet_length |= ((size_t)c) << 48; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6; break; case LWS_RXPS_04_FRAME_HDR_LEN64_6: #if defined __LP64__ wsi->u.ws.rx_packet_length |= ((size_t)c) << 40; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5; break; case LWS_RXPS_04_FRAME_HDR_LEN64_5: #if defined __LP64__ wsi->u.ws.rx_packet_length |= ((size_t)c) << 32; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4; break; case LWS_RXPS_04_FRAME_HDR_LEN64_4: wsi->u.ws.rx_packet_length |= ((size_t)c) << 24; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; break; case LWS_RXPS_04_FRAME_HDR_LEN64_3: wsi->u.ws.rx_packet_length |= ((size_t)c) << 16; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; break; case LWS_RXPS_04_FRAME_HDR_LEN64_2: wsi->u.ws.rx_packet_length |= ((size_t)c) << 8; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; break; case LWS_RXPS_04_FRAME_HDR_LEN64_1: wsi->u.ws.rx_packet_length |= (size_t)c; if (wsi->u.ws.this_frame_masked) wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; else { if (wsi->u.ws.rx_packet_length) wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; else { wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } } break; case LWS_RXPS_07_COLLECT_FRAME_KEY_1: wsi->u.ws.mask[0] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_2: wsi->u.ws.mask[1] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_3: wsi->u.ws.mask[2] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_4: wsi->u.ws.mask[3] = c; if (c) wsi->u.ws.all_zero_nonce = 0; if (wsi->u.ws.rx_packet_length) wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; else { wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } break; case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: assert(wsi->u.ws.rx_ubuf); if (wsi->u.ws.this_frame_masked && !wsi->u.ws.all_zero_nonce) c ^= wsi->u.ws.mask[(wsi->u.ws.mask_idx++) & 3]; wsi->u.ws.rx_ubuf[LWS_PRE + (wsi->u.ws.rx_ubuf_head++)] = c; if (--wsi->u.ws.rx_packet_length == 0) { /* spill because we have the whole frame */ wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } /* * if there's no protocol max frame size given, we are * supposed to default to LWS_MAX_SOCKET_IO_BUF */ if (!wsi->protocol->rx_buffer_size && wsi->u.ws.rx_ubuf_head != LWS_MAX_SOCKET_IO_BUF) break; if (wsi->protocol->rx_buffer_size && wsi->u.ws.rx_ubuf_head != wsi->protocol->rx_buffer_size) break; /* spill because we filled our rx buffer */ spill: handled = 0; /* * is this frame a control packet we should take care of at this * layer? If so service it and hide it from the user callback */ switch (wsi->u.ws.opcode) { case LWSWSOPC_CLOSE: pp = (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE]; if (lws_check_opt(wsi->context->options, LWS_SERVER_OPTION_VALIDATE_UTF8) && wsi->u.ws.rx_ubuf_head > 2 && lws_check_utf8(&wsi->u.ws.utf8, pp + 2, wsi->u.ws.rx_ubuf_head - 2)) goto utf8_fail; /* is this an acknowledgement of our close? */ if (wsi->state == LWSS_AWAITING_CLOSE_ACK) { /* * fine he has told us he is closing too, let's * finish our close */ lwsl_parser("seen server's close ack\n"); return -1; } lwsl_parser("client sees server close len = %d\n", wsi->u.ws.rx_ubuf_head); if (wsi->u.ws.rx_ubuf_head >= 2) { close_code = (pp[0] << 8) | pp[1]; if (close_code < 1000 || close_code == 1004 || close_code == 1005 || close_code == 1006 || close_code == 1012 || close_code == 1013 || close_code == 1014 || close_code == 1015 || (close_code >= 1016 && close_code < 3000) ) { pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff; pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff; } } if (user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, wsi->user_space, pp, wsi->u.ws.rx_ubuf_head)) return -1; /* * parrot the close packet payload back * we do not care about how it went, we are closing * immediately afterwards */ lws_write(wsi, (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE], wsi->u.ws.rx_ubuf_head, LWS_WRITE_CLOSE); wsi->state = LWSS_RETURNED_CLOSE_ALREADY; /* close the connection */ return -1; case LWSWSOPC_PING: lwsl_info("received %d byte ping, sending pong\n", wsi->u.ws.rx_ubuf_head); /* he set a close reason on this guy, ignore PING */ if (wsi->u.ws.close_in_ping_buffer_len) goto ping_drop; if (wsi->u.ws.ping_pending_flag) { /* * there is already a pending ping payload * we should just log and drop */ lwsl_parser("DROP PING since one pending\n"); goto ping_drop; } /* control packets can only be < 128 bytes long */ if (wsi->u.ws.rx_ubuf_head > 128 - 3) { lwsl_parser("DROP PING payload too large\n"); goto ping_drop; } /* stash the pong payload */ memcpy(wsi->u.ws.ping_payload_buf + LWS_PRE, &wsi->u.ws.rx_ubuf[LWS_PRE], wsi->u.ws.rx_ubuf_head); wsi->u.ws.ping_payload_len = wsi->u.ws.rx_ubuf_head; wsi->u.ws.ping_pending_flag = 1; /* get it sent as soon as possible */ lws_callback_on_writable(wsi); ping_drop: wsi->u.ws.rx_ubuf_head = 0; handled = 1; break; case LWSWSOPC_PONG: lwsl_info("client receied pong\n"); lwsl_hexdump(&wsi->u.ws.rx_ubuf[LWS_PRE], wsi->u.ws.rx_ubuf_head); /* issue it */ callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG; break; case LWSWSOPC_CONTINUATION: case LWSWSOPC_TEXT_FRAME: case LWSWSOPC_BINARY_FRAME: break; default: lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode); /* * It's something special we can't understand here. * Pass the payload up to the extension's parsing * state machine. */ eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE]; eff_buf.token_len = wsi->u.ws.rx_ubuf_head; if (lws_ext_cb_active(wsi, LWS_EXT_CB_EXTENDED_PAYLOAD_RX, &eff_buf, 0) <= 0) { /* not handle or fail */ lwsl_ext("Unhandled ext opc 0x%x\n", wsi->u.ws.opcode); wsi->u.ws.rx_ubuf_head = 0; return 0; } handled = 1; break; } /* * No it's real payload, pass it up to the user callback. * It's nicely buffered with the pre-padding taken care of * so it can be sent straight out again using lws_write */ if (handled) goto already_done; eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE]; eff_buf.token_len = wsi->u.ws.rx_ubuf_head; drain_extension: n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0); lwsl_ext("Ext RX returned %d\n", n); if (n < 0) /* fail */ return -1; lwsl_ext("post inflate eff_buf len %d\n", eff_buf.token_len); if (rx_draining_ext && !eff_buf.token_len) { lwsl_err(" --- ignoring zero drain result, ending drain\n"); goto already_done; } if (wsi->u.ws.check_utf8 && !wsi->u.ws.defeat_check_utf8) { if (lws_check_utf8(&wsi->u.ws.utf8, (unsigned char *)eff_buf.token, eff_buf.token_len)) goto utf8_fail; /* we are ending partway through utf-8 character? */ if (!wsi->u.ws.rx_packet_length && wsi->u.ws.final && wsi->u.ws.utf8 && !n) { lwsl_info("FINAL utf8 error\n"); utf8_fail: lwsl_info("utf8 error\n"); return -1; } } if (eff_buf.token_len < 0 && callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG) goto already_done; if (!eff_buf.token) goto already_done; eff_buf.token[eff_buf.token_len] = '\0'; if (!wsi->protocol->callback) goto already_done; if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG) lwsl_info("Client doing pong callback\n"); if (n && eff_buf.token_len) { /* extension had more... main loop will come back * we want callback to be done with this set, if so, * because lws_is_final() hides it was final until the * last chunk */ wsi->u.ws.rx_draining_ext = 1; wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list; pt->rx_draining_ext_list = wsi; lwsl_ext("%s: RX EXT DRAINING: Adding to list\n", __func__); } if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY || wsi->state == LWSS_AWAITING_CLOSE_ACK) goto already_done; m = wsi->protocol->callback(wsi, (enum lws_callback_reasons)callback_action, wsi->user_space, eff_buf.token, eff_buf.token_len); /* if user code wants to close, let caller know */ if (m) return 1; already_done: wsi->u.ws.rx_ubuf_head = 0; break; default: lwsl_err("client rx illegal state\n"); return 1; } return 0; illegal_ctl_length: lwsl_warn("Control frame asking for extended length is illegal\n"); /* kill the connection */ return -1; } |
Added undroid/libwebsockets/lib/client.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" int lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len) { int m; switch (wsi->mode) { case LWSCM_WSCL_WAITING_PROXY_REPLY: case LWSCM_WSCL_ISSUE_HANDSHAKE: case LWSCM_WSCL_WAITING_SERVER_REPLY: case LWSCM_WSCL_WAITING_EXTENSION_CONNECT: case LWSCM_WS_CLIENT: while (len) { /* * we were accepting input but now we stopped doing so */ if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { lwsl_debug("%s: caching %d\n", __func__, len); lws_rxflow_cache(wsi, *buf, 0, len); return 0; } if (wsi->u.ws.rx_draining_ext) { m = lws_rx_sm(wsi, 0); if (m < 0) return -1; continue; } /* account for what we're using in rxflow buffer */ if (wsi->rxflow_buffer) wsi->rxflow_pos++; if (lws_client_rx_sm(wsi, *(*buf)++)) { lwsl_debug("client_rx_sm exited\n"); return -1; } len--; } lwsl_debug("%s: finished with %d\n", __func__, len); return 0; default: break; } return 0; } int lws_client_socket_service(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pollfd) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; char *p = (char *)&pt->serv_buf[0]; char *sb = p; unsigned char c; int n, len; switch (wsi->mode) { case LWSCM_WSCL_WAITING_CONNECT: /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE * timeout protection set in client-handshake.c */ if (!lws_client_connect_2(wsi)) { /* closed */ lwsl_client("closed\n"); return -1; } /* either still pending connection, or changed mode */ return 0; case LWSCM_WSCL_WAITING_PROXY_REPLY: /* handle proxy hung up on us */ if (pollfd->revents & LWS_POLLHUP) { lwsl_warn("Proxy connection %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; } n = recv(wsi->sock, sb, LWS_MAX_SOCKET_IO_BUF, 0); if (n < 0) { if (LWS_ERRNO == LWS_EAGAIN) { lwsl_debug("Proxy read returned EAGAIN... retrying\n"); return 0; } lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); lwsl_err("ERROR reading from proxy socket\n"); return 0; } pt->serv_buf[13] = '\0'; if (strcmp(sb, "HTTP/1.0 200 ") && strcmp(sb, "HTTP/1.1 200 ")) { lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); lwsl_err("ERROR proxy: %s\n", sb); return 0; } /* clear his proxy connection timeout */ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* fallthru */ case LWSCM_WSCL_ISSUE_HANDSHAKE: /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE * timeout protection set in client-handshake.c * * take care of our lws_callback_on_writable * happening at a time when there's no real connection yet */ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) return -1; #ifdef LWS_OPENSSL_SUPPORT /* we can retry this... just cook the SSL BIO the first time */ if (wsi->use_ssl && !wsi->ssl) { if (lws_ssl_client_bio_create(wsi)) return -1; } if (wsi->use_ssl) { n = lws_ssl_client_connect1(wsi); if (!n) return 0; if (n < 0) goto bail3; } else wsi->ssl = NULL; /* fallthru */ case LWSCM_WSCL_WAITING_SSL: if (wsi->use_ssl) { n = lws_ssl_client_connect2(wsi); if (!n) return 0; if (n < 0) goto bail3; } else wsi->ssl = NULL; #endif wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE2; lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, context->timeout_secs); /* fallthru */ case LWSCM_WSCL_ISSUE_HANDSHAKE2: p = lws_generate_client_handshake(wsi, p); if (p == NULL) { lwsl_err("Failed to generate handshake for client\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; } /* send our request to the server */ lws_latency_pre(context, wsi); n = lws_ssl_capable_write(wsi, (unsigned char *)sb, p - sb); lws_latency(context, wsi, "send lws_issue_raw", n, n == p - sb); switch (n) { case LWS_SSL_CAPABLE_ERROR: lwsl_debug("ERROR writing to client socket\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 0; case LWS_SSL_CAPABLE_MORE_SERVICE: lws_callback_on_writable(wsi); break; } wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; wsi->u.hdr.lextable_pos = 0; wsi->mode = LWSCM_WSCL_WAITING_SERVER_REPLY; lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, context->timeout_secs); break; case LWSCM_WSCL_WAITING_SERVER_REPLY: /* handle server hung up on us */ if (pollfd->revents & LWS_POLLHUP) { lwsl_debug("Server connection %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); goto bail3; } if (!(pollfd->revents & LWS_POLLIN)) break; /* interpret the server response */ /* * HTTP/1.1 101 Switching Protocols * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== * Sec-WebSocket-Protocol: chat */ /* * we have to take some care here to only take from the * socket bytewise. The browser may (and has been seen to * in the case that onopen() performs websocket traffic) * coalesce both handshake response and websocket traffic * in one packet, since at that point the connection is * definitively ready from browser pov. */ len = 1; while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE && len > 0) { n = lws_ssl_capable_read(wsi, &c, 1); lws_latency(context, wsi, "send lws_issue_raw", n, n == 1); switch (n) { case 0: case LWS_SSL_CAPABLE_ERROR: goto bail3; case LWS_SSL_CAPABLE_MORE_SERVICE: return 0; } if (lws_parse(wsi, c)) { lwsl_warn("problems parsing header\n"); goto bail3; } } /* * hs may also be coming in multiple packets, there is a 5-sec * libwebsocket timeout still active here too, so if parsing did * not complete just wait for next packet coming in this state */ if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE) break; /* * otherwise deal with the handshake. If there's any * packet traffic already arrived we'll trigger poll() again * right away and deal with it that way */ return lws_client_interpret_server_handshake(wsi); bail3: lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n"); wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return -1; case LWSCM_WSCL_WAITING_EXTENSION_CONNECT: lwsl_ext("LWSCM_WSCL_WAITING_EXTENSION_CONNECT\n"); break; case LWSCM_WSCL_PENDING_CANDIDATE_CHILD: lwsl_ext("LWSCM_WSCL_PENDING_CANDIDATE_CHILD\n"); break; default: break; } return 0; } /* * In-place str to lower case */ static void strtolower(char *s) { while (*s) { *s = tolower((int)*s); s++; } } /** * lws_http_transaction_completed() - wait for new http transaction or close * @wsi: websocket connection * * Returns 1 if the HTTP connection must close now * Returns 0 and resets connection to wait for new HTTP header / * transaction if possible */ int LWS_WARN_UNUSED_RESULT lws_http_transaction_completed_client(struct lws *wsi) { lwsl_debug("%s: wsi %p\n", __func__, wsi); /* if we can't go back to accept new headers, drop the connection */ if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) { lwsl_info("%s: %p: close connection\n", __func__, wsi); return 1; } /* otherwise set ourselves up ready to go again */ wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED; wsi->mode = LWSCM_HTTP_CLIENT_ACCEPTED; wsi->u.http.content_length = 0; wsi->hdr_parsing_completed = 0; /* He asked for it to stay alive indefinitely */ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* * As client, nothing new is going to come until we ask for it * we can drop the ah, if any */ if (wsi->u.hdr.ah) { wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; lws_header_table_detach(wsi, 0); } /* If we're (re)starting on headers, need other implied init */ wsi->u.hdr.ues = URIES_IDLE; lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi); return 0; } int lws_client_interpret_server_handshake(struct lws *wsi) { int n, len, okay = 0, isErrorCodeReceived = 0, port = 0, ssl = 0; int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR; const char *pc, *prot, *ads = NULL, *path; struct allocated_headers *ah; char *p; #ifndef LWS_NO_EXTENSIONS struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; char *sb = (char *)&pt->serv_buf[0]; const struct lws_ext_options *opts; const struct lws_extension *ext; char ext_name[128]; const char *c, *a; char ignore; int more = 1; void *v; #endif if (!wsi->do_ws) { /* we are being an http client... */ ah = wsi->u.hdr.ah; lws_union_transition(wsi, LWSCM_HTTP_CLIENT_ACCEPTED); wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED; wsi->u.http.ah = ah; } /* * well, what the server sent looked reasonable for syntax. * Now let's confirm it sent all the necessary headers * * http (non-ws) client will expect something like this * * HTTP/1.0.200 * server:.libwebsockets * content-type:.text/html * content-length:.17703 * set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000 * * * */ wsi->u.http.connection_type = HTTP_CONNECTION_KEEP_ALIVE; p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP); if (wsi->do_ws && !p) { lwsl_info("no URI\n"); goto bail3; } if (!p) { p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0); wsi->u.http.connection_type = HTTP_CONNECTION_CLOSE; } if (!p) { lwsl_info("no URI\n"); goto bail3; } n = atoi(p); if (n == 301 || n == 302 || n == 303 || n == 307 || n == 308) { p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION); if (!p) goto bail3; if (lws_parse_uri(p, &prot, &ads, &port, &path)) goto bail3; if (!strcmp(prot, "wss://") || !strcmp(prot, "https://")) ssl = 1; if (lws_client_reset(wsi, ssl, ads, port, path, ads)) { lwsl_err("Redirect failed\n"); goto bail3; } return 0; } if (!wsi->do_ws) { if (n != 200) { lwsl_notice("Connection failed with code %d", n); goto bail2; } #ifdef LWS_WITH_HTTP_PROXY wsi->perform_rewrite = 0; if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) { if (!strncmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE), "text/html", 9)) wsi->perform_rewrite = 1; } #endif /* allocate the per-connection user memory (if any) */ if (lws_ensure_user_space(wsi)) { lwsl_err("Problem allocating wsi user mem\n"); goto bail2; } /* he may choose to send us stuff in chunked transfer-coding */ wsi->chunked = 0; wsi->chunk_remaining = 0; /* ie, next thing is chunk size */ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING)) { wsi->chunked = !strcmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING), "chunked"); /* first thing is hex, after payload there is crlf */ wsi->chunk_parser = ELCP_HEX; } if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { wsi->u.http.content_length = atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)); lwsl_notice("%s: incoming content length %d\n", __func__, wsi->u.http.content_length); wsi->u.http.content_remain = wsi->u.http.content_length; } else /* can't do 1.1 without a content length or chunked */ if (!wsi->chunked) wsi->u.http.connection_type = HTTP_CONNECTION_CLOSE; /* * we seem to be good to go, give client last chance to check * headers and OK it */ if (wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, wsi->user_space, NULL, 0)) goto bail2; /* clear his proxy connection timeout */ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; /* call him back to inform him he is up */ if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP, wsi->user_space, NULL, 0)) goto bail3; /* free up his parsing allocations */ lws_header_table_detach(wsi, 0); lwsl_notice("%s: client connection up\n", __func__); return 0; } if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) { lwsl_info("no ACCEPT\n"); isErrorCodeReceived = 1; goto bail3; } if (p && strncmp(p, "101", 3)) { lwsl_warn( "lws_client_handshake: got bad HTTP response '%s'\n", p); goto bail3; } p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE); if (!p) { lwsl_info("no UPGRADE\n"); goto bail3; } strtolower(p); if (strcmp(p, "websocket")) { lwsl_warn( "lws_client_handshake: got bad Upgrade header '%s'\n", p); goto bail3; } p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION); if (!p) { lwsl_info("no Connection hdr\n"); goto bail3; } strtolower(p); if (strcmp(p, "upgrade")) { lwsl_warn("lws_client_int_s_hs: bad header %s\n", p); goto bail3; } pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS); if (!pc) { lwsl_parser("lws_client_int_s_hs: no protocol list\n"); } else lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc); /* * confirm the protocol the server wants to talk was in the list * of protocols we offered */ len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL); if (!len) { lwsl_info("lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\n"); /* * no protocol name to work from, * default to first protocol */ wsi->protocol = &wsi->vhost->protocols[0]; goto check_extensions; } p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL); len = strlen(p); while (pc && *pc && !okay) { if (!strncmp(pc, p, len) && (pc[len] == ',' || pc[len] == '\0')) { okay = 1; continue; } while (*pc && *pc++ != ',') ; while (*pc && *pc == ' ') pc++; } if (!okay) { lwsl_err("lws_client_int_s_hs: got bad protocol %s\n", p); goto bail2; } /* * identify the selected protocol struct and set it */ n = 0; wsi->protocol = NULL; while (wsi->vhost->protocols[n].callback && !wsi->protocol) { if (strcmp(p, wsi->vhost->protocols[n].name) == 0) { wsi->protocol = &wsi->vhost->protocols[n]; break; } n++; } if (wsi->protocol == NULL) { lwsl_err("lws_client_int_s_hs: fail protocol %s\n", p); goto bail2; } check_extensions: #ifndef LWS_NO_EXTENSIONS /* instantiate the accepted extensions */ if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) { lwsl_ext("no client extensions allowed by server\n"); goto check_accept; } /* * break down the list of server accepted extensions * and go through matching them or identifying bogons */ if (lws_hdr_copy(wsi, sb, LWS_MAX_SOCKET_IO_BUF, WSI_TOKEN_EXTENSIONS) < 0) { lwsl_warn("ext list from server failed to copy\n"); goto bail2; } c = sb; n = 0; ignore = 0; a = NULL; while (more) { if (*c && (*c != ',' && *c != '\t')) { if (*c == ';') { ignore = 1; if (!a) a = c + 1; } if (ignore || *c == ' ') { c++; continue; } ext_name[n] = *c++; if (n < sizeof(ext_name) - 1) n++; continue; } ext_name[n] = '\0'; ignore = 0; if (!*c) more = 0; else { c++; if (!n) continue; } /* check we actually support it */ lwsl_notice("checking client ext %s\n", ext_name); n = 0; ext = wsi->vhost->extensions; while (ext && ext->callback) { if (strcmp(ext_name, ext->name)) { ext++; continue; } n = 1; lwsl_notice("instantiating client ext %s\n", ext_name); /* instantiate the extension on this conn */ wsi->active_extensions[wsi->count_act_ext] = ext; /* allow him to construct his ext instance */ if (ext->callback(lws_get_context(wsi), ext, wsi, LWS_EXT_CB_CLIENT_CONSTRUCT, (void *)&wsi->act_ext_user[wsi->count_act_ext], (void *)&opts, 0)) { lwsl_notice(" ext %s failed construction\n", ext_name); ext++; continue; } /* * allow the user code to override ext defaults if it * wants to */ ext_name[0] = '\0'; if (user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_WS_EXT_DEFAULTS, (char *)ext->name, ext_name, sizeof(ext_name))) goto bail2; if (ext_name[0] && lws_ext_parse_options(ext, wsi, wsi->act_ext_user[ wsi->count_act_ext], opts, ext_name, strlen(ext_name))) { lwsl_err("%s: unable to parse user defaults '%s'", __func__, ext_name); goto bail2; } /* * give the extension the server options */ if (a && lws_ext_parse_options(ext, wsi, wsi->act_ext_user[wsi->count_act_ext], opts, a, c - a)) { lwsl_err("%s: unable to parse remote def '%s'", __func__, a); goto bail2; } if (ext->callback(lws_get_context(wsi), ext, wsi, LWS_EXT_CB_OPTION_CONFIRM, wsi->act_ext_user[wsi->count_act_ext], NULL, 0)) { lwsl_err("%s: ext %s rejects server options %s", ext->name, a); goto bail2; } wsi->count_act_ext++; ext++; } if (n == 0) { lwsl_warn("Unknown ext '%s'!\n", ext_name); goto bail2; } a = NULL; n = 0; } check_accept: #endif /* * Confirm his accept token is the one we precomputed */ p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT); if (strcmp(p, wsi->u.hdr.ah->initial_handshake_hash_base64)) { lwsl_warn("lws_client_int_s_hs: accept '%s' wrong vs '%s'\n", p, wsi->u.hdr.ah->initial_handshake_hash_base64); goto bail2; } /* allocate the per-connection user memory (if any) */ if (lws_ensure_user_space(wsi)) { lwsl_err("Problem allocating wsi user mem\n"); goto bail2; } /* * we seem to be good to go, give client last chance to check * headers and OK it */ if (wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, wsi->user_space, NULL, 0)) goto bail2; /* clear his proxy connection timeout */ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* free up his parsing allocations */ lws_header_table_detach(wsi, 0); lws_union_transition(wsi, LWSCM_WS_CLIENT); wsi->state = LWSS_ESTABLISHED; wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; /* * create the frame buffer for this connection according to the * size mentioned in the protocol definition. If 0 there, then * use a big default for compatibility */ n = wsi->protocol->rx_buffer_size; if (!n) n = LWS_MAX_SOCKET_IO_BUF; n += LWS_PRE; wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */); if (!wsi->u.ws.rx_ubuf) { lwsl_err("Out of Mem allocating rx buffer %d\n", n); goto bail2; } wsi->u.ws.rx_ubuf_alloc = n; lwsl_info("Allocating client RX buffer %d\n", n); if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) { lwsl_warn("Failed to set SNDBUF to %d", n); goto bail3; } lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name); /* call him back to inform him he is up */ if (wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED, wsi->user_space, NULL, 0)) goto bail3; #ifndef LWS_NO_EXTENSIONS /* * inform all extensions, not just active ones since they * already know */ ext = wsi->vhost->extensions; while (ext && ext->callback) { v = NULL; for (n = 0; n < wsi->count_act_ext; n++) if (wsi->active_extensions[n] == ext) v = wsi->act_ext_user[n]; ext->callback(context, ext, wsi, LWS_EXT_CB_ANY_WSI_ESTABLISHED, v, NULL, 0); ext++; } #endif return 0; bail3: close_reason = LWS_CLOSE_STATUS_NOSTATUS; bail2: if (wsi->protocol && wsi->state == LWSS_ESTABLISHED) { if (isErrorCodeReceived && p) { wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, p, (unsigned int)strlen(p)); } else { wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); } } lwsl_info("closing connection due to bail2 connection error\n"); /* closing will free up his parsing allocations */ lws_close_free_wsi(wsi, close_reason); return 1; } char * lws_generate_client_handshake(struct lws *wsi, char *pkt) { char buf[128], hash[20], key_b64[40], *p = pkt; struct lws_context *context = wsi->context; const char *meth; int n; #ifndef LWS_NO_EXTENSIONS const struct lws_extension *ext; int ext_count = 0; #endif meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD); if (!meth) { meth = "GET"; wsi->do_ws = 1; } else wsi->do_ws = 0; if (wsi->do_ws) { /* * create the random key */ n = lws_get_random(context, hash, 16); if (n != 16) { lwsl_err("Unable to read from random dev %s\n", SYSTEM_RANDOM_FILEPATH); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return NULL; } lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64)); } /* * 04 example client handshake * * GET /chat HTTP/1.1 * Host: server.example.com * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 4 */ p += sprintf(p, "%s %s HTTP/1.1\x0d\x0a", meth, lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI)); p += sprintf(p, "Pragma: no-cache\x0d\x0a" "Cache-Control: no-cache\x0d\x0a"); p += sprintf(p, "Host: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST)); if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) p += sprintf(p, "Origin: http://%s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)); if (wsi->do_ws) { p += sprintf(p, "Upgrade: websocket\x0d\x0a" "Connection: Upgrade\x0d\x0a" "Sec-WebSocket-Key: "); strcpy(p, key_b64); p += strlen(key_b64); p += sprintf(p, "\x0d\x0a"); if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS)) p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS)); /* tell the server what extensions we could support */ #ifndef LWS_NO_EXTENSIONS ext = wsi->vhost->extensions; while (ext && ext->callback) { n = lws_ext_cb_all_exts(context, wsi, LWS_EXT_CB_CHECK_OK_TO_PROPOSE_EXTENSION, (char *)ext->name, 0); if (n) { /* an extension vetos us */ lwsl_ext("ext %s vetoed\n", (char *)ext->name); ext++; continue; } n = wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, wsi->user_space, (char *)ext->name, 0); /* * zero return from callback means * go ahead and allow the extension, * it's what we get if the callback is * unhandled */ if (n) { ext++; continue; } /* apply it */ if (ext_count) *p++ = ','; else p += sprintf(p, "Sec-WebSocket-Extensions: "); p += sprintf(p, "%s", ext->client_offer); ext_count++; ext++; } if (ext_count) p += sprintf(p, "\x0d\x0a"); #endif if (wsi->ietf_spec_revision) p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a", wsi->ietf_spec_revision); /* prepare the expected server accept response */ key_b64[39] = '\0'; /* enforce composed length below buf sizeof */ n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64); lws_SHA1((unsigned char *)buf, n, (unsigned char *)hash); lws_b64_encode_string(hash, 20, wsi->u.hdr.ah->initial_handshake_hash_base64, sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64)); } /* give userland a chance to append, eg, cookies */ wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, wsi->user_space, &p, (pkt + LWS_MAX_SOCKET_IO_BUF) - p - 12); p += sprintf(p, "\x0d\x0a"); return p; } |
Added undroid/libwebsockets/lib/context.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #ifndef LWS_BUILD_HASH #define LWS_BUILD_HASH "unknown-build-hash" #endif static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH; /** * lws_get_library_version: get version and git hash library built from * * returns a const char * to a string like "1.1 178d78c" * representing the library version followed by the git head hash it * was built from */ LWS_VISIBLE const char * lws_get_library_version(void) { return library_version; } static const char * const mount_protocols[] = { "http://", "https://", "file://", "cgi://", ">http://", ">https://", }; LWS_VISIBLE void * lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot, int size) { int n = 0; /* allocate the vh priv array only on demand */ if (!vhost->protocol_vh_privs) { vhost->protocol_vh_privs = (void **)lws_zalloc( vhost->count_protocols * sizeof(void *)); if (!vhost->protocol_vh_privs) return NULL; } while (n < vhost->count_protocols && &vhost->protocols[n] != prot) n++; if (n == vhost->count_protocols) return NULL; vhost->protocol_vh_privs[n] = lws_zalloc(size); return vhost->protocol_vh_privs[n]; } LWS_VISIBLE void * lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot) { int n = 0; if (!vhost->protocol_vh_privs) return NULL; while (n < vhost->count_protocols && &vhost->protocols[n] != prot) n++; if (n == vhost->count_protocols) { lwsl_err("%s: unknown protocol %p\n", __func__, prot); return NULL; } return vhost->protocol_vh_privs[n]; } static const struct lws_protocol_vhost_options * lws_vhost_protocol_options(struct lws_vhost *vh, const char *name) { const struct lws_protocol_vhost_options *pvo = vh->pvo; while (pvo) { // lwsl_notice("%s: '%s' '%s'\n", __func__, pvo->name, name); if (!strcmp(pvo->name, name)) return pvo; pvo = pvo->next; } return NULL; } int lws_protocol_init(struct lws_context *context) { struct lws_vhost *vh = context->vhost_list; const struct lws_protocol_vhost_options *pvo, *pvo1; struct lws wsi; int n; memset(&wsi, 0, sizeof(wsi)); wsi.context = context; lwsl_notice("%s\n", __func__); while (vh) { wsi.vhost = vh; /* initialize supported protocols on this vhost */ for (n = 0; n < vh->count_protocols; n++) { wsi.protocol = &vh->protocols[n]; pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name); if (pvo) { /* * linked list of options specific to * vh + protocol */ pvo1 = pvo; pvo = pvo1->options; while (pvo) { lwsl_notice(" vh %s prot %s opt %s\n", vh->name, vh->protocols[n].name, pvo->name); if (!strcmp(pvo->name, "default")) { lwsl_notice("Setting default " "protocol for vh %s to %s\n", vh->name, vh->protocols[n].name); vh->default_protocol_index = n; } pvo = pvo->next; } pvo = pvo1->options; } /* * inform all the protocols that they are doing their one-time * initialization if they want to. * * NOTE the wsi is all zeros except for the context, vh and * protocol ptrs so lws_get_context(wsi) etc can work */ vh->protocols[n].callback(&wsi, LWS_CALLBACK_PROTOCOL_INIT, NULL, (void *)pvo, 0); } vh = vh->vhost_next; } context->protocol_init_done = 1; return 0; } static int callback_http_dummy( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { return 0; } /* list of supported protocols and callbacks */ static const struct lws_protocols protocols_dummy[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http_dummy, /* callback */ 0, /* per_session_data_size */ 0, /* max frame size / rx buffer */ }, /* * the other protocols are provided by lws plugins */ { NULL, NULL, 0, 0 } /* terminator */ }; LWS_VISIBLE struct lws_vhost * lws_create_vhost(struct lws_context *context, struct lws_context_creation_info *info) { struct lws_vhost *vh = lws_zalloc(sizeof(*vh)), **vh1 = &context->vhost_list; const struct lws_http_mount *mounts; #ifdef LWS_WITH_PLUGINS struct lws_plugin *plugin = context->plugin_list; struct lws_protocols *lwsp; int m, n, f = !info->pvo; #endif char *p; if (!vh) return NULL; if (!info->protocols) info->protocols = &protocols_dummy[0]; vh->context = context; if (!info->vhost_name) vh->name = "default"; else vh->name = info->vhost_name; vh->iface = info->iface; for (vh->count_protocols = 0; info->protocols[vh->count_protocols].callback; vh->count_protocols++) ; vh->options = info->options; vh->pvo = info->pvo; vh->keepalive_timeout = info->keepalive_timeout; #ifdef LWS_WITH_PLUGINS if (plugin) { /* * give the vhost a unified list of protocols including the * ones that came from plugins */ lwsp = lws_zalloc(sizeof(struct lws_protocols) * (vh->count_protocols + context->plugin_protocol_count + 1)); if (!lwsp) return NULL; m = vh->count_protocols; memcpy(lwsp, info->protocols, sizeof(struct lws_protocols) * m); /* for compatibility, all protocols enabled on vhost if only * the default vhost exists. Otherwise only vhosts who ask * for a protocol get it enabled. */ if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) f = 0; while (plugin) { for (n = 0; n < plugin->caps.count_protocols; n++) { /* * for compatibility's sake, no pvo implies * allow all protocols */ if (f || lws_vhost_protocol_options(vh, plugin->caps.protocols[n].name)) { memcpy(&lwsp[m], &plugin->caps.protocols[n], sizeof(struct lws_protocols)); m++; vh->count_protocols++; } } plugin = plugin->list; } vh->protocols = lwsp; } else #endif vh->protocols = info->protocols; vh->same_vh_protocol_list = (struct lws **) lws_zalloc(sizeof(struct lws *) * vh->count_protocols); vh->mount_list = info->mounts; #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(context)) { lwsl_notice("Creating Vhost '%s' path \"%s\", %d protocols\n", vh->name, info->iface, vh->count_protocols); } else #endif lwsl_notice("Creating Vhost '%s' port %d, %d protocols\n", vh->name, info->port, vh->count_protocols); mounts = info->mounts; while (mounts) { lwsl_notice(" mounting %s%s to %s\n", mount_protocols[mounts->origin_protocol], mounts->origin, mounts->mountpoint); mounts = mounts->mount_next; } #ifndef LWS_NO_EXTENSIONS #ifdef LWS_WITH_PLUGINS if (context->plugin_extension_count) { m = 0; while (info->extensions && info->extensions[m].callback) m++; /* * give the vhost a unified list of extensions including the * ones that came from plugins */ vh->extensions = lws_zalloc(sizeof(struct lws_extension) * (m + context->plugin_extension_count + 1)); if (!vh->extensions) return NULL; memcpy((struct lws_extension *)vh->extensions, info->extensions, sizeof(struct lws_extension) * m); plugin = context->plugin_list; while (plugin) { memcpy((struct lws_extension *)&vh->extensions[m], plugin->caps.extensions, sizeof(struct lws_extension) * plugin->caps.count_extensions); m += plugin->caps.count_extensions; plugin = plugin->list; } } else #endif vh->extensions = info->extensions; #endif vh->listen_port = info->port; vh->http_proxy_port = 0; vh->http_proxy_address[0] = '\0'; /* either use proxy from info, or try get it from env var */ if (info->http_proxy_address) { /* override for backwards compatibility */ if (info->http_proxy_port) vh->http_proxy_port = info->http_proxy_port; lws_set_proxy(vh, info->http_proxy_address); } else { #ifdef LWS_HAVE_GETENV p = getenv("http_proxy"); if (p) lws_set_proxy(vh, p); #endif } vh->ka_time = info->ka_time; vh->ka_interval = info->ka_interval; vh->ka_probes = info->ka_probes; if (vh->options & LWS_SERVER_OPTION_STS) lwsl_notice(" STS enabled\n"); #ifdef LWS_WITH_ACCESS_LOG if (info->log_filepath) { vh->log_fd = open(info->log_filepath, O_CREAT | O_APPEND | O_RDWR, 0600); if (vh->log_fd == LWS_INVALID_FILE) { lwsl_err("unable to open log filepath %s\n", info->log_filepath); goto bail; } #ifndef WIN32 if (context->uid != -1) if (chown(info->log_filepath, context->uid, context->gid) == -1) lwsl_err("unable to chown log file %s\n", info->log_filepath); #endif } else vh->log_fd = LWS_INVALID_FILE; #endif if (lws_context_init_server_ssl(info, vh)) goto bail; if (lws_context_init_client_ssl(info, vh)) goto bail; if (lws_context_init_server(info, vh)) goto bail; while (1) { if (!(*vh1)) { *vh1 = vh; break; } vh1 = &(*vh1)->vhost_next; }; return vh; bail: lws_free(vh); return NULL; } /** * lws_create_context() - Create the websocket handler * @info: pointer to struct with parameters * * This function creates the listening socket (if serving) and takes care * of all initialization in one step. * * After initialization, it returns a struct lws_context * that * represents this server. After calling, user code needs to take care * of calling lws_service() with the context pointer to get the * server's sockets serviced. This must be done in the same process * context as the initialization call. * * The protocol callback functions are called for a handful of events * including http requests coming in, websocket connections becoming * established, and data arriving; it's also called periodically to allow * async transmission. * * HTTP requests are sent always to the FIRST protocol in @protocol, since * at that time websocket protocol has not been negotiated. Other * protocols after the first one never see any HTTP callack activity. * * The server created is a simple http server by default; part of the * websocket standard is upgrading this http connection to a websocket one. * * This allows the same server to provide files like scripts and favicon / * images or whatever over http and dynamic data over websockets all in * one place; they're all handled in the user callback. */ LWS_VISIBLE struct lws_context * lws_create_context(struct lws_context_creation_info *info) { struct lws_context *context = NULL; struct lws wsi; #ifndef LWS_NO_DAEMONIZE int pid_daemon = get_daemonize_pid(); #endif int n, m; #if defined(__ANDROID__) struct rlimit rt; #endif lwsl_notice("Initial logging level %d\n", log_level); lwsl_notice("Libwebsockets version: %s\n", library_version); #if LWS_POSIX #ifdef LWS_USE_IPV6 if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6)) lwsl_notice("IPV6 compiled in and enabled\n"); else lwsl_notice("IPV6 compiled in but disabled\n"); #else lwsl_notice("IPV6 not compiled in\n"); #endif lws_feature_status_libev(info); lws_feature_status_libuv(info); #endif lwsl_info(" LWS_DEF_HEADER_LEN : %u\n", LWS_DEF_HEADER_LEN); lwsl_info(" LWS_MAX_PROTOCOLS : %u\n", LWS_MAX_PROTOCOLS); lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP); lwsl_info(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED); lwsl_info(" sizeof (*info) : %u\n", sizeof(*info)); #if LWS_POSIX lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH); #endif if (lws_plat_context_early_init()) return NULL; context = lws_zalloc(sizeof(struct lws_context)); if (!context) { lwsl_err("No memory for websocket context\n"); return NULL; } context->time_up = time(NULL); #ifndef LWS_NO_DAEMONIZE if (pid_daemon) { context->started_with_parent = pid_daemon; lwsl_notice(" Started with daemon pid %d\n", pid_daemon); } #endif #if defined(__ANDROID__) n = getrlimit ( RLIMIT_NOFILE,&rt); if (-1 == n) { lwsl_err("Get RLIMIT_NOFILE failed!\n"); return NULL; } context->max_fds = rt.rlim_cur; #else context->max_fds = getdtablesize(); #endif if (info->count_threads) context->count_threads = info->count_threads; else context->count_threads = 1; if (context->count_threads > LWS_MAX_SMP) context->count_threads = LWS_MAX_SMP; context->token_limits = info->token_limits; context->options = info->options; if (info->timeout_secs) context->timeout_secs = info->timeout_secs; else context->timeout_secs = AWAITING_TIMEOUT; lwsl_info(" default timeout (secs): %u\n", context->timeout_secs); if (info->max_http_header_data) context->max_http_header_data = info->max_http_header_data; else context->max_http_header_data = LWS_DEF_HEADER_LEN; if (info->max_http_header_pool) context->max_http_header_pool = info->max_http_header_pool; else context->max_http_header_pool = LWS_DEF_HEADER_POOL; /* * Allocate the per-thread storage for scratchpad buffers, * and header data pool */ for (n = 0; n < context->count_threads; n++) { context->pt[n].serv_buf = lws_zalloc(LWS_MAX_SOCKET_IO_BUF); if (!context->pt[n].serv_buf) { lwsl_err("OOM\n"); return NULL; } context->pt[n].context = context; context->pt[n].tid = n; context->pt[n].http_header_data = lws_malloc(context->max_http_header_data * context->max_http_header_pool); if (!context->pt[n].http_header_data) goto bail; context->pt[n].ah_pool = lws_zalloc(sizeof(struct allocated_headers) * context->max_http_header_pool); for (m = 0; m < context->max_http_header_pool; m++) context->pt[n].ah_pool[m].data = (char *)context->pt[n].http_header_data + (m * context->max_http_header_data); if (!context->pt[n].ah_pool) goto bail; lws_pt_mutex_init(&context->pt[n]); } if (info->fd_limit_per_thread) context->fd_limit_per_thread = info->fd_limit_per_thread; else context->fd_limit_per_thread = context->max_fds / context->count_threads; lwsl_notice(" Threads: %d each %d fds\n", context->count_threads, context->fd_limit_per_thread); memset(&wsi, 0, sizeof(wsi)); wsi.context = context; if (!info->ka_interval && info->ka_time > 0) { lwsl_err("info->ka_interval can't be 0 if ka_time used\n"); return NULL; } #ifdef LWS_USE_LIBEV /* (Issue #264) In order to *avoid breaking backwards compatibility*, we * enable libev mediated SIGINT handling with a default handler of * lws_sigint_cb. The handler can be overridden or disabled * by invoking lws_sigint_cfg after creating the context, but * before invoking lws_initloop: */ context->use_ev_sigint = 1; context->lws_ev_sigint_cb = &lws_ev_sigint_cb; #endif /* LWS_USE_LIBEV */ #ifdef LWS_USE_LIBUV /* (Issue #264) In order to *avoid breaking backwards compatibility*, we * enable libev mediated SIGINT handling with a default handler of * lws_sigint_cb. The handler can be overridden or disabled * by invoking lws_sigint_cfg after creating the context, but * before invoking lws_initloop: */ context->use_ev_sigint = 1; context->lws_uv_sigint_cb = &lws_uv_sigint_cb; #endif lwsl_info(" mem: context: %5u bytes (%d ctx + (%d thr x %d))\n", sizeof(struct lws_context) + (context->count_threads * LWS_MAX_SOCKET_IO_BUF), sizeof(struct lws_context), context->count_threads, LWS_MAX_SOCKET_IO_BUF); lwsl_info(" mem: http hdr rsvd: %5u bytes (%u thr x (%u + %u) x %u))\n", (context->max_http_header_data + sizeof(struct allocated_headers)) * context->max_http_header_pool * context->count_threads, context->count_threads, context->max_http_header_data, sizeof(struct allocated_headers), context->max_http_header_pool); n = sizeof(struct lws_pollfd) * context->count_threads * context->fd_limit_per_thread; context->pt[0].fds = lws_zalloc(n); if (context->pt[0].fds == NULL) { lwsl_err("OOM allocating %d fds\n", context->max_fds); goto bail; } lwsl_info(" mem: pollfd map: %5u\n", n); if (info->server_string) { context->server_string = info->server_string; context->server_string_len = (short) strlen(context->server_string); } else { context->server_string = "libwebsockets"; context->server_string_len = 13; } #if LWS_MAX_SMP > 1 /* each thread serves his own chunk of fds */ for (n = 1; n < (int)info->count_threads; n++) context->pt[n].fds = context->pt[n - 1].fds + context->fd_limit_per_thread; #endif if (lws_plat_init(context, info)) goto bail; lws_context_init_ssl_library(info); context->user_space = info->user; /* * if he's not saying he'll make his own vhosts later then act * compatibly and make a default vhost using the data in the info */ if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) if (!lws_create_vhost(context, info)) { lwsl_err("Failed to create default vhost\n"); return NULL; } lws_context_init_extensions(info, context); lwsl_notice(" mem: per-conn: %5u bytes + protocol rx buf\n", sizeof(struct lws)); strcpy(context->canonical_hostname, "unknown"); lws_server_get_canonical_hostname(context, info); context->uid = info->uid; context->gid = info->gid; /* * drop any root privs for this process * to listen on port < 1023 we would have needed root, but now we are * listening, we don't want the power for anything else */ if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) lws_plat_drop_app_privileges(info); /* * give all extensions a chance to create any per-context * allocations they need */ if (info->port != CONTEXT_PORT_NO_LISTEN) { if (lws_ext_cb_all_exts(context, NULL, LWS_EXT_CB_SERVER_CONTEXT_CONSTRUCT, NULL, 0) < 0) goto bail; } else if (lws_ext_cb_all_exts(context, NULL, LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0) goto bail; return context; bail: lws_context_destroy(context); return NULL; } /** * lws_context_destroy() - Destroy the websocket context * @context: Websocket context * * This function closes any active connections and then frees the * context. After calling this, any further use of the context is * undefined. */ LWS_VISIBLE void lws_context_destroy(struct lws_context *context) { const struct lws_protocols *protocol = NULL; struct lws_context_per_thread *pt; struct lws_vhost *vh = NULL, *vh1; struct lws wsi; int n, m; lwsl_notice("%s\n", __func__); if (!context) return; m = context->count_threads; context->being_destroyed = 1; memset(&wsi, 0, sizeof(wsi)); wsi.context = context; #ifdef LWS_LATENCY if (context->worst_latency_info[0]) lwsl_notice("Worst latency: %s\n", context->worst_latency_info); #endif while (m--) { pt = &context->pt[m]; for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) { struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd); if (!wsi) continue; lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY /* no protocol close */); n--; } lws_pt_mutex_destroy(pt); } /* * give all extensions a chance to clean up any per-context * allocations they might have made */ n = lws_ext_cb_all_exts(context, NULL, LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0); n = lws_ext_cb_all_exts(context, NULL, LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0); /* * inform all the protocols that they are done and will have no more * callbacks. * * We can't free things until after the event loop shuts down. */ if (context->protocol_init_done) vh = context->vhost_list; while (vh) { wsi.vhost = vh; protocol = vh->protocols; if (protocol) { n = 0; while (n < vh->count_protocols) { wsi.protocol = protocol; protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY, NULL, NULL, 0); protocol++; n++; } } vh = vh->vhost_next; } for (n = 0; n < context->count_threads; n++) { pt = &context->pt[n]; lws_libev_destroyloop(context, n); lws_libuv_destroyloop(context, n); lws_free_set_NULL(context->pt[n].serv_buf); if (pt->ah_pool) lws_free(pt->ah_pool); if (pt->http_header_data) lws_free(pt->http_header_data); } lws_plat_context_early_destroy(context); lws_ssl_context_destroy(context); if (context->pt[0].fds) lws_free_set_NULL(context->pt[0].fds); /* free all the vhost allocations */ vh = context->vhost_list; while (vh) { protocol = vh->protocols; if (protocol) { n = 0; while (n < vh->count_protocols) { if (vh->protocol_vh_privs && vh->protocol_vh_privs[n]) { lws_free(vh->protocol_vh_privs[n]); vh->protocol_vh_privs[n] = NULL; } protocol++; n++; } } if (vh->protocol_vh_privs) lws_free(vh->protocol_vh_privs); lws_ssl_SSL_CTX_destroy(vh); lws_free(vh->same_vh_protocol_list); #ifdef LWS_WITH_PLUGINS if (context->plugin_list) lws_free((void *)vh->protocols); #ifndef LWS_NO_EXTENSIONS if (context->plugin_extension_count) lws_free((void *)vh->extensions); #endif #endif #ifdef LWS_WITH_ACCESS_LOG if (vh->log_fd != LWS_INVALID_FILE) close(vh->log_fd); #endif vh1 = vh->vhost_next; lws_free(vh); vh = vh1; } lws_plat_context_late_destroy(context); lws_free(context); } |
Added undroid/libwebsockets/lib/daemonize.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This code is mainly taken from Doug Potter's page * * http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize * * I contacted him 2007-04-16 about the license for the original code, * he replied it is Public Domain. Use the URL above to get the original * Public Domain version if you want it. * * This version is LGPL2.1+SLE like the rest of libwebsockets and is * Copyright (c)2006 - 2013 Andy Green <andy@warmcat.com> */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <limits.h> #include <unistd.h> #include <errno.h> #include "private-libwebsockets.h" int pid_daemon; static char *lock_path; int get_daemonize_pid() { return pid_daemon; } static void child_handler(int signum) { int fd, len, sent; char sz[20]; switch (signum) { case SIGALRM: /* timed out daemonizing */ exit(0); break; case SIGUSR1: /* positive confirmation we daemonized well */ /* Create the lock file as the current user */ fd = open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640); if (fd < 0) { fprintf(stderr, "unable to create lock file %s, code=%d (%s)\n", lock_path, errno, strerror(errno)); exit(5); } len = sprintf(sz, "%u", pid_daemon); sent = write(fd, sz, len); if (sent != len) fprintf(stderr, "unable to write pid to lock file %s, code=%d (%s)\n", lock_path, errno, strerror(errno)); close(fd); exit(0); //!!(sent == len)); case SIGCHLD: /* daemonization failed */ exit(6); break; } } static void lws_daemon_closing(int sigact) { if (getpid() == pid_daemon) if (lock_path) { unlink(lock_path); lws_free_set_NULL(lock_path); } kill(getpid(), SIGKILL); } /* * You just need to call this from your main(), when it * returns you are all set "in the background" decoupled * from the console you were started from. * * The process context you called from has been terminated then. */ LWS_VISIBLE int lws_daemonize(const char *_lock_path) { struct sigaction act; pid_t sid, parent; int n, fd, ret; char buf[10]; /* already a daemon */ // if (getppid() == 1) // return 1; fd = open(_lock_path, O_RDONLY); if (fd >= 0) { n = read(fd, buf, sizeof(buf)); close(fd); if (n) { n = atoi(buf); ret = kill(n, 0); if (ret >= 0) { fprintf(stderr, "Daemon already running from pid %d\n", n); exit(1); } fprintf(stderr, "Removing stale lock file %s from dead pid %d\n", _lock_path, n); unlink(lock_path); } } n = strlen(_lock_path) + 1; lock_path = lws_malloc(n); if (!lock_path) { fprintf(stderr, "Out of mem in lws_daemonize\n"); return 1; } strcpy(lock_path, _lock_path); /* Trap signals that we expect to receive */ signal(SIGCHLD, child_handler); /* died */ signal(SIGUSR1, child_handler); /* was happy */ signal(SIGALRM, child_handler); /* timeout daemonizing */ /* Fork off the parent process */ pid_daemon = fork(); if (pid_daemon < 0) { fprintf(stderr, "unable to fork daemon, code=%d (%s)", errno, strerror(errno)); exit(9); } /* If we got a good PID, then we can exit the parent process. */ if (pid_daemon > 0) { /* * Wait for confirmation signal from the child via * SIGCHILD / USR1, or for two seconds to elapse * (SIGALRM). pause() should not return. */ alarm(2); pause(); /* should not be reachable */ exit(1); } /* At this point we are executing as the child process */ parent = getppid(); pid_daemon = getpid(); /* Cancel certain signals */ signal(SIGCHLD, SIG_DFL); /* A child process dies */ signal(SIGTSTP, SIG_IGN); /* Various TTY signals */ signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */ /* Change the file mode mask */ umask(0); /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { fprintf(stderr, "unable to create a new session, code %d (%s)", errno, strerror(errno)); exit(2); } /* * Change the current working directory. This prevents the current * directory from being locked; hence not being able to remove it. */ if (chdir("/tmp") < 0) { fprintf(stderr, "unable to change directory to %s, code %d (%s)", "/", errno, strerror(errno)); exit(3); } /* Redirect standard files to /dev/null */ if (!freopen("/dev/null", "r", stdin)) fprintf(stderr, "unable to freopen() stdin, code %d (%s)", errno, strerror(errno)); if (!freopen("/dev/null", "w", stdout)) fprintf(stderr, "unable to freopen() stdout, code %d (%s)", errno, strerror(errno)); if (!freopen("/dev/null", "w", stderr)) fprintf(stderr, "unable to freopen() stderr, code %d (%s)", errno, strerror(errno)); /* Tell the parent process that we are A-okay */ kill(parent, SIGUSR1); act.sa_handler = lws_daemon_closing; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGTERM, &act, NULL); /* return to continue what is now "the daemon" */ return 0; } |
Added undroid/libwebsockets/lib/extension-permessage-deflate.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * ./lib/extension-permessage-deflate.c * * Copyright (C) 2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #include "extension-permessage-deflate.h" #include <stdio.h> #include <string.h> #include <assert.h> #define LWS_ZLIB_MEMLEVEL 8 const struct lws_ext_options lws_ext_pm_deflate_options[] = { /* public RFC7692 settings */ { "server_no_context_takeover", EXTARG_NONE }, { "client_no_context_takeover", EXTARG_NONE }, { "server_max_window_bits", EXTARG_OPT_DEC }, { "client_max_window_bits", EXTARG_OPT_DEC }, /* ones only user code can set */ { "rx_buf_size", EXTARG_DEC }, { "tx_buf_size", EXTARG_DEC }, { "compression_level", EXTARG_DEC }, { "mem_level", EXTARG_DEC }, { NULL, 0 }, /* sentinel */ }; static void lws_extension_pmdeflate_restrict_args(struct lws *wsi, struct lws_ext_pm_deflate_priv *priv) { int n, extra; /* cap the RX buf at the nearest power of 2 to protocol rx buf */ n = LWS_MAX_SOCKET_IO_BUF; if (wsi->protocol->rx_buffer_size) n = wsi->protocol->rx_buffer_size; extra = 7; while (n >= 1 << (extra + 1)) extra++; if (extra < priv->args[PMD_RX_BUF_PWR2]) { priv->args[PMD_RX_BUF_PWR2] = extra; lwsl_err(" Capping pmd rx to %d\n", 1 << extra); } } LWS_VISIBLE int lws_extension_callback_pm_deflate(struct lws_context *context, const struct lws_extension *ext, struct lws *wsi, enum lws_extension_callback_reasons reason, void *user, void *in, size_t len) { struct lws_ext_pm_deflate_priv *priv = (struct lws_ext_pm_deflate_priv *)user; struct lws_tokens *eff_buf = (struct lws_tokens *)in; static unsigned char trail[] = { 0, 0, 0xff, 0xff }; int n, ret = 0, was_fin = 0, extra; struct lws_ext_option_arg *oa; switch (reason) { case LWS_EXT_CB_NAMED_OPTION_SET: oa = in; if (!oa->option_name) break; for (n = 0; n < ARRAY_SIZE(lws_ext_pm_deflate_options); n++) if (!strcmp(lws_ext_pm_deflate_options[n].name, oa->option_name)) break; if (n == ARRAY_SIZE(lws_ext_pm_deflate_options)) break; oa->option_index = n; /* fallthru */ case LWS_EXT_CB_OPTION_SET: oa = in; lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__, oa->option_index, oa->start, oa->len); if (oa->start) priv->args[oa->option_index] = atoi(oa->start); else priv->args[oa->option_index] = 1; lws_extension_pmdeflate_restrict_args(wsi, priv); break; case LWS_EXT_CB_OPTION_CONFIRM: if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 || priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 || priv->args[PMD_CLIENT_MAX_WINDOW_BITS] < 8 || priv->args[PMD_CLIENT_MAX_WINDOW_BITS] > 15) return -1; break; case LWS_EXT_CB_CLIENT_CONSTRUCT: case LWS_EXT_CB_CONSTRUCT: n = LWS_MAX_SOCKET_IO_BUF; if (wsi->protocol->rx_buffer_size) n = wsi->protocol->rx_buffer_size; if (n < 128) { lwsl_err(" permessage-deflate requires the protocol (%s) to have an RX buffer >= 128\n", wsi->protocol->name); return -1; } /* fill in **user */ priv = lws_zalloc(sizeof(*priv)); *((void **)user) = priv; lwsl_ext("%s: LWS_EXT_CB_*CONSTRUCT\n", __func__); memset(priv, 0, sizeof(*priv)); /* fill in pointer to options list */ if (in) *((const struct lws_ext_options **)in) = lws_ext_pm_deflate_options; /* fallthru */ case LWS_EXT_CB_OPTION_DEFAULT: /* set the public, RFC7692 defaults... */ priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER] = 0, priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER] = 0; priv->args[PMD_SERVER_MAX_WINDOW_BITS] = 15; priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 15; /* ...and the ones the user code can override */ priv->args[PMD_RX_BUF_PWR2] = 10; /* ie, 1024 */ priv->args[PMD_TX_BUF_PWR2] = 10; /* ie, 1024 */ priv->args[PMD_COMP_LEVEL] = 1; priv->args[PMD_MEM_LEVEL] = 8; lws_extension_pmdeflate_restrict_args(wsi, priv); break; case LWS_EXT_CB_DESTROY: lwsl_ext("%s: LWS_EXT_CB_DESTROY\n", __func__); lws_free(priv->buf_rx_inflated); lws_free(priv->buf_tx_deflated); if (priv->rx_init) (void)inflateEnd(&priv->rx); if (priv->tx_init) (void)deflateEnd(&priv->tx); lws_free(priv); return ret; case LWS_EXT_CB_PAYLOAD_RX: lwsl_ext(" %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\n", __func__, eff_buf->token_len, priv->rx.avail_in); if (!(wsi->u.ws.rsv_first_msg & 0x40)) return 0; #if 0 for (n = 0; n < eff_buf->token_len; n++) { printf("%02X ", (unsigned char)eff_buf->token[n]); if ((n & 15) == 15) printf("\n"); } printf("\n"); #endif if (!priv->rx_init) if (inflateInit2(&priv->rx, -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) { lwsl_err("%s: iniflateInit failed\n", __func__); return -1; } priv->rx_init = 1; if (!priv->buf_rx_inflated) priv->buf_rx_inflated = lws_malloc(LWS_PRE + 7 + 5 + (1 << priv->args[PMD_RX_BUF_PWR2])); if (!priv->buf_rx_inflated) { lwsl_err("%s: OOM\n", __func__); return -1; } /* * We have to leave the input stream alone if we didn't * finish with it yet. The input stream is held in the wsi * rx buffer by the caller, so this assumption is safe while * we block new rx while draining the existing rx */ if (eff_buf->token && eff_buf->token_len) { priv->rx.next_in = (unsigned char *)eff_buf->token; priv->rx.avail_in = eff_buf->token_len; } priv->rx.next_out = priv->buf_rx_inflated + LWS_PRE; eff_buf->token = (char *)priv->rx.next_out; priv->rx.avail_out = 1 << priv->args[PMD_RX_BUF_PWR2]; if (priv->rx_held_valid) { lwsl_ext("-- RX piling on held byte --\n"); *(priv->rx.next_out++) = priv->rx_held; priv->rx.avail_out--; priv->rx_held_valid = 0; } /* if... * * - he has no remaining input content for this message, and * - and this is the final fragment, and * - we used everything that could be drained on the input side * * ...then put back the 00 00 FF FF the sender stripped as our * input to zlib */ if (!priv->rx.avail_in && wsi->u.ws.final && !wsi->u.ws.rx_packet_length) { lwsl_ext("RX APPEND_TRAILER-DO\n"); was_fin = 1; priv->rx.next_in = trail; priv->rx.avail_in = sizeof(trail); } n = inflate(&priv->rx, Z_NO_FLUSH); lwsl_ext("inflate ret %d, avi %d, avo %d, wsifinal %d\n", n, priv->rx.avail_in, priv->rx.avail_out, wsi->u.ws.final); switch (n) { case Z_NEED_DICT: case Z_STREAM_ERROR: case Z_DATA_ERROR: case Z_MEM_ERROR: lwsl_info("zlib error inflate %d: %s\n", n, priv->rx.msg); return -1; } /* * If we did not already send in the 00 00 FF FF, and he's * out of input, he did not EXACTLY fill the output buffer * (which is ambiguous and we will force it to go around * again by withholding a byte), and he's otherwise working on * being a FIN fragment, then do the FIN message processing * of faking up the 00 00 FF FF that the sender stripped. */ if (!priv->rx.avail_in && wsi->u.ws.final && !wsi->u.ws.rx_packet_length && !was_fin && priv->rx.avail_out /* ambiguous as to if it is the end */ ) { lwsl_ext("RX APPEND_TRAILER-DO\n"); was_fin = 1; priv->rx.next_in = trail; priv->rx.avail_in = sizeof(trail); n = inflate(&priv->rx, Z_SYNC_FLUSH); lwsl_ext("RX trailer inf returned %d, avi %d, avo %d\n", n, priv->rx.avail_in, priv->rx.avail_out); switch (n) { case Z_NEED_DICT: case Z_STREAM_ERROR: case Z_DATA_ERROR: case Z_MEM_ERROR: lwsl_info("zlib error inflate %d: %s\n", n, priv->rx.msg); return -1; } } /* * we must announce in our returncode now if there is more * output to be expected from inflate, so we can decide to * set the FIN bit on this bufferload or not. However zlib * is ambiguous when we exactly filled the inflate buffer. It * does not give us a clue as to whether we should understand * that to mean he ended on a buffer boundary, or if there is * more in the pipeline. * * So to work around that safely, if it used all output space * exactly, we ALWAYS say there is more coming and we withhold * the last byte of the buffer to guarantee that is true. * * That still leaves us at least one byte to finish with a FIN * on, even if actually nothing more is coming from the next * inflate action itself. */ if (!priv->rx.avail_out) { /* he used all available out buf */ lwsl_ext("-- rx grabbing held --\n"); /* snip the last byte and hold it for next time */ priv->rx_held = *(--priv->rx.next_out); priv->rx_held_valid = 1; } eff_buf->token_len = (char *)priv->rx.next_out - eff_buf->token; priv->count_rx_between_fin += eff_buf->token_len; lwsl_ext(" %s: RX leaving with new effbuff len %d, " "ret %d, rx.avail_in=%d, TOTAL RX since FIN %d\n", __func__, eff_buf->token_len, priv->rx_held_valid, priv->rx.avail_in, priv->count_rx_between_fin); if (was_fin) { priv->count_rx_between_fin = 0; if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) { (void)inflateEnd(&priv->rx); priv->rx_init = 0; } } #if 0 for (n = 0; n < eff_buf->token_len; n++) putchar(eff_buf->token[n]); puts("\n"); #endif return priv->rx_held_valid; case LWS_EXT_CB_PAYLOAD_TX: if (!priv->tx_init) if (deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL], Z_DEFLATED, -priv->args[PMD_CLIENT_MAX_WINDOW_BITS + !wsi->vhost->listen_port], priv->args[PMD_MEM_LEVEL], Z_DEFAULT_STRATEGY) != Z_OK) { lwsl_ext("inflateInit2 failed\n"); return 1; } priv->tx_init = 1; if (!priv->buf_tx_deflated) priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 + (1 << priv->args[PMD_TX_BUF_PWR2])); if (!priv->buf_tx_deflated) { lwsl_err("%s: OOM\n", __func__); return -1; } if (eff_buf->token) { lwsl_ext("%s: TX: eff_buf length %d\n", __func__, eff_buf->token_len); priv->tx.next_in = (unsigned char *)eff_buf->token; priv->tx.avail_in = eff_buf->token_len; } #if 0 for (n = 0; n < eff_buf->token_len; n++) { printf("%02X ", (unsigned char)eff_buf->token[n]); if ((n & 15) == 15) printf("\n"); } printf("\n"); #endif priv->tx.next_out = priv->buf_tx_deflated + LWS_PRE + 5; eff_buf->token = (char *)priv->tx.next_out; priv->tx.avail_out = 1 << priv->args[PMD_TX_BUF_PWR2]; n = deflate(&priv->tx, Z_SYNC_FLUSH); if (n == Z_STREAM_ERROR) { lwsl_ext("%s: Z_STREAM_ERROR\n", __func__); return -1; } if (priv->tx_held_valid) { priv->tx_held_valid = 0; if (priv->tx.avail_out == 1 << priv->args[PMD_TX_BUF_PWR2]) /* * we can get a situation he took something in * but did not generate anything out, at the end * of a message (eg, next thing he sends is 80 * 00, a zero length FIN, like Authobahn can * send). * If we have come back as a FIN, we must not * place the pending trailer 00 00 FF FF, just * the 1 byte of live data */ *(--eff_buf->token) = priv->tx_held[0]; else { /* he generated data, prepend whole pending */ eff_buf->token -= 5; for (n = 0; n < 5; n++) eff_buf->token[n] = priv->tx_held[n]; } } priv->compressed_out = 1; eff_buf->token_len = (int)(priv->tx.next_out - (unsigned char *)eff_buf->token); /* * we must announce in our returncode now if there is more * output to be expected from inflate, so we can decide to * set the FIN bit on this bufferload or not. However zlib * is ambiguous when we exactly filled the inflate buffer. It * does not give us a clue as to whether we should understand * that to mean he ended on a buffer boundary, or if there is * more in the pipeline. * * Worse, the guy providing the stuff we are sending may not * know until after that this was, actually, the last chunk, * that can happen even if we did not fill the output buf, ie * he may send after this a zero-length FIN fragment. * * This is super difficult because we must snip the last 4 * bytes in the case this is the last compressed output of the * message. The only way to deal with it is defer sending the * last 5 bytes of each frame until the next one, when we will * be in a position to understand if that has a FIN or not. */ extra = !!(len & LWS_WRITE_NO_FIN) || !priv->tx.avail_out; if (eff_buf->token_len >= 4 + extra) { lwsl_ext("tx held %d\n", 4 + extra); priv->tx_held_valid = extra; for (n = 3 + extra; n >= 0; n--) priv->tx_held[n] = *(--priv->tx.next_out); eff_buf->token_len -= 4 + extra; } lwsl_ext(" TX rewritten with new effbuff len %d, ret %d\n", eff_buf->token_len, !priv->tx.avail_out); return !priv->tx.avail_out; /* 1 == have more tx pending */ case LWS_EXT_CB_PACKET_TX_PRESEND: if (!priv->compressed_out) break; priv->compressed_out = 0; if ((*(eff_buf->token) & 0x80) && priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) { (void)deflateEnd(&priv->tx); priv->tx_init = 0; } n = *(eff_buf->token) & 15; /* set RSV1, but not on CONTINUATION */ if (n == LWSWSOPC_TEXT_FRAME || n == LWSWSOPC_BINARY_FRAME) *eff_buf->token |= 0x40; #if 0 for (n = 0; n < eff_buf->token_len; n++) { printf("%02X ", (unsigned char)eff_buf->token[n]); if ((n & 15) == 15) puts("\n"); } puts("\n"); #endif lwsl_ext("%s: tx opcode 0x%02X\n", __func__, (unsigned char)*eff_buf->token); break; default: break; } return 0; } |
Added undroid/libwebsockets/lib/extension-permessage-deflate.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include <zlib.h> #define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1 #define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION enum arg_indexes { PMD_SERVER_NO_CONTEXT_TAKEOVER, PMD_CLIENT_NO_CONTEXT_TAKEOVER, PMD_SERVER_MAX_WINDOW_BITS, PMD_CLIENT_MAX_WINDOW_BITS, PMD_RX_BUF_PWR2, PMD_TX_BUF_PWR2, PMD_COMP_LEVEL, PMD_MEM_LEVEL, PMD_ARG_COUNT }; struct lws_ext_pm_deflate_priv { z_stream rx; z_stream tx; unsigned char *buf_rx_inflated; /* RX inflated output buffer */ unsigned char *buf_tx_deflated; /* TX deflated output buffer */ size_t count_rx_between_fin; unsigned char args[PMD_ARG_COUNT]; unsigned char tx_held[5]; unsigned char rx_held; unsigned char tx_init:1; unsigned char rx_init:1; unsigned char compressed_out:1; unsigned char rx_held_valid:1; unsigned char tx_held_valid:1; unsigned char rx_append_trailer:1; unsigned char pending_tx_trailer:1; }; |
Added undroid/libwebsockets/lib/extension.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" #include "extension-permessage-deflate.h" LWS_VISIBLE void lws_context_init_extensions(struct lws_context_creation_info *info, struct lws_context *context) { lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE); } enum lws_ext_option_parser_states { LEAPS_SEEK_NAME, LEAPS_EAT_NAME, LEAPS_SEEK_VAL, LEAPS_EAT_DEC, LEAPS_SEEK_ARG_TERM }; LWS_VISIBLE int lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi, void *ext_user, const struct lws_ext_options *opts, const char *in, int len) { enum lws_ext_option_parser_states leap = LEAPS_SEEK_NAME; unsigned int match_map = 0, n, m, w = 0, count_options = 0, pending_close_quote = 0; struct lws_ext_option_arg oa; oa.option_name = NULL; while (opts[count_options].name) count_options++; while (len) { lwsl_ext("'%c' %d", *in, leap); switch (leap) { case LEAPS_SEEK_NAME: if (*in == ' ') break; if (*in == ',') { len = 1; break; } match_map = (1 << count_options) - 1; leap = LEAPS_EAT_NAME; w = 0; /* fallthru */ case LEAPS_EAT_NAME: oa.start = NULL; oa.len = 0; m = match_map; n = 0; pending_close_quote = 0; while (m) { if (m & 1) { lwsl_ext(" m=%d, n=%d, w=%d\n", m, n, w); if (*in == opts[n].name[w]) { if (!opts[n].name[w + 1]) { oa.option_index = n; lwsl_ext("hit %d\n", oa.option_index); leap = LEAPS_SEEK_VAL; if (len ==1) goto set_arg; break; } } else { match_map &= ~(1 << n); if (!match_map) { lwsl_ext("empty match map\n"); return -1; } } } m >>= 1; n++; } w++; break; case LEAPS_SEEK_VAL: if (*in == ' ') break; if (*in == ',') { len = 1; break; } if (*in == ';' || len == 1) { /* ie,nonoptional */ if (opts[oa.option_index].type == EXTARG_DEC) return -1; leap = LEAPS_SEEK_NAME; goto set_arg; } if (*in == '=') { w = 0; pending_close_quote = 0; if (opts[oa.option_index].type == EXTARG_NONE) return -1; leap = LEAPS_EAT_DEC; break; } return -1; case LEAPS_EAT_DEC: if (*in >= '0' && *in <= '9') { if (!w) oa.start = in; w++; if (len != 1) break; } if (!w && *in =='"') { pending_close_quote = 1; break; } if (!w) return -1; if (pending_close_quote && *in != '"' && len != 1) return -1; leap = LEAPS_SEEK_ARG_TERM; if (oa.start) oa.len = in - oa.start; if (len == 1) oa.len++; set_arg: ext->callback(lws_get_context(wsi), ext, wsi, LWS_EXT_CB_OPTION_SET, ext_user, (char *)&oa, 0); if (len == 1) break; if (pending_close_quote && *in == '"') break; /* fallthru */ case LEAPS_SEEK_ARG_TERM: if (*in == ' ') break; if (*in == ';') { leap = LEAPS_SEEK_NAME; break; } if (*in == ',') { len = 1; break; } return -1; } len--; in++; } return 0; } /* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */ int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len) { int n, m, handled = 0; for (n = 0; n < wsi->count_act_ext; n++) { m = wsi->active_extensions[n]->callback(lws_get_context(wsi), wsi->active_extensions[n], wsi, reason, wsi->act_ext_user[n], arg, len); if (m < 0) { lwsl_ext("Ext '%s' failed to handle callback %d!\n", wsi->active_extensions[n]->name, reason); return -1; } /* valgrind... */ if (reason == LWS_EXT_CB_DESTROY) wsi->act_ext_user[n] = NULL; if (m > handled) handled = m; } return handled; } int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi, int reason, void *arg, int len) { int n = 0, m, handled = 0; const struct lws_extension *ext; if (!wsi || !wsi->vhost) return 0; ext = wsi->vhost->extensions; while (ext && ext->callback && !handled) { m = ext->callback(context, ext, wsi, reason, (void *)(long)n, arg, len); if (m < 0) { lwsl_ext("Ext '%s' failed to handle callback %d!\n", wsi->active_extensions[n]->name, reason); return -1; } if (m) handled = 1; ext++; n++; } return 0; } int lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len) { struct lws_tokens eff_buf; int ret, m, n = 0; eff_buf.token = (char *)buf; eff_buf.token_len = len; /* * while we have original buf to spill ourselves, or extensions report * more in their pipeline */ ret = 1; while (ret == 1) { /* default to nobody has more to spill */ ret = 0; /* show every extension the new incoming data */ m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_PRESEND, &eff_buf, 0); if (m < 0) return -1; if (m) /* handled */ ret = 1; if ((char *)buf != eff_buf.token) /* * extension recreated it: * need to buffer this if not all sent */ wsi->u.ws.clean_buffer = 0; /* assuming they left us something to send, send it */ if (eff_buf.token_len) { n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token, eff_buf.token_len); if (n < 0) { lwsl_info("closing from ext access\n"); return -1; } /* always either sent it all or privately buffered */ if (wsi->u.ws.clean_buffer) len = n; } lwsl_parser("written %d bytes to client\n", n); /* no extension has more to spill? Then we can go */ if (!ret) break; /* we used up what we had */ eff_buf.token = NULL; eff_buf.token_len = 0; /* * Did that leave the pipe choked? * Or we had to hold on to some of it? */ if (!lws_send_pipe_choked(wsi) && !wsi->trunc_len) /* no we could add more, lets's do that */ continue; lwsl_debug("choked\n"); /* * Yes, he's choked. Don't spill the rest now get a callback * when he is ready to send and take care of it there */ lws_callback_on_writable(wsi); wsi->extension_data_pending = 1; ret = 0; } return len; } int lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r, void *v, size_t len) { struct lws_context *context = wsi->context; int n, handled = 0; /* maybe an extension will take care of it for us */ for (n = 0; n < wsi->count_act_ext && !handled; n++) { if (!wsi->active_extensions[n]->callback) continue; handled |= wsi->active_extensions[n]->callback(context, wsi->active_extensions[n], wsi, r, wsi->act_ext_user[n], v, len); } return handled; } /** * lws_set_extension_option(): set extension option if possible * * @wsi: websocket connection * @ext_name: name of ext, like "permessage-deflate" * @opt_name: name of option, like "rx_buf_size" * @opt_val: value to set option to */ int lws_set_extension_option(struct lws *wsi, const char *ext_name, const char *opt_name, const char *opt_val) { struct lws_ext_option_arg oa; int idx = 0; /* first identify if the ext is active on this wsi */ while (idx < wsi->count_act_ext && strcmp(wsi->active_extensions[idx]->name, ext_name)) idx++; if (idx == wsi->count_act_ext) return -1; /* request ext not active on this wsi */ oa.option_name = opt_name; oa.option_index = 0; oa.start = opt_val; oa.len = 0; return wsi->active_extensions[idx]->callback( wsi->context, wsi->active_extensions[idx], wsi, LWS_EXT_CB_NAMED_OPTION_SET, wsi->act_ext_user[idx], &oa, 0); } |
Added undroid/libwebsockets/lib/getifaddrs.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * downloaded from * http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c */ #if !LWS_HAVE_GETIFADDRS /* * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include "private-libwebsockets.h" #ifdef LWS_HAVE_SYS_SOCKIO_H #include <sys/sockio.h> #endif #ifdef LWS_HAVE_NETINET_IN6_VAR_H #include <netinet/in6_var.h> #endif #ifndef max #define max(a, b) ((a) > (b) ? (a) : (b)) #endif #include "getifaddrs.h" static int getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags, size_t ifreq_sz) { int ret; int fd; size_t buf_size; char *buf; struct ifconf ifconf; char *p; size_t sz; struct sockaddr sa_zero; struct ifreq *ifr; struct ifaddrs *start, **end = &start; buf = NULL; memset(&sa_zero, 0, sizeof(sa_zero)); fd = socket(af, SOCK_DGRAM, 0); if (fd < 0) return -1; buf_size = 8192; for (;;) { buf = lws_zalloc(buf_size); if (buf == NULL) { ret = ENOMEM; goto error_out; } ifconf.ifc_len = buf_size; ifconf.ifc_buf = buf; /* * Solaris returns EINVAL when the buffer is too small. */ if (ioctl(fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { ret = errno; goto error_out; } /* * Can the difference between a full and a overfull buf * be determined? */ if (ifconf.ifc_len < (int)buf_size) break; lws_free(buf); buf_size *= 2; } for (p = ifconf.ifc_buf; p < ifconf.ifc_buf + ifconf.ifc_len; p += sz) { struct ifreq ifreq; struct sockaddr *sa; size_t salen; ifr = (struct ifreq *)p; sa = &ifr->ifr_addr; sz = ifreq_sz; salen = sizeof(struct sockaddr); #ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN salen = sa->sa_len; sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); #endif #ifdef SA_LEN salen = SA_LEN(sa); sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); #endif memset(&ifreq, 0, sizeof(ifreq)); memcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); if (ioctl(fd, siocgifflags, &ifreq) < 0) { ret = errno; goto error_out; } *end = lws_malloc(sizeof(**end)); (*end)->ifa_next = NULL; (*end)->ifa_name = strdup(ifr->ifr_name); (*end)->ifa_flags = ifreq.ifr_flags; (*end)->ifa_addr = lws_malloc(salen); memcpy((*end)->ifa_addr, sa, salen); (*end)->ifa_netmask = NULL; #if 0 /* fix these when we actually need them */ if (ifreq.ifr_flags & IFF_BROADCAST) { (*end)->ifa_broadaddr = lws_malloc(sizeof(ifr->ifr_broadaddr)); memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, sizeof(ifr->ifr_broadaddr)); } else if (ifreq.ifr_flags & IFF_POINTOPOINT) { (*end)->ifa_dstaddr = lws_malloc(sizeof(ifr->ifr_dstaddr)); memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, sizeof(ifr->ifr_dstaddr)); } else (*end)->ifa_dstaddr = NULL; #else (*end)->ifa_dstaddr = NULL; #endif (*end)->ifa_data = NULL; end = &(*end)->ifa_next; } *ifap = start; close(fd); lws_free(buf); return 0; error_out: close(fd); lws_free(buf); errno = ret; return -1; } int getifaddrs(struct ifaddrs **ifap) { int ret = -1; errno = ENXIO; #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS) if (ret) ret = getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS, sizeof(struct in6_ifreq)); #endif #if defined(LWS_HAVE_IPV6) && defined(SIOCGIFCONF) if (ret) ret = getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); #endif #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS) if (ret) ret = getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); #endif return ret; } void freeifaddrs(struct ifaddrs *ifp) { struct ifaddrs *p, *q; for (p = ifp; p; ) { lws_free(p->ifa_name); lws_free(p->ifa_addr); lws_free(p->ifa_dstaddr); lws_free(p->ifa_netmask); lws_free(p->ifa_data); q = p; p = p->ifa_next; lws_free(q); } } #ifdef TEST void print_addr(const char *s, struct sockaddr *sa) { int i; printf(" %s=%d/", s, sa->sa_family); #ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN for (i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++) printf("%02x", ((unsigned char *)sa->sa_data)[i]); #else for (i = 0; i < sizeof(sa->sa_data); i++) printf("%02x", ((unsigned char *)sa->sa_data)[i]); #endif printf("\n"); } void print_ifaddrs(struct ifaddrs *x) { struct ifaddrs *p; for (p = x; p; p = p->ifa_next) { printf("%s\n", p->ifa_name); printf(" flags=%x\n", p->ifa_flags); if (p->ifa_addr) print_addr("addr", p->ifa_addr); if (p->ifa_dstaddr) print_addr("dstaddr", p->ifa_dstaddr); if (p->ifa_netmask) print_addr("netmask", p->ifa_netmask); printf(" %p\n", p->ifa_data); } } int main() { struct ifaddrs *a = NULL, *b; getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); print_ifaddrs(a); printf("---\n"); getifaddrs(&b); print_ifaddrs(b); return 0; } #endif #endif |
Added undroid/libwebsockets/lib/getifaddrs.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #if LWS_HAVE_GETIFADDRS #include <sys/types.h> #include <ifaddrs.h> #else #ifdef __cplusplus extern "C" { #endif /* * Copyright (c) 2000 Kungliga Tekniska H�gskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */ #ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791 #define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791 /* * the interface is defined in terms of the fields below, and this is * sometimes #define'd, so there seems to be no simple way of solving * this and this seemed the best. */ #undef ifa_dstaddr struct ifaddrs { struct ifaddrs *ifa_next; char *ifa_name; unsigned int ifa_flags; struct sockaddr *ifa_addr; struct sockaddr *ifa_netmask; struct sockaddr *ifa_dstaddr; void *ifa_data; }; #ifndef ifa_broadaddr #define ifa_broadaddr ifa_dstaddr #endif int getifaddrs(struct ifaddrs **); void freeifaddrs(struct ifaddrs *); #endif /* __ifaddrs_h__ */ #ifdef __cplusplus } #endif #endif |
Added undroid/libwebsockets/lib/handshake.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" /* * -04 of the protocol (actually the 80th version) has a radically different * handshake. The 04 spec gives the following idea * * The handshake from the client looks as follows: * * GET /chat HTTP/1.1 * Host: server.example.com * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== * Sec-WebSocket-Origin: http://example.com * Sec-WebSocket-Protocol: chat, superchat * Sec-WebSocket-Version: 4 * * The handshake from the server looks as follows: * * HTTP/1.1 101 Switching Protocols * Upgrade: websocket * Connection: Upgrade * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo= * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC== * Sec-WebSocket-Protocol: chat */ #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif /* * We have to take care about parsing because the headers may be split * into multiple fragments. They may contain unknown headers with arbitrary * argument lengths. So, we parse using a single-character at a time state * machine that is completely independent of packet size. * * Returns <0 for error or length of chars consumed from buf (up to len) */ LWS_VISIBLE int lws_read(struct lws *wsi, unsigned char *buf, size_t len) { unsigned char *last_char, *oldbuf = buf; int body_chunk_len; size_t n; lwsl_debug("%s: incoming len %d state %d\n", __func__, (int)len, wsi->state); switch (wsi->state) { #ifdef LWS_USE_HTTP2 case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS: case LWSS_HTTP2_ESTABLISHED: n = 0; while (n < len) { /* * we were accepting input but now we stopped doing so */ if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { lws_rxflow_cache(wsi, buf, n, len); return 1; } /* account for what we're using in rxflow buffer */ if (wsi->rxflow_buffer) wsi->rxflow_pos++; if (lws_http2_parser(wsi, buf[n++])) { lwsl_debug("%s: http2_parser bailed\n", __func__); goto bail; } } break; #endif case LWSS_CLIENT_HTTP_ESTABLISHED: break; case LWSS_HTTP: wsi->hdr_parsing_completed = 0; /* fallthru */ case LWSS_HTTP_ISSUING_FILE: wsi->state = LWSS_HTTP_HEADERS; wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; wsi->u.hdr.lextable_pos = 0; /* fallthru */ case LWSS_HTTP_HEADERS: if (!wsi->u.hdr.ah) { lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__); assert(0); } lwsl_parser("issuing %d bytes to parser\n", (int)len); if (lws_handshake_client(wsi, &buf, len)) goto bail; last_char = buf; if (lws_handshake_server(wsi, &buf, len)) /* Handshake indicates this session is done. */ goto bail; /* * It's possible that we've exhausted our data already, or * rx flow control has stopped us dealing with this early, * but lws_handshake_server doesn't update len for us. * Figure out how much was read, so that we can proceed * appropriately: */ len -= (buf - last_char); lwsl_debug("%s: thinks we have used %d\n", __func__, len); if (!wsi->hdr_parsing_completed) /* More header content on the way */ goto read_ok; switch (wsi->state) { case LWSS_HTTP: case LWSS_HTTP_HEADERS: goto read_ok; case LWSS_HTTP_ISSUING_FILE: goto read_ok; case LWSS_HTTP_BODY: wsi->u.http.content_remain = wsi->u.http.content_length; if (wsi->u.http.content_remain) goto http_postbody; /* there is no POST content */ goto postbody_completion; default: break; } break; case LWSS_HTTP_BODY: http_postbody: while (len && wsi->u.http.content_remain) { /* Copy as much as possible, up to the limit of: * what we have in the read buffer (len) * remaining portion of the POST body (content_remain) */ body_chunk_len = min(wsi->u.http.content_remain,len); wsi->u.http.content_remain -= body_chunk_len; len -= body_chunk_len; #ifdef LWS_WITH_CGI if (wsi->cgi) { struct lws_cgi_args args; args.ch = LWS_STDIN; args.stdwsi = &wsi->cgi->stdwsi[0]; args.data = buf; args.len = body_chunk_len; /* returns how much used */ n = user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_CGI_STDIN_DATA, wsi->user_space, (void *)&args, 0); if ((int)n < 0) goto bail; } else { #endif n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY, wsi->user_space, buf, body_chunk_len); if (n) goto bail; n = body_chunk_len; #ifdef LWS_WITH_CGI } #endif buf += n; if (wsi->u.http.content_remain) { lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, wsi->context->timeout_secs); break; } /* he sent all the content in time */ postbody_completion: lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); #ifdef LWS_WITH_CGI if (!wsi->cgi) #endif { n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BODY_COMPLETION, wsi->user_space, NULL, 0); if (n) goto bail; } break; } break; case LWSS_ESTABLISHED: case LWSS_AWAITING_CLOSE_ACK: case LWSS_SHUTDOWN: if (lws_handshake_client(wsi, &buf, len)) goto bail; switch (wsi->mode) { case LWSCM_WS_SERVING: if (lws_interpret_incoming_packet(wsi, &buf, len) < 0) { lwsl_info("interpret_incoming_packet has bailed\n"); goto bail; } break; } break; default: lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state); break; } read_ok: /* Nothing more to do for now */ lwsl_info("%s: read_ok, used %d\n", __func__, buf - oldbuf); return buf - oldbuf; bail: lwsl_debug("closing connection at lws_read bail:\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return -1; } |
Added undroid/libwebsockets/lib/header.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #include "lextable-strings.h" const unsigned char *lws_token_to_string(enum lws_token_indexes token) { if ((unsigned int)token >= ARRAY_SIZE(set)) return NULL; return (unsigned char *)set[token]; } int lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end) { #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return lws_add_http2_header_by_name(wsi, name, value, length, p, end); #else (void)wsi; #endif if (name) { while (*p < end && *name) *((*p)++) = *name++; if (*p == end) return 1; *((*p)++) = ' '; } if (*p + length + 3 >= end) return 1; memcpy(*p, value, length); *p += length; *((*p)++) = '\x0d'; *((*p)++) = '\x0a'; return 0; } int lws_finalize_http_header(struct lws *wsi, unsigned char **p, unsigned char *end) { #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return 0; #else (void)wsi; #endif if ((long)(end - *p) < 3) return 1; *((*p)++) = '\x0d'; *((*p)++) = '\x0a'; return 0; } int lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end) { const unsigned char *name; #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return lws_add_http2_header_by_token(wsi, token, value, length, p, end); #endif name = lws_token_to_string(token); if (!name) return 1; return lws_add_http_header_by_name(wsi, name, value, length, p, end); } int lws_add_http_header_content_length(struct lws *wsi, unsigned long content_length, unsigned char **p, unsigned char *end) { char b[24]; int n; n = sprintf(b, "%lu", content_length); if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)b, n, p, end)) return 1; wsi->u.http.content_length = content_length; wsi->u.http.content_remain = content_length; return 0; } static const char *err400[] = { "Bad Request", "Unauthorized", "Payment Required", "Forbidden", "Not Found", "Method Not Allowed", "Not Acceptable", "Proxy Auth Required", "Request Timeout", "Conflict", "Gone", "Length Required", "Precondition Failed", "Request Entity Too Large", "Request URI too Long", "Unsupported Media Type", "Requested Range Not Satisfiable", "Expectation Failed" }; static const char *err500[] = { "Internal Server Error", "Not Implemented", "Bad Gateway", "Service Unavailable", "Gateway Timeout", "HTTP Version Not Supported" }; int lws_add_http_header_status(struct lws *wsi, unsigned int code, unsigned char **p, unsigned char *end) { unsigned char code_and_desc[60]; const char *description = "", *p1; int n; static const char * const hver[] = { "HTTP/1.0", "HTTP/1.1", "HTTP/2" }; #ifdef LWS_WITH_ACCESS_LOG wsi->access_log.response = code; #endif #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) return lws_add_http2_header_status(wsi, code, p, end); #endif if (code >= 400 && code < (400 + ARRAY_SIZE(err400))) description = err400[code - 400]; if (code >= 500 && code < (500 + ARRAY_SIZE(err500))) description = err500[code - 500]; if (code == 200) description = "OK"; if (code == 304) description = "Not Modified"; else if (code >= 300 && code < 400) description = "Redirect"; if (wsi->u.http.request_version < ARRAY_SIZE(hver)) p1 = hver[wsi->u.http.request_version]; else p1 = hver[0]; n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description); if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *) wsi->context->server_string, wsi->context->server_string_len, p, end)) return 1; if (wsi->vhost->options & LWS_SERVER_OPTION_STS) if (lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *)"max-age=15768000 ; " "includeSubDomains", 36, p, end)) return 1; return 0; } /** * lws_return_http_status() - Return simple http status * @wsi: Websocket instance (available from user callback) * @code: Status index, eg, 404 * @html_body: User-readable HTML description < 1KB, or NULL * * Helper to report HTTP errors back to the client cleanly and * consistently */ LWS_VISIBLE int lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; unsigned char *p = pt->serv_buf + LWS_PRE; unsigned char *start = p, *body = p + 512; unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE; int n, m, len; char slen[20]; if (!html_body) html_body = ""; len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>", code, html_body); if (lws_add_http_header_status(wsi, code, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) return 1; n = sprintf(slen, "%d", len); if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)slen, n, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (m != (int)(p - start)) return 1; m = lws_write(wsi, body, len, LWS_WRITE_HTTP); return m != n; } LWS_VISIBLE int lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len, unsigned char **p, unsigned char *end) { unsigned char *start = *p; int n; if (lws_add_http_header_status(wsi, code, p, end)) return -1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_LOCATION, loc, len, p, end)) return -1; /* * if we're going with http/1.1 and keepalive, * we have to give fake content metadata so the * client knows we completed the transaction and * it can do the redirect... */ if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, p, end)) return -1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)"0", 1, p, end)) return -1; if (lws_finalize_http_header(wsi, p, end)) return -1; n = lws_write(wsi, start, *p - start, LWS_WRITE_HTTP_HEADERS); return n; } |
Added undroid/libwebsockets/lib/hpack.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * lib/hpack.c * * Copyright (C) 2014 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" /* * Official static header table for HPACK * +-------+-----------------------------+---------------+ | 1 | :authority | | | 2 | :method | GET | | 3 | :method | POST | | 4 | :path | / | | 5 | :path | /index.html | | 6 | :scheme | http | | 7 | :scheme | https | | 8 | :status | 200 | | 9 | :status | 204 | | 10 | :status | 206 | | 11 | :status | 304 | | 12 | :status | 400 | | 13 | :status | 404 | | 14 | :status | 500 | | 15 | accept-charset | | | 16 | accept-encoding | gzip, deflate | | 17 | accept-language | | | 18 | accept-ranges | | | 19 | accept | | | 20 | access-control-allow-origin | | | 21 | age | | | 22 | allow | | | 23 | authorization | | | 24 | cache-control | | | 25 | content-disposition | | | 26 | content-encoding | | | 27 | content-language | | | 28 | content-length | | | 29 | content-location | | | 30 | content-range | | | 31 | content-type | | | 32 | cookie | | | 33 | date | | | 34 | etag | | | 35 | expect | | | 36 | expires | | | 37 | from | | | 38 | host | | | 39 | if-match | | | 40 | if-modified-since | | | 41 | if-none-match | | | 42 | if-range | | | 43 | if-unmodified-since | | | 44 | last-modified | | | 45 | link | | | 46 | location | | | 47 | max-forwards | | | 48 | proxy-authenticate | | | 49 | proxy-authorization | | | 50 | range | | | 51 | referer | | | 52 | refresh | | | 53 | retry-after | | | 54 | server | | | 55 | set-cookie | | | 56 | strict-transport-security | | | 57 | transfer-encoding | | | 58 | user-agent | | | 59 | vary | | | 60 | via | | | 61 | www-authenticate | | +-------+-----------------------------+---------------+ */ static const unsigned char static_token[] = { 0, WSI_TOKEN_HTTP_COLON_AUTHORITY, WSI_TOKEN_HTTP_COLON_METHOD, WSI_TOKEN_HTTP_COLON_METHOD, WSI_TOKEN_HTTP_COLON_PATH, WSI_TOKEN_HTTP_COLON_PATH, WSI_TOKEN_HTTP_COLON_SCHEME, WSI_TOKEN_HTTP_COLON_SCHEME, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_COLON_STATUS, WSI_TOKEN_HTTP_ACCEPT_CHARSET, WSI_TOKEN_HTTP_ACCEPT_ENCODING, WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, WSI_TOKEN_HTTP_ACCEPT_RANGES, WSI_TOKEN_HTTP_ACCEPT, WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN, WSI_TOKEN_HTTP_AGE, WSI_TOKEN_HTTP_ALLOW, WSI_TOKEN_HTTP_AUTHORIZATION, WSI_TOKEN_HTTP_CACHE_CONTROL, WSI_TOKEN_HTTP_CONTENT_DISPOSITION, WSI_TOKEN_HTTP_CONTENT_ENCODING, WSI_TOKEN_HTTP_CONTENT_LANGUAGE, WSI_TOKEN_HTTP_CONTENT_LENGTH, WSI_TOKEN_HTTP_CONTENT_LOCATION, WSI_TOKEN_HTTP_CONTENT_RANGE, WSI_TOKEN_HTTP_CONTENT_TYPE, WSI_TOKEN_HTTP_COOKIE, WSI_TOKEN_HTTP_DATE, WSI_TOKEN_HTTP_ETAG, WSI_TOKEN_HTTP_EXPECT, WSI_TOKEN_HTTP_EXPIRES, WSI_TOKEN_HTTP_FROM, WSI_TOKEN_HOST, WSI_TOKEN_HTTP_IF_MATCH, WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, WSI_TOKEN_HTTP_IF_NONE_MATCH, WSI_TOKEN_HTTP_IF_RANGE, WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE, WSI_TOKEN_HTTP_LAST_MODIFIED, WSI_TOKEN_HTTP_LINK, WSI_TOKEN_HTTP_LOCATION, WSI_TOKEN_HTTP_MAX_FORWARDS, WSI_TOKEN_HTTP_PROXY_AUTHENTICATE, WSI_TOKEN_HTTP_PROXY_AUTHORIZATION, WSI_TOKEN_HTTP_RANGE, WSI_TOKEN_HTTP_REFERER, WSI_TOKEN_HTTP_REFRESH, WSI_TOKEN_HTTP_RETRY_AFTER, WSI_TOKEN_HTTP_SERVER, WSI_TOKEN_HTTP_SET_COOKIE, WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY, WSI_TOKEN_HTTP_TRANSFER_ENCODING, WSI_TOKEN_HTTP_USER_AGENT, WSI_TOKEN_HTTP_VARY, WSI_TOKEN_HTTP_VIA, WSI_TOKEN_HTTP_WWW_AUTHENTICATE, }; /* some of the entries imply values as well as header names */ static const char * const http2_canned[] = { "", "", "GET", "POST", "/", "/index.html", "http", "https", "200", "204", "206", "304", "400", "404", "500", "", "gzip, deflate" }; /* see minihuf.c */ #include "huftable.h" static int huftable_decode(int pos, char c) { int q = pos + !!c; if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */ return lextable[q] | 0x8000; return pos + (lextable[q] << 1); } static int lws_hpack_update_table_size(struct lws *wsi, int idx) { lwsl_info("hpack set table size %d\n", idx); return 0; } static int lws_frag_start(struct lws *wsi, int hdr_token_idx) { struct allocated_headers * ah = wsi->u.http2.http.ah; if (!hdr_token_idx) { lwsl_err("%s: zero hdr_token_idx\n", __func__); return 1; } if (ah->nfrag >= ARRAY_SIZE(ah->frag_index)) { lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag); return 1; } ah->frags[ah->nfrag].offset = ah->pos; ah->frags[ah->nfrag].len = 0; ah->frags[ah->nfrag].nfrag = 0; ah->frag_index[hdr_token_idx] = ah->nfrag; return 0; } static int lws_frag_append(struct lws *wsi, unsigned char c) { struct allocated_headers * ah = wsi->u.http2.http.ah; ah->data[ah->pos++] = c; ah->frags[ah->nfrag].len++; return ah->pos >= wsi->context->max_http_header_data; } static int lws_frag_end(struct lws *wsi) { if (lws_frag_append(wsi, 0)) return 1; wsi->u.http2.http.ah->nfrag++; return 0; } static void lws_dump_header(struct lws *wsi, int hdr) { char s[200]; int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr); s[len] = '\0'; lwsl_info(" hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s); } static int lws_token_from_index(struct lws *wsi, int index, char **arg, int *len) { struct hpack_dynamic_table *dyn; /* dynamic table only belongs to network wsi */ wsi = lws_http2_get_network_wsi(wsi); dyn = wsi->u.http2.hpack_dyn_table; if (index < ARRAY_SIZE(static_token)) return static_token[index]; if (!dyn) return 0; index -= ARRAY_SIZE(static_token); if (index >= dyn->num_entries) return 0; if (arg && len) { *arg = dyn->args + dyn->entries[index].arg_offset; *len = dyn->entries[index].arg_len; } return dyn->entries[index].token; } static int lws_hpack_add_dynamic_header(struct lws *wsi, int token, char *arg, int len) { struct hpack_dynamic_table *dyn; int ret = 1; wsi = lws_http2_get_network_wsi(wsi); dyn = wsi->u.http2.hpack_dyn_table; if (!dyn) { dyn = lws_zalloc(sizeof(*dyn)); if (!dyn) return 1; wsi->u.http2.hpack_dyn_table = dyn; dyn->args = lws_malloc(1024); if (!dyn->args) goto bail1; dyn->args_length = 1024; dyn->entries = lws_malloc(sizeof(dyn->entries[0]) * 20); if (!dyn->entries) goto bail2; dyn->num_entries = 20; } if (dyn->next == dyn->num_entries) return 1; if (dyn->args_length - dyn->pos < len) return 1; dyn->entries[dyn->next].token = token; dyn->entries[dyn->next].arg_offset = dyn->pos; if (len) memcpy(dyn->args + dyn->pos, arg, len); dyn->entries[dyn->next].arg_len = len; lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n", __func__, dyn->next, token, lws_token_to_string(token), len); dyn->pos += len; dyn->next++; return 0; bail2: lws_free(dyn->args); bail1: lws_free(dyn); wsi->u.http2.hpack_dyn_table = NULL; return ret; } static int lws_write_indexed_hdr(struct lws *wsi, int idx) { const char *p; int tok = lws_token_from_index(wsi, idx, NULL, 0); lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok, lws_token_to_string(tok)); if (lws_frag_start(wsi, tok)) return 1; if (idx < ARRAY_SIZE(http2_canned)) { p = http2_canned[idx]; while (*p) if (lws_frag_append(wsi, *p++)) return 1; } if (lws_frag_end(wsi)) return 1; lws_dump_header(wsi, tok); return 0; } int lws_hpack_interpret(struct lws *wsi, unsigned char c) { unsigned int prev; unsigned char c1; int n; lwsl_debug(" state %d\n", wsi->u.http2.hpack); switch (wsi->u.http2.hpack) { case HPKS_OPT_PADDING: wsi->u.http2.padding = c; lwsl_info("padding %d\n", c); if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) { wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY; wsi->u.http2.hpack_m = 4; } else wsi->u.http2.hpack = HPKS_TYPE; break; case HKPS_OPT_E_DEPENDENCY: wsi->u.http2.hpack_e_dep <<= 8; wsi->u.http2.hpack_e_dep |= c; if (! --wsi->u.http2.hpack_m) { lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep); wsi->u.http2.hpack = HKPS_OPT_WEIGHT; } break; case HKPS_OPT_WEIGHT: /* weight */ wsi->u.http2.hpack = HPKS_TYPE; break; case HPKS_TYPE: if (wsi->u.http2.count > (wsi->u.http2.length - wsi->u.http2.padding)) { lwsl_info("padding eat\n"); break; } if (c & 0x80) { /* indexed header field only */ /* just a possibly-extended integer */ wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7; lwsl_debug("HKPS_TYPE setting header_index %d\n", c & 0x7f); wsi->u.http2.header_index = c & 0x7f; if ((c & 0x7f) == 0x7f) { wsi->u.http2.hpack_len = c & 0x7f; wsi->u.http2.hpack_m = 0; wsi->u.http2.hpack = HPKS_IDX_EXT; break; } lwsl_debug("HKPS_TYPE: %d\n", c & 0x7f); if (lws_write_indexed_hdr(wsi, c & 0x7f)) return 1; /* stay at same state */ break; } if (c & 0x40) { /* literal header incr idx */ /* * [possibly-extended hdr idx (6) | new literal hdr name] * H + possibly-extended value length * literal value */ lwsl_debug("HKPS_TYPE 2 setting header_index %d\n", 0); wsi->u.http2.header_index = 0; if (c == 0x40) { /* literal name */ wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR; wsi->u.http2.value = 0; wsi->u.http2.hpack = HPKS_HLEN; break; } /* indexed name */ wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR; if ((c & 0x3f) == 0x3f) { wsi->u.http2.hpack_len = c & 0x3f; wsi->u.http2.hpack_m = 0; wsi->u.http2.hpack = HPKS_IDX_EXT; break; } lwsl_debug("HKPS_TYPE 3 setting header_index %d\n", c & 0x3f); wsi->u.http2.header_index = c & 0x3f; wsi->u.http2.value = 1; wsi->u.http2.hpack = HPKS_HLEN; break; } switch(c & 0xf0) { case 0x10: /* literal header never index */ case 0: /* literal header without indexing */ /* * follows 0x40 except 4-bit hdr idx * and don't add to index */ if (c == 0) { /* literal name */ wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE; wsi->u.http2.hpack = HPKS_HLEN; wsi->u.http2.value = 0; break; } //lwsl_debug("indexed\n"); /* indexed name */ wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE; wsi->u.http2.header_index = 0; if ((c & 0xf) == 0xf) { wsi->u.http2.hpack_len = c & 0xf; wsi->u.http2.hpack_m = 0; wsi->u.http2.hpack = HPKS_IDX_EXT; break; } //lwsl_err("HKPS_TYPE 5 setting header_index %d\n", c & 0xf); wsi->u.http2.header_index = c & 0xf; wsi->u.http2.value = 1; wsi->u.http2.hpack = HPKS_HLEN; break; case 0x20: case 0x30: /* header table size update */ /* possibly-extended size value (5) */ wsi->u.http2.hpack_type = HPKT_SIZE_5; if ((c & 0x1f) == 0x1f) { wsi->u.http2.hpack_len = c & 0x1f; wsi->u.http2.hpack_m = 0; wsi->u.http2.hpack = HPKS_IDX_EXT; break; } lws_hpack_update_table_size(wsi, c & 0x1f); /* stay at HPKS_TYPE state */ break; } break; case HPKS_IDX_EXT: wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m; wsi->u.http2.hpack_m += 7; if (!(c & 0x80)) { switch (wsi->u.http2.hpack_type) { case HPKT_INDEXED_HDR_7: //lwsl_err("HKPS_IDX_EXT hdr idx %d\n", wsi->u.http2.hpack_len); if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len)) return 1; wsi->u.http2.hpack = HPKS_TYPE; break; default: // lwsl_err("HKPS_IDX_EXT setting header_index %d\n", // wsi->u.http2.hpack_len); wsi->u.http2.header_index = wsi->u.http2.hpack_len; wsi->u.http2.value = 1; wsi->u.http2.hpack = HPKS_HLEN; break; } } break; case HPKS_HLEN: /* [ H | 7+ ] */ wsi->u.http2.huff = !!(c & 0x80); wsi->u.http2.hpack_pos = 0; wsi->u.http2.hpack_len = c & 0x7f; if (wsi->u.http2.hpack_len < 0x7f) { pre_data: if (wsi->u.http2.value) { if (wsi->u.http2.header_index) if (lws_frag_start(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index, NULL, NULL))) { // lwsl_notice("%s: hlen failed\n", __func__); return 1; } } else wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; wsi->u.http2.hpack = HPKS_DATA; break; } wsi->u.http2.hpack_m = 0; wsi->u.http2.hpack = HPKS_HLEN_EXT; break; case HPKS_HLEN_EXT: wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m; wsi->u.http2.hpack_m += 7; if (!(c & 0x80)) goto pre_data; break; case HPKS_DATA: for (n = 0; n < 8; n++) { if (wsi->u.http2.huff) { prev = wsi->u.http2.hpack_pos; wsi->u.http2.hpack_pos = huftable_decode( wsi->u.http2.hpack_pos, (c >> 7) & 1); c <<= 1; if (wsi->u.http2.hpack_pos == 0xffff) return 1; if (!(wsi->u.http2.hpack_pos & 0x8000)) continue; c1 = wsi->u.http2.hpack_pos & 0x7fff; wsi->u.http2.hpack_pos = 0; if (!c1 && prev == HUFTABLE_0x100_PREV) ; /* EOT */ } else { n = 8; c1 = c; } if (wsi->u.http2.value) { /* value */ if (wsi->u.http2.header_index) if (lws_frag_append(wsi, c1)) return 1; } else { /* name */ if (lws_parse(wsi, c1)) return 1; } } if (--wsi->u.http2.hpack_len == 0) { switch (wsi->u.http2.hpack_type) { case HPKT_LITERAL_HDR_VALUE_INCR: case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!! if (lws_hpack_add_dynamic_header(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index, NULL, NULL), NULL, 0)) return 1; break; default: break; } n = 8; if (wsi->u.http2.value) { if (lws_frag_end(wsi)) return 1; // lwsl_err("data\n"); lws_dump_header(wsi, lws_token_from_index( wsi, wsi->u.http2.header_index, NULL, NULL)); if (wsi->u.http2.count + wsi->u.http2.padding == wsi->u.http2.length) wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING; else wsi->u.http2.hpack = HPKS_TYPE; } else { /* name */ //if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT) wsi->u.http2.value = 1; wsi->u.http2.hpack = HPKS_HLEN; } } break; case HKPS_OPT_DISCARD_PADDING: lwsl_info("eating padding %x\n", c); if (! --wsi->u.http2.padding) wsi->u.http2.hpack = HPKS_TYPE; break; } return 0; } static int lws_http2_num(int starting_bits, unsigned long num, unsigned char **p, unsigned char *end) { int mask = (1 << starting_bits) - 1; if (num < mask) { *((*p)++) |= num; return *p >= end; } *((*p)++) |= mask; if (*p >= end) return 1; num -= mask; while (num >= 128) { *((*p)++) = 0x80 | (num & 0x7f); if (*p >= end) return 1; num >>= 7; } return 0; } int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end) { int len; lwsl_info("%s: %p %s:%s\n", __func__, *p, name, value); len = strlen((char *)name); if (len) if (name[len - 1] == ':') len--; if (end - *p < len + length + 8) return 1; *((*p)++) = 0; /* not indexed, literal name */ **p = 0; /* non-HUF */ if (lws_http2_num(7, len, p, end)) return 1; memcpy(*p, name, len); *p += len; *(*p) = 0; /* non-HUF */ if (lws_http2_num(7, length, p, end)) return 1; memcpy(*p, value, length); *p += length; return 0; } int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end) { const unsigned char *name; name = lws_token_to_string(token); if (!name) return 1; return lws_add_http2_header_by_name(wsi, name, value, length, p, end); } int lws_add_http2_header_status(struct lws *wsi, unsigned int code, unsigned char **p, unsigned char *end) { unsigned char status[10]; int n; wsi->u.http2.send_END_STREAM = !!(code >= 400); n = sprintf((char *)status, "%u", code); if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS, status, n, p, end)) return 1; return 0; } |
Added undroid/libwebsockets/lib/http2.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" const struct http2_settings lws_http2_default_settings = { { 0, /* LWS_HTTP2_SETTINGS__HEADER_TABLE_SIZE */ 4096, /* LWS_HTTP2_SETTINGS__ENABLE_PUSH */ 1, /* LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS */ 100, /* LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE */ 65535, /* LWS_HTTP2_SETTINGS__MAX_FRAME_SIZE */ 16384, /* LWS_HTTP2_SETTINGS__MAX_HEADER_LIST_SIZE */ ~0, }}; void lws_http2_init(struct http2_settings *settings) { memcpy(settings, lws_http2_default_settings.setting, sizeof(*settings)); } struct lws * lws_http2_wsi_from_id(struct lws *wsi, unsigned int sid) { do { if (wsi->u.http2.my_stream_id == sid) return wsi; wsi = wsi->u.http2.next_child_wsi; } while (wsi); return NULL; } struct lws * lws_create_server_child_wsi(struct lws_vhost *vhost, struct lws *parent_wsi, unsigned int sid) { struct lws *wsi = lws_create_new_server_wsi(vhost); if (!wsi) return NULL; /* no more children allowed by parent */ if (parent_wsi->u.http2.child_count + 1 == parent_wsi->u.http2.peer_settings.setting[ LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS]) goto bail; lws_http2_init(&wsi->u.http2.peer_settings); lws_http2_init(&wsi->u.http2.my_settings); wsi->u.http2.stream_id = sid; wsi->u.http2.my_stream_id = sid; wsi->u.http2.parent_wsi = parent_wsi; wsi->u.http2.next_child_wsi = parent_wsi->u.http2.next_child_wsi; parent_wsi->u.http2.next_child_wsi = wsi; parent_wsi->u.http2.child_count++; wsi->u.http2.my_priority = 16; wsi->u.http2.tx_credit = 65535; wsi->state = LWSS_HTTP2_ESTABLISHED; wsi->mode = parent_wsi->mode; wsi->protocol = &vhost->protocols[0]; if (lws_ensure_user_space(wsi)) goto bail; lwsl_info("%s: %p new child %p, sid %d, user_space=%p\n", __func__, parent_wsi, wsi, sid, wsi->user_space); return wsi; bail: vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0); lws_free(wsi); return NULL; } int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi) { struct lws **w = &wsi->u.http2.parent_wsi; do { if (*w == wsi) { *w = wsi->u.http2.next_child_wsi; (wsi->u.http2.parent_wsi)->u.http2.child_count--; return 0; } w = &((*w)->u.http2.next_child_wsi); } while (*w); lwsl_err("%s: can't find %p\n", __func__, wsi); return 1; } int lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len) { unsigned int a, b; if (!len) return 0; if (len < LWS_HTTP2_SETTINGS_LENGTH) return 1; while (len >= LWS_HTTP2_SETTINGS_LENGTH) { a = (buf[0] << 8) | buf[1]; if (a < LWS_HTTP2_SETTINGS__COUNT) { b = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5]; settings->setting[a] = b; lwsl_info("http2 settings %d <- 0x%x\n", a, b); } len -= LWS_HTTP2_SETTINGS_LENGTH; buf += LWS_HTTP2_SETTINGS_LENGTH; } if (len) return 1; return 0; } struct lws *lws_http2_get_network_wsi(struct lws *wsi) { while (wsi->u.http2.parent_wsi) wsi = wsi->u.http2.parent_wsi; return wsi; } int lws_http2_frame_write(struct lws *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf) { struct lws *wsi_eff = lws_http2_get_network_wsi(wsi); unsigned char *p = &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH]; int n; *p++ = len >> 16; *p++ = len >> 8; *p++ = len; *p++ = type; *p++ = flags; *p++ = sid >> 24; *p++ = sid >> 16; *p++ = sid >> 8; *p++ = sid; lwsl_info("%s: %p (eff %p). type %d, flags 0x%x, sid=%d, len=%d\n", __func__, wsi, wsi_eff, type, flags, sid, len, wsi->u.http2.tx_credit); if (type == LWS_HTTP2_FRAME_TYPE_DATA) { if (wsi->u.http2.tx_credit < len) lwsl_err("%s: %p: sending payload len %d" " but tx_credit only %d!\n", len, wsi->u.http2.tx_credit); wsi->u.http2.tx_credit -= len; } n = lws_issue_raw(wsi_eff, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH], len + LWS_HTTP2_FRAME_HEADER_LENGTH); if (n >= LWS_HTTP2_FRAME_HEADER_LENGTH) return n - LWS_HTTP2_FRAME_HEADER_LENGTH; return n; } static void lws_http2_settings_write(struct lws *wsi, int n, unsigned char *buf) { *buf++ = n >> 8; *buf++ = n; *buf++ = wsi->u.http2.my_settings.setting[n] >> 24; *buf++ = wsi->u.http2.my_settings.setting[n] >> 16; *buf++ = wsi->u.http2.my_settings.setting[n] >> 8; *buf = wsi->u.http2.my_settings.setting[n]; } static const char * https_client_preface = "PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d\x0a\x0d\x0a"; int lws_http2_parser(struct lws *wsi, unsigned char c) { struct lws *swsi; int n; switch (wsi->state) { case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: if (https_client_preface[wsi->u.http2.count++] != c) return 1; if (!https_client_preface[wsi->u.http2.count]) { lwsl_info("http2: %p: established\n", wsi); wsi->state = LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS; wsi->u.http2.count = 0; wsi->u.http2.tx_credit = 65535; /* * we must send a settings frame -- empty one is OK... * that must be the first thing sent by server * and the peer must send a SETTINGS with ACK flag... */ lws_set_protocol_write_pending(wsi, LWS_PPS_HTTP2_MY_SETTINGS); } break; case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS: case LWSS_HTTP2_ESTABLISHED: if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { // payload wsi->u.http2.count++; wsi->u.http2.stream_wsi->u.http2.count = wsi->u.http2.count; /* applies to wsi->u.http2.stream_wsi which may be wsi*/ switch(wsi->u.http2.type) { case LWS_HTTP2_FRAME_TYPE_SETTINGS: wsi->u.http2.stream_wsi->u.http2.one_setting[wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH] = c; if (wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH == LWS_HTTP2_SETTINGS_LENGTH - 1) if (lws_http2_interpret_settings_payload( &wsi->u.http2.stream_wsi->u.http2.peer_settings, wsi->u.http2.one_setting, LWS_HTTP2_SETTINGS_LENGTH)) return 1; break; case LWS_HTTP2_FRAME_TYPE_CONTINUATION: case LWS_HTTP2_FRAME_TYPE_HEADERS: lwsl_info(" %02X\n", c); if (!wsi->u.http2.stream_wsi->u.hdr.ah) if (lws_header_table_attach(wsi->u.http2.stream_wsi, 0)) { lwsl_err("%s: Failed to get ah\n", __func__); return 1; } if (lws_hpack_interpret(wsi->u.http2.stream_wsi, c)) { lwsl_notice("%s: lws_hpack_interpret failed\n", __func__); return 1; } break; case LWS_HTTP2_FRAME_TYPE_GOAWAY: if (wsi->u.http2.count >= 5 && wsi->u.http2.count <= 8) { wsi->u.http2.hpack_e_dep <<= 8; wsi->u.http2.hpack_e_dep |= c; if (wsi->u.http2.count == 8) { lwsl_info("goaway err 0x%x\n", wsi->u.http2.hpack_e_dep); } } wsi->u.http2.GOING_AWAY = 1; break; case LWS_HTTP2_FRAME_TYPE_DATA: break; case LWS_HTTP2_FRAME_TYPE_PRIORITY: break; case LWS_HTTP2_FRAME_TYPE_RST_STREAM: break; case LWS_HTTP2_FRAME_TYPE_PUSH_PROMISE: break; case LWS_HTTP2_FRAME_TYPE_PING: if (wsi->u.http2.flags & LWS_HTTP2_FLAG_SETTINGS_ACK) { // ack } else { /* they're sending us a ping request */ if (wsi->u.http2.count > 8) return 1; wsi->u.http2.ping_payload[wsi->u.http2.count - 1] = c; } break; case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE: wsi->u.http2.hpack_e_dep <<= 8; wsi->u.http2.hpack_e_dep |= c; break; } if (wsi->u.http2.count != wsi->u.http2.length) break; /* end of frame */ wsi->u.http2.frame_state = 0; wsi->u.http2.count = 0; swsi = wsi->u.http2.stream_wsi; /* set our initial window size */ if (!wsi->u.http2.initialized) { wsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE]; lwsl_info("initial tx credit on master conn %p: %d\n", wsi, wsi->u.http2.tx_credit); wsi->u.http2.initialized = 1; } switch (wsi->u.http2.type) { case LWS_HTTP2_FRAME_TYPE_HEADERS: /* service the http request itself */ lwsl_info("servicing initial http request, wsi=%p, stream wsi=%p\n", wsi, wsi->u.http2.stream_wsi); n = lws_http_action(swsi); (void)n; lwsl_info(" action result %d\n", n); break; case LWS_HTTP2_FRAME_TYPE_PING: if (wsi->u.http2.flags & LWS_HTTP2_FLAG_SETTINGS_ACK) { // ack } else { /* they're sending us a ping request */ lws_set_protocol_write_pending(wsi, LWS_PPS_HTTP2_PONG); } break; case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE: wsi->u.http2.hpack_e_dep &= ~(1 << 31); if ((long long)swsi->u.http2.tx_credit + (unsigned long long)wsi->u.http2.hpack_e_dep > (~(1 << 31))) return 1; /* actually need to close swsi not the whole show */ swsi->u.http2.tx_credit += wsi->u.http2.hpack_e_dep; if (swsi->u.http2.waiting_tx_credit && swsi->u.http2.tx_credit > 0) { lwsl_info("%s: %p: waiting_tx_credit -> wait on writeable\n", __func__, wsi); swsi->u.http2.waiting_tx_credit = 0; lws_callback_on_writable(swsi); } break; } break; } switch (wsi->u.http2.frame_state++) { case 0: wsi->u.http2.length = c; break; case 1: case 2: wsi->u.http2.length <<= 8; wsi->u.http2.length |= c; break; case 3: wsi->u.http2.type = c; break; case 4: wsi->u.http2.flags = c; break; case 5: case 6: case 7: case 8: wsi->u.http2.stream_id <<= 8; wsi->u.http2.stream_id |= c; break; } if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { /* frame header complete */ lwsl_info("frame: type 0x%x, flags 0x%x, sid 0x%x, len 0x%x\n", wsi->u.http2.type, wsi->u.http2.flags, wsi->u.http2.stream_id, wsi->u.http2.length); wsi->u.http2.count = 0; wsi->u.http2.stream_wsi = wsi; if (wsi->u.http2.stream_id) wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id); switch (wsi->u.http2.type) { case LWS_HTTP2_FRAME_TYPE_SETTINGS: /* nonzero sid on settings is illegal */ if (wsi->u.http2.stream_id) return 1; if (wsi->u.http2.flags & LWS_HTTP2_FLAG_SETTINGS_ACK) { // ack } else /* non-ACK coming in means we must ACK it */ lws_set_protocol_write_pending(wsi, LWS_PPS_HTTP2_ACK_SETTINGS); break; case LWS_HTTP2_FRAME_TYPE_PING: if (wsi->u.http2.stream_id) return 1; if (wsi->u.http2.length != 8) return 1; break; case LWS_HTTP2_FRAME_TYPE_CONTINUATION: if (wsi->u.http2.END_HEADERS) return 1; goto update_end_headers; case LWS_HTTP2_FRAME_TYPE_HEADERS: lwsl_info("LWS_HTTP2_FRAME_TYPE_HEADERS: stream_id = %d\n", wsi->u.http2.stream_id); if (!wsi->u.http2.stream_id) return 1; if (!wsi->u.http2.stream_wsi) { wsi->u.http2.stream_wsi = lws_create_server_child_wsi(wsi->vhost, wsi, wsi->u.http2.stream_id); wsi->u.http2.stream_wsi->http2_substream = 1; } /* END_STREAM means after servicing this, close the stream */ wsi->u.http2.END_STREAM = !!(wsi->u.http2.flags & LWS_HTTP2_FLAG_END_STREAM); lwsl_info("%s: headers END_STREAM = %d\n",__func__, wsi->u.http2.END_STREAM); update_end_headers: /* no END_HEADERS means CONTINUATION must come */ wsi->u.http2.END_HEADERS = !!(wsi->u.http2.flags & LWS_HTTP2_FLAG_END_HEADERS); swsi = wsi->u.http2.stream_wsi; if (!swsi) return 1; /* prepare the hpack parser at the right start */ swsi->u.http2.flags = wsi->u.http2.flags; swsi->u.http2.length = wsi->u.http2.length; swsi->u.http2.END_STREAM = wsi->u.http2.END_STREAM; if (swsi->u.http2.flags & LWS_HTTP2_FLAG_PADDED) swsi->u.http2.hpack = HPKS_OPT_PADDING; else if (swsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) { swsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY; swsi->u.http2.hpack_m = 4; } else swsi->u.http2.hpack = HPKS_TYPE; lwsl_info("initial hpack state %d\n", swsi->u.http2.hpack); break; case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE: if (wsi->u.http2.length != 4) return 1; break; } if (wsi->u.http2.length == 0) wsi->u.http2.frame_state = 0; } break; } return 0; } int lws_http2_do_pps_send(struct lws_context *context, struct lws *wsi) { unsigned char settings[LWS_PRE + 6 * LWS_HTTP2_SETTINGS__COUNT]; struct lws *swsi; int n, m = 0; lwsl_debug("%s: %p: %d\n", __func__, wsi, wsi->pps); switch (wsi->pps) { case LWS_PPS_HTTP2_MY_SETTINGS: for (n = 1; n < LWS_HTTP2_SETTINGS__COUNT; n++) if (wsi->u.http2.my_settings.setting[n] != lws_http2_default_settings.setting[n]) { lws_http2_settings_write(wsi, n, &settings[LWS_PRE + m]); m += sizeof(wsi->u.http2.one_setting); } n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_SETTINGS, 0, LWS_HTTP2_STREAM_ID_MASTER, m, &settings[LWS_PRE]); if (n != m) { lwsl_info("send %d %d\n", n, m); return 1; } break; case LWS_PPS_HTTP2_ACK_SETTINGS: /* send ack ... always empty */ n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_SETTINGS, 1, LWS_HTTP2_STREAM_ID_MASTER, 0, &settings[LWS_PRE]); if (n) { lwsl_err("ack tells %d\n", n); return 1; } /* this is the end of the preface dance then? */ if (wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS) { wsi->state = LWSS_HTTP2_ESTABLISHED; wsi->u.http.fd = LWS_INVALID_FILE; if (lws_is_ssl(lws_http2_get_network_wsi(wsi))) { lwsl_info("skipping nonexistant ssl upgrade headers\n"); break; } /* * we need to treat the headers from this upgrade * as the first job. These need to get * shifted to stream ID 1 */ lwsl_info("%s: setting up sid 1\n", __func__); swsi = wsi->u.http2.stream_wsi = lws_create_server_child_wsi(wsi->vhost, wsi, 1); /* pass on the initial headers to SID 1 */ swsi->u.http.ah = wsi->u.http.ah; wsi->u.http.ah = NULL; lwsl_info("%s: inherited headers %p\n", __func__, swsi->u.http.ah); swsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE]; lwsl_info("initial tx credit on conn %p: %d\n", swsi, swsi->u.http2.tx_credit); swsi->u.http2.initialized = 1; /* demanded by HTTP2 */ swsi->u.http2.END_STREAM = 1; lwsl_info("servicing initial http request\n"); return lws_http_action(swsi); } break; case LWS_PPS_HTTP2_PONG: memcpy(&settings[LWS_PRE], wsi->u.http2.ping_payload, 8); n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_PING, LWS_HTTP2_FLAG_SETTINGS_ACK, LWS_HTTP2_STREAM_ID_MASTER, 8, &settings[LWS_PRE]); if (n != 8) { lwsl_info("send %d %d\n", n, m); return 1; } break; default: break; } return 0; } struct lws * lws_http2_get_nth_child(struct lws *wsi, int n) { do { wsi = wsi->u.http2.next_child_wsi; if (!wsi) return NULL; } while (n--); return wsi; } |
Added undroid/libwebsockets/lib/huftable.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | static unsigned char lextable[] = { /* pos 0000: 0 */ /* 0 */ 0x42 /* (to 0x0084 state 98) */, /* 1 */ 0x01 /* (to 0x0002 state 1) */, /* pos 0002: 1 */ /* 0 */ 0x5C /* (to 0x00BA state 151) */, /* 1 */ 0x01 /* (to 0x0004 state 2) */, /* pos 0004: 2 */ /* 0 */ 0x66 /* (to 0x00D0 state 173) */, /* 1 */ 0x01 /* (to 0x0006 state 3) */, /* pos 0006: 3 */ /* 0 */ 0x74 /* (to 0x00EE state 204) */, /* 1 */ 0x01 /* (to 0x0008 state 4) */, /* pos 0008: 4 */ /* 0 */ 0x8C /* (to 0x0120 state 263) */, /* 1 */ 0x01 /* (to 0x000A state 5) */, /* pos 000a: 5 */ /* 0 */ 0x46 /* (to 0x0096 state 113) */, /* 1 */ 0x01 /* (to 0x000C state 6) */, /* pos 000c: 6 */ /* 0 */ 0x75 /* (to 0x00F6 state 211) */, /* 1 */ 0x01 /* (to 0x000E state 7) */, /* pos 000e: 7 */ /* 0 */ 0x40 /* (to 0x008E state 104) */, /* 1 */ 0x01 /* (to 0x0010 state 8) */, /* pos 0010: 8 */ /* 0 */ 0x45 /* (to 0x009A state 116) */, /* 1 */ 0x01 /* (to 0x0012 state 9) */, /* pos 0012: 9 */ /* 0 */ 0x40 /* (to 0x0092 state 108) */, /* 1 */ 0x01 /* (to 0x0014 state 10) */, /* pos 0014: 10 */ /* 0 */ 0x01 /* (to 0x0016 state 11) */, /* 1 */ 0x03 /* (to 0x001A state 14) */, /* pos 0016: 11 */ /* 0 */ 0x01 /* (to 0x0018 state 12) */, /* 1 */ 0x5B /* (to 0x00CC state 166) */, /* pos 0018: 12 */ /* terminal 0 */ 0x00, /* terminal 36 */ 0x24, /* pos 001a: 14 */ /* 0 */ 0x72 /* (to 0x00FE state 220) */, /* 1 */ 0x01 /* (to 0x001C state 15) */, /* pos 001c: 15 */ /* 0 */ 0x72 /* (to 0x0100 state 222) */, /* 1 */ 0x01 /* (to 0x001E state 16) */, /* pos 001e: 16 */ /* 0 */ 0x53 /* (to 0x00C4 state 158) */, /* 1 */ 0x01 /* (to 0x0020 state 17) */, /* pos 0020: 17 */ /* terminal 123 */ 0x7B, /* 1 */ 0x01 /* (to 0x0022 state 18) */, /* pos 0022: 18 */ /* 0 */ 0x6B /* (to 0x00F8 state 216) */, /* 1 */ 0x01 /* (to 0x0024 state 19) */, /* pos 0024: 19 */ /* 0 */ 0x84 /* (to 0x012C state 279) */, /* 1 */ 0x01 /* (to 0x0026 state 20) */, /* pos 0026: 20 */ /* 0 */ 0x01 /* (to 0x0028 state 21) */, /* 1 */ 0x06 /* (to 0x0032 state 27) */, /* pos 0028: 21 */ /* 0 */ 0xB3 /* (to 0x018E state 377) */, /* 1 */ 0x01 /* (to 0x002A state 22) */, /* pos 002a: 22 */ /* 0 */ 0xC3 /* (to 0x01B0 state 414) */, /* 1 */ 0x01 /* (to 0x002C state 23) */, /* pos 002c: 23 */ /* 0 */ 0x01 /* (to 0x002E state 24) */, /* 1 */ 0x8C /* (to 0x0144 state 301) */, /* pos 002e: 24 */ /* 0 */ 0x01 /* (to 0x0030 state 25) */, /* 1 */ 0x8A /* (to 0x0142 state 298) */, /* pos 0030: 25 */ /* terminal 1 */ 0x01, /* terminal 135 */ 0x87, /* pos 0032: 27 */ /* 0 */ 0x8E /* (to 0x014E state 314) */, /* 1 */ 0x01 /* (to 0x0034 state 28) */, /* pos 0034: 28 */ /* 0 */ 0x0F /* (to 0x0052 state 50) */, /* 1 */ 0x01 /* (to 0x0036 state 29) */, /* pos 0036: 29 */ /* 0 */ 0xA4 /* (to 0x017E state 362) */, /* 1 */ 0x01 /* (to 0x0038 state 30) */, /* pos 0038: 30 */ /* 0 */ 0xB7 /* (to 0x01A6 state 403) */, /* 1 */ 0x01 /* (to 0x003A state 31) */, /* pos 003a: 31 */ /* 0 */ 0xC8 /* (to 0x01CA state 440) */, /* 1 */ 0x01 /* (to 0x003C state 32) */, /* pos 003c: 32 */ /* 0 */ 0x01 /* (to 0x003E state 33) */, /* 1 */ 0x0F /* (to 0x005A state 55) */, /* pos 003e: 33 */ /* 0 */ 0x01 /* (to 0x0040 state 34) */, /* 1 */ 0x07 /* (to 0x004C state 46) */, /* pos 0040: 34 */ /* 0 */ 0x01 /* (to 0x0042 state 35) */, /* 1 */ 0x03 /* (to 0x0046 state 39) */, /* pos 0042: 35 */ /* terminal 254 */ 0xFE, /* 1 */ 0x01 /* (to 0x0044 state 36) */, /* pos 0044: 36 */ /* terminal 2 */ 0x02, /* terminal 3 */ 0x03, /* pos 0046: 39 */ /* 0 */ 0x01 /* (to 0x0048 state 40) */, /* 1 */ 0x02 /* (to 0x004A state 43) */, /* pos 0048: 40 */ /* terminal 4 */ 0x04, /* terminal 5 */ 0x05, /* pos 004a: 43 */ /* terminal 6 */ 0x06, /* terminal 7 */ 0x07, /* pos 004c: 46 */ /* 0 */ 0x01 /* (to 0x004E state 47) */, /* 1 */ 0x0E /* (to 0x0068 state 67) */, /* pos 004e: 47 */ /* 0 */ 0x01 /* (to 0x0050 state 48) */, /* 1 */ 0x0C /* (to 0x0066 state 63) */, /* pos 0050: 48 */ /* terminal 8 */ 0x08, /* terminal 11 */ 0x0B, /* pos 0052: 50 */ /* 0 */ 0xA7 /* (to 0x01A0 state 396) */, /* 1 */ 0x01 /* (to 0x0054 state 51) */, /* pos 0054: 51 */ /* 0 */ 0x01 /* (to 0x0056 state 52) */, /* 1 */ 0x7B /* (to 0x014A state 309) */, /* pos 0056: 52 */ /* terminal 239 */ 0xEF, /* 1 */ 0x01 /* (to 0x0058 state 53) */, /* pos 0058: 53 */ /* terminal 9 */ 0x09, /* terminal 142 */ 0x8E, /* pos 005a: 55 */ /* 0 */ 0x0A /* (to 0x006E state 74) */, /* 1 */ 0x01 /* (to 0x005C state 56) */, /* pos 005c: 56 */ /* 0 */ 0x11 /* (to 0x007E state 91) */, /* 1 */ 0x01 /* (to 0x005E state 57) */, /* pos 005e: 57 */ /* 0 */ 0x64 /* (to 0x0126 state 274) */, /* 1 */ 0x01 /* (to 0x0060 state 58) */, /* pos 0060: 58 */ /* terminal 249 */ 0xF9, /* 1 */ 0x01 /* (to 0x0062 state 59) */, /* pos 0062: 59 */ /* 0 */ 0x01 /* (to 0x0064 state 60) */, /* 1 */ 0x0A /* (to 0x0076 state 81) */, /* pos 0064: 60 */ /* terminal 10 */ 0x0A, /* terminal 13 */ 0x0D, /* pos 0066: 63 */ /* terminal 12 */ 0x0C, /* terminal 14 */ 0x0E, /* pos 0068: 67 */ /* 0 */ 0x01 /* (to 0x006A state 68) */, /* 1 */ 0x02 /* (to 0x006C state 71) */, /* pos 006a: 68 */ /* terminal 15 */ 0x0F, /* terminal 16 */ 0x10, /* pos 006c: 71 */ /* terminal 17 */ 0x11, /* terminal 18 */ 0x12, /* pos 006e: 74 */ /* 0 */ 0x01 /* (to 0x0070 state 75) */, /* 1 */ 0x05 /* (to 0x0078 state 84) */, /* pos 0070: 75 */ /* 0 */ 0x01 /* (to 0x0072 state 76) */, /* 1 */ 0x02 /* (to 0x0074 state 79) */, /* pos 0072: 76 */ /* terminal 19 */ 0x13, /* terminal 20 */ 0x14, /* pos 0074: 79 */ /* terminal 21 */ 0x15, /* terminal 23 */ 0x17, /* pos 0076: 81 */ /* terminal 22 */ 0x16, /* terminal 256 */ 0x00, /* pos 0078: 84 */ /* 0 */ 0x01 /* (to 0x007A state 85) */, /* 1 */ 0x02 /* (to 0x007C state 88) */, /* pos 007a: 85 */ /* terminal 24 */ 0x18, /* terminal 25 */ 0x19, /* pos 007c: 88 */ /* terminal 26 */ 0x1A, /* terminal 27 */ 0x1B, /* pos 007e: 91 */ /* 0 */ 0x01 /* (to 0x0080 state 92) */, /* 1 */ 0x02 /* (to 0x0082 state 95) */, /* pos 0080: 92 */ /* terminal 28 */ 0x1C, /* terminal 29 */ 0x1D, /* pos 0082: 95 */ /* terminal 30 */ 0x1E, /* terminal 31 */ 0x1F, /* pos 0084: 98 */ /* 0 */ 0x13 /* (to 0x00AA state 133) */, /* 1 */ 0x01 /* (to 0x0086 state 99) */, /* pos 0086: 99 */ /* 0 */ 0x01 /* (to 0x0088 state 100) */, /* 1 */ 0x0F /* (to 0x00A4 state 129) */, /* pos 0088: 100 */ /* 0 */ 0x4B /* (to 0x011E state 258) */, /* 1 */ 0x01 /* (to 0x008A state 101) */, /* pos 008a: 101 */ /* 0 */ 0x01 /* (to 0x008C state 102) */, /* 1 */ 0x0C /* (to 0x00A2 state 126) */, /* pos 008c: 102 */ /* terminal 32 */ 0x20, /* terminal 37 */ 0x25, /* pos 008e: 104 */ /* 0 */ 0x01 /* (to 0x0090 state 105) */, /* 1 */ 0x08 /* (to 0x009E state 119) */, /* pos 0090: 105 */ /* terminal 33 */ 0x21, /* terminal 34 */ 0x22, /* pos 0092: 108 */ /* terminal 124 */ 0x7C, /* 1 */ 0x01 /* (to 0x0094 state 109) */, /* pos 0094: 109 */ /* terminal 35 */ 0x23, /* terminal 62 */ 0x3E, /* pos 0096: 113 */ /* 0 */ 0x01 /* (to 0x0098 state 114) */, /* 1 */ 0x05 /* (to 0x00A0 state 124) */, /* pos 0098: 114 */ /* terminal 38 */ 0x26, /* terminal 42 */ 0x2A, /* pos 009a: 116 */ /* terminal 63 */ 0x3F, /* 1 */ 0x01 /* (to 0x009C state 117) */, /* pos 009c: 117 */ /* terminal 39 */ 0x27, /* terminal 43 */ 0x2B, /* pos 009e: 119 */ /* terminal 40 */ 0x28, /* terminal 41 */ 0x29, /* pos 00a0: 124 */ /* terminal 44 */ 0x2C, /* terminal 59 */ 0x3B, /* pos 00a2: 126 */ /* terminal 45 */ 0x2D, /* terminal 46 */ 0x2E, /* pos 00a4: 129 */ /* 0 */ 0x01 /* (to 0x00A6 state 130) */, /* 1 */ 0x08 /* (to 0x00B4 state 144) */, /* pos 00a6: 130 */ /* 0 */ 0x01 /* (to 0x00A8 state 131) */, /* 1 */ 0x06 /* (to 0x00B2 state 141) */, /* pos 00a8: 131 */ /* terminal 47 */ 0x2F, /* terminal 51 */ 0x33, /* pos 00aa: 133 */ /* 0 */ 0x01 /* (to 0x00AC state 134) */, /* 1 */ 0x2D /* (to 0x0104 state 229) */, /* pos 00ac: 134 */ /* 0 */ 0x01 /* (to 0x00AE state 135) */, /* 1 */ 0x02 /* (to 0x00B0 state 138) */, /* pos 00ae: 135 */ /* terminal 48 */ 0x30, /* terminal 49 */ 0x31, /* pos 00b0: 138 */ /* terminal 50 */ 0x32, /* terminal 97 */ 0x61, /* pos 00b2: 141 */ /* terminal 52 */ 0x34, /* terminal 53 */ 0x35, /* pos 00b4: 144 */ /* 0 */ 0x01 /* (to 0x00B6 state 145) */, /* 1 */ 0x02 /* (to 0x00B8 state 148) */, /* pos 00b6: 145 */ /* terminal 54 */ 0x36, /* terminal 55 */ 0x37, /* pos 00b8: 148 */ /* terminal 56 */ 0x38, /* terminal 57 */ 0x39, /* pos 00ba: 151 */ /* 0 */ 0x06 /* (to 0x00C6 state 160) */, /* 1 */ 0x01 /* (to 0x00BC state 152) */, /* pos 00bc: 152 */ /* 0 */ 0x2C /* (to 0x0114 state 246) */, /* 1 */ 0x01 /* (to 0x00BE state 153) */, /* pos 00be: 153 */ /* 0 */ 0x2F /* (to 0x011C state 256) */, /* 1 */ 0x01 /* (to 0x00C0 state 154) */, /* pos 00c0: 154 */ /* 0 */ 0x01 /* (to 0x00C2 state 155) */, /* 1 */ 0x07 /* (to 0x00CE state 170) */, /* pos 00c2: 155 */ /* terminal 58 */ 0x3A, /* terminal 66 */ 0x42, /* pos 00c4: 158 */ /* terminal 60 */ 0x3C, /* terminal 96 */ 0x60, /* pos 00c6: 160 */ /* 0 */ 0x01 /* (to 0x00C8 state 161) */, /* 1 */ 0x21 /* (to 0x0108 state 232) */, /* pos 00c8: 161 */ /* 0 */ 0x01 /* (to 0x00CA state 162) */, /* 1 */ 0x1D /* (to 0x0102 state 224) */, /* pos 00ca: 162 */ /* terminal 61 */ 0x3D, /* terminal 65 */ 0x41, /* pos 00cc: 166 */ /* terminal 64 */ 0x40, /* terminal 91 */ 0x5B, /* pos 00ce: 170 */ /* terminal 67 */ 0x43, /* terminal 68 */ 0x44, /* pos 00d0: 173 */ /* 0 */ 0x01 /* (to 0x00D2 state 174) */, /* 1 */ 0x08 /* (to 0x00E0 state 189) */, /* pos 00d2: 174 */ /* 0 */ 0x01 /* (to 0x00D4 state 175) */, /* 1 */ 0x04 /* (to 0x00DA state 182) */, /* pos 00d4: 175 */ /* 0 */ 0x01 /* (to 0x00D6 state 176) */, /* 1 */ 0x02 /* (to 0x00D8 state 179) */, /* pos 00d6: 176 */ /* terminal 69 */ 0x45, /* terminal 70 */ 0x46, /* pos 00d8: 179 */ /* terminal 71 */ 0x47, /* terminal 72 */ 0x48, /* pos 00da: 182 */ /* 0 */ 0x01 /* (to 0x00DC state 183) */, /* 1 */ 0x02 /* (to 0x00DE state 186) */, /* pos 00dc: 183 */ /* terminal 73 */ 0x49, /* terminal 74 */ 0x4A, /* pos 00de: 186 */ /* terminal 75 */ 0x4B, /* terminal 76 */ 0x4C, /* pos 00e0: 189 */ /* 0 */ 0x01 /* (to 0x00E2 state 190) */, /* 1 */ 0x04 /* (to 0x00E8 state 197) */, /* pos 00e2: 190 */ /* 0 */ 0x01 /* (to 0x00E4 state 191) */, /* 1 */ 0x02 /* (to 0x00E6 state 194) */, /* pos 00e4: 191 */ /* terminal 77 */ 0x4D, /* terminal 78 */ 0x4E, /* pos 00e6: 194 */ /* terminal 79 */ 0x4F, /* terminal 80 */ 0x50, /* pos 00e8: 197 */ /* 0 */ 0x01 /* (to 0x00EA state 198) */, /* 1 */ 0x02 /* (to 0x00EC state 201) */, /* pos 00ea: 198 */ /* terminal 81 */ 0x51, /* terminal 82 */ 0x52, /* pos 00ec: 201 */ /* terminal 83 */ 0x53, /* terminal 84 */ 0x54, /* pos 00ee: 204 */ /* 0 */ 0x01 /* (to 0x00F0 state 205) */, /* 1 */ 0x11 /* (to 0x0110 state 242) */, /* pos 00f0: 205 */ /* 0 */ 0x01 /* (to 0x00F2 state 206) */, /* 1 */ 0x02 /* (to 0x00F4 state 209) */, /* pos 00f2: 206 */ /* terminal 85 */ 0x55, /* terminal 86 */ 0x56, /* pos 00f4: 209 */ /* terminal 87 */ 0x57, /* terminal 89 */ 0x59, /* pos 00f6: 211 */ /* terminal 88 */ 0x58, /* terminal 90 */ 0x5A, /* pos 00f8: 216 */ /* 0 */ 0x01 /* (to 0x00FA state 217) */, /* 1 */ 0x1F /* (to 0x0136 state 286) */, /* pos 00fa: 217 */ /* 0 */ 0x01 /* (to 0x00FC state 218) */, /* 1 */ 0x17 /* (to 0x0128 state 276) */, /* pos 00fc: 218 */ /* terminal 92 */ 0x5C, /* terminal 195 */ 0xC3, /* pos 00fe: 220 */ /* terminal 93 */ 0x5D, /* terminal 126 */ 0x7E, /* pos 0100: 222 */ /* terminal 94 */ 0x5E, /* terminal 125 */ 0x7D, /* pos 0102: 224 */ /* terminal 95 */ 0x5F, /* terminal 98 */ 0x62, /* pos 0104: 229 */ /* 0 */ 0x01 /* (to 0x0106 state 230) */, /* 1 */ 0x05 /* (to 0x010E state 240) */, /* pos 0106: 230 */ /* terminal 99 */ 0x63, /* terminal 101 */ 0x65, /* pos 0108: 232 */ /* 0 */ 0x01 /* (to 0x010A state 233) */, /* 1 */ 0x02 /* (to 0x010C state 237) */, /* pos 010a: 233 */ /* terminal 100 */ 0x64, /* terminal 102 */ 0x66, /* pos 010c: 237 */ /* terminal 103 */ 0x67, /* terminal 104 */ 0x68, /* pos 010e: 240 */ /* terminal 105 */ 0x69, /* terminal 111 */ 0x6F, /* pos 0110: 242 */ /* 0 */ 0x01 /* (to 0x0112 state 243) */, /* 1 */ 0x05 /* (to 0x011A state 254) */, /* pos 0112: 243 */ /* terminal 106 */ 0x6A, /* terminal 107 */ 0x6B, /* pos 0114: 246 */ /* 0 */ 0x01 /* (to 0x0116 state 247) */, /* 1 */ 0x02 /* (to 0x0118 state 250) */, /* pos 0116: 247 */ /* terminal 108 */ 0x6C, /* terminal 109 */ 0x6D, /* pos 0118: 250 */ /* terminal 110 */ 0x6E, /* terminal 112 */ 0x70, /* pos 011a: 254 */ /* terminal 113 */ 0x71, /* terminal 118 */ 0x76, /* pos 011c: 256 */ /* terminal 114 */ 0x72, /* terminal 117 */ 0x75, /* pos 011e: 258 */ /* terminal 115 */ 0x73, /* terminal 116 */ 0x74, /* pos 0120: 263 */ /* 0 */ 0x01 /* (to 0x0122 state 264) */, /* 1 */ 0x02 /* (to 0x0124 state 267) */, /* pos 0122: 264 */ /* terminal 119 */ 0x77, /* terminal 120 */ 0x78, /* pos 0124: 267 */ /* terminal 121 */ 0x79, /* terminal 122 */ 0x7A, /* pos 0126: 274 */ /* terminal 127 */ 0x7F, /* terminal 220 */ 0xDC, /* pos 0128: 276 */ /* terminal 208 */ 0xD0, /* 1 */ 0x01 /* (to 0x012A state 277) */, /* pos 012a: 277 */ /* terminal 128 */ 0x80, /* terminal 130 */ 0x82, /* pos 012c: 279 */ /* 0 */ 0x2E /* (to 0x0188 state 372) */, /* 1 */ 0x01 /* (to 0x012E state 280) */, /* pos 012e: 280 */ /* 0 */ 0x01 /* (to 0x0130 state 281) */, /* 1 */ 0x1B /* (to 0x0164 state 332) */, /* pos 0130: 281 */ /* 0 */ 0x01 /* (to 0x0132 state 282) */, /* 1 */ 0x06 /* (to 0x013C state 291) */, /* pos 0132: 282 */ /* terminal 230 */ 0xE6, /* 1 */ 0x01 /* (to 0x0134 state 283) */, /* pos 0134: 283 */ /* terminal 129 */ 0x81, /* terminal 132 */ 0x84, /* pos 0136: 286 */ /* 0 */ 0x01 /* (to 0x0138 state 287) */, /* 1 */ 0x14 /* (to 0x015E state 328) */, /* pos 0138: 287 */ /* 0 */ 0x01 /* (to 0x013A state 288) */, /* 1 */ 0x30 /* (to 0x0198 state 388) */, /* pos 013a: 288 */ /* terminal 131 */ 0x83, /* terminal 162 */ 0xA2, /* pos 013c: 291 */ /* 0 */ 0x01 /* (to 0x013E state 292) */, /* 1 */ 0x02 /* (to 0x0140 state 296) */, /* pos 013e: 292 */ /* terminal 133 */ 0x85, /* terminal 134 */ 0x86, /* pos 0140: 296 */ /* terminal 136 */ 0x88, /* terminal 146 */ 0x92, /* pos 0142: 298 */ /* terminal 137 */ 0x89, /* terminal 138 */ 0x8A, /* pos 0144: 301 */ /* 0 */ 0x01 /* (to 0x0146 state 302) */, /* 1 */ 0x02 /* (to 0x0148 state 305) */, /* pos 0146: 302 */ /* terminal 139 */ 0x8B, /* terminal 140 */ 0x8C, /* pos 0148: 305 */ /* terminal 141 */ 0x8D, /* terminal 143 */ 0x8F, /* pos 014a: 309 */ /* 0 */ 0x01 /* (to 0x014C state 310) */, /* 1 */ 0x06 /* (to 0x0156 state 319) */, /* pos 014c: 310 */ /* terminal 144 */ 0x90, /* terminal 145 */ 0x91, /* pos 014e: 314 */ /* 0 */ 0x01 /* (to 0x0150 state 315) */, /* 1 */ 0x12 /* (to 0x0172 state 350) */, /* pos 0150: 315 */ /* 0 */ 0x01 /* (to 0x0152 state 316) */, /* 1 */ 0x05 /* (to 0x015A state 325) */, /* pos 0152: 316 */ /* 0 */ 0x01 /* (to 0x0154 state 317) */, /* 1 */ 0x03 /* (to 0x0158 state 322) */, /* pos 0154: 317 */ /* terminal 147 */ 0x93, /* terminal 149 */ 0x95, /* pos 0156: 319 */ /* terminal 148 */ 0x94, /* terminal 159 */ 0x9F, /* pos 0158: 322 */ /* terminal 150 */ 0x96, /* terminal 151 */ 0x97, /* pos 015a: 325 */ /* 0 */ 0x01 /* (to 0x015C state 326) */, /* 1 */ 0x08 /* (to 0x016A state 338) */, /* pos 015c: 326 */ /* terminal 152 */ 0x98, /* terminal 155 */ 0x9B, /* pos 015e: 328 */ /* 0 */ 0x42 /* (to 0x01E2 state 465) */, /* 1 */ 0x01 /* (to 0x0160 state 329) */, /* pos 0160: 329 */ /* 0 */ 0x01 /* (to 0x0162 state 330) */, /* 1 */ 0x0C /* (to 0x0178 state 355) */, /* pos 0162: 330 */ /* terminal 153 */ 0x99, /* terminal 161 */ 0xA1, /* pos 0164: 332 */ /* 0 */ 0x01 /* (to 0x0166 state 333) */, /* 1 */ 0x05 /* (to 0x016E state 347) */, /* pos 0166: 333 */ /* 0 */ 0x01 /* (to 0x0168 state 334) */, /* 1 */ 0x03 /* (to 0x016C state 342) */, /* pos 0168: 334 */ /* terminal 154 */ 0x9A, /* terminal 156 */ 0x9C, /* pos 016a: 338 */ /* terminal 157 */ 0x9D, /* terminal 158 */ 0x9E, /* pos 016c: 342 */ /* terminal 160 */ 0xA0, /* terminal 163 */ 0xA3, /* pos 016e: 347 */ /* 0 */ 0x01 /* (to 0x0170 state 348) */, /* 1 */ 0x07 /* (to 0x017C state 360) */, /* pos 0170: 348 */ /* terminal 164 */ 0xA4, /* terminal 169 */ 0xA9, /* pos 0172: 350 */ /* 0 */ 0x01 /* (to 0x0174 state 351) */, /* 1 */ 0x09 /* (to 0x0184 state 369) */, /* pos 0174: 351 */ /* 0 */ 0x01 /* (to 0x0176 state 352) */, /* 1 */ 0x03 /* (to 0x017A state 357) */, /* pos 0176: 352 */ /* terminal 165 */ 0xA5, /* terminal 166 */ 0xA6, /* pos 0178: 355 */ /* terminal 167 */ 0xA7, /* terminal 172 */ 0xAC, /* pos 017a: 357 */ /* terminal 168 */ 0xA8, /* terminal 174 */ 0xAE, /* pos 017c: 360 */ /* terminal 170 */ 0xAA, /* terminal 173 */ 0xAD, /* pos 017e: 362 */ /* 0 */ 0x01 /* (to 0x0180 state 363) */, /* 1 */ 0x1B /* (to 0x01B4 state 417) */, /* pos 0180: 363 */ /* 0 */ 0x01 /* (to 0x0182 state 364) */, /* 1 */ 0x2A /* (to 0x01D4 state 449) */, /* pos 0182: 364 */ /* terminal 171 */ 0xAB, /* terminal 206 */ 0xCE, /* pos 0184: 369 */ /* 0 */ 0x01 /* (to 0x0186 state 370) */, /* 1 */ 0x09 /* (to 0x0196 state 385) */, /* pos 0186: 370 */ /* terminal 175 */ 0xAF, /* terminal 180 */ 0xB4, /* pos 0188: 372 */ /* 0 */ 0x01 /* (to 0x018A state 373) */, /* 1 */ 0x27 /* (to 0x01D6 state 451) */, /* pos 018a: 373 */ /* 0 */ 0x01 /* (to 0x018C state 374) */, /* 1 */ 0x05 /* (to 0x0194 state 381) */, /* pos 018c: 374 */ /* terminal 176 */ 0xB0, /* terminal 177 */ 0xB1, /* pos 018e: 377 */ /* 0 */ 0x01 /* (to 0x0190 state 378) */, /* 1 */ 0x07 /* (to 0x019C state 393) */, /* pos 0190: 378 */ /* 0 */ 0x01 /* (to 0x0192 state 379) */, /* 1 */ 0x05 /* (to 0x019A state 390) */, /* pos 0192: 379 */ /* terminal 178 */ 0xB2, /* terminal 181 */ 0xB5, /* pos 0194: 381 */ /* terminal 179 */ 0xB3, /* terminal 209 */ 0xD1, /* pos 0196: 385 */ /* terminal 182 */ 0xB6, /* terminal 183 */ 0xB7, /* pos 0198: 388 */ /* terminal 184 */ 0xB8, /* terminal 194 */ 0xC2, /* pos 019a: 390 */ /* terminal 185 */ 0xB9, /* terminal 186 */ 0xBA, /* pos 019c: 393 */ /* 0 */ 0x01 /* (to 0x019E state 394) */, /* 1 */ 0x04 /* (to 0x01A4 state 400) */, /* pos 019e: 394 */ /* terminal 187 */ 0xBB, /* terminal 189 */ 0xBD, /* pos 01a0: 396 */ /* 0 */ 0x01 /* (to 0x01A2 state 397) */, /* 1 */ 0x07 /* (to 0x01AE state 412) */, /* pos 01a2: 397 */ /* terminal 188 */ 0xBC, /* terminal 191 */ 0xBF, /* pos 01a4: 400 */ /* terminal 190 */ 0xBE, /* terminal 196 */ 0xC4, /* pos 01a6: 403 */ /* 0 */ 0x01 /* (to 0x01A8 state 404) */, /* 1 */ 0x0D /* (to 0x01C0 state 427) */, /* pos 01a8: 404 */ /* 0 */ 0x01 /* (to 0x01AA state 405) */, /* 1 */ 0x0A /* (to 0x01BC state 424) */, /* pos 01aa: 405 */ /* 0 */ 0x01 /* (to 0x01AC state 406) */, /* 1 */ 0x08 /* (to 0x01BA state 421) */, /* pos 01ac: 406 */ /* terminal 192 */ 0xC0, /* terminal 193 */ 0xC1, /* pos 01ae: 412 */ /* terminal 197 */ 0xC5, /* terminal 231 */ 0xE7, /* pos 01b0: 414 */ /* 0 */ 0x01 /* (to 0x01B2 state 415) */, /* 1 */ 0x1B /* (to 0x01E6 state 475) */, /* pos 01b2: 415 */ /* terminal 198 */ 0xC6, /* terminal 228 */ 0xE4, /* pos 01b4: 417 */ /* 0 */ 0x1B /* (to 0x01EA state 481) */, /* 1 */ 0x01 /* (to 0x01B6 state 418) */, /* pos 01b6: 418 */ /* 0 */ 0x01 /* (to 0x01B8 state 419) */, /* 1 */ 0x19 /* (to 0x01E8 state 478) */, /* pos 01b8: 419 */ /* terminal 199 */ 0xC7, /* terminal 207 */ 0xCF, /* pos 01ba: 421 */ /* terminal 200 */ 0xC8, /* terminal 201 */ 0xC9, /* pos 01bc: 424 */ /* 0 */ 0x01 /* (to 0x01BE state 425) */, /* 1 */ 0x06 /* (to 0x01C8 state 438) */, /* pos 01be: 425 */ /* terminal 202 */ 0xCA, /* terminal 205 */ 0xCD, /* pos 01c0: 427 */ /* 0 */ 0x0D /* (to 0x01DA state 455) */, /* 1 */ 0x01 /* (to 0x01C2 state 428) */, /* pos 01c2: 428 */ /* 0 */ 0x17 /* (to 0x01F0 state 490) */, /* 1 */ 0x01 /* (to 0x01C4 state 429) */, /* pos 01c4: 429 */ /* terminal 255 */ 0xFF, /* 1 */ 0x01 /* (to 0x01C6 state 430) */, /* pos 01c6: 430 */ /* terminal 203 */ 0xCB, /* terminal 204 */ 0xCC, /* pos 01c8: 438 */ /* terminal 210 */ 0xD2, /* terminal 213 */ 0xD5, /* pos 01ca: 440 */ /* 0 */ 0x01 /* (to 0x01CC state 441) */, /* 1 */ 0x14 /* (to 0x01F2 state 494) */, /* pos 01cc: 441 */ /* 0 */ 0x01 /* (to 0x01CE state 442) */, /* 1 */ 0x09 /* (to 0x01DE state 461) */, /* pos 01ce: 442 */ /* 0 */ 0x01 /* (to 0x01D0 state 443) */, /* 1 */ 0x02 /* (to 0x01D2 state 447) */, /* pos 01d0: 443 */ /* terminal 211 */ 0xD3, /* terminal 212 */ 0xD4, /* pos 01d2: 447 */ /* terminal 214 */ 0xD6, /* terminal 221 */ 0xDD, /* pos 01d4: 449 */ /* terminal 215 */ 0xD7, /* terminal 225 */ 0xE1, /* pos 01d6: 451 */ /* 0 */ 0x01 /* (to 0x01D8 state 452) */, /* 1 */ 0x07 /* (to 0x01E4 state 469) */, /* pos 01d8: 452 */ /* terminal 216 */ 0xD8, /* terminal 217 */ 0xD9, /* pos 01da: 455 */ /* 0 */ 0x01 /* (to 0x01DC state 456) */, /* 1 */ 0x09 /* (to 0x01EC state 484) */, /* pos 01dc: 456 */ /* terminal 218 */ 0xDA, /* terminal 219 */ 0xDB, /* pos 01de: 461 */ /* 0 */ 0x01 /* (to 0x01E0 state 462) */, /* 1 */ 0x08 /* (to 0x01EE state 488) */, /* pos 01e0: 462 */ /* terminal 222 */ 0xDE, /* terminal 223 */ 0xDF, /* pos 01e2: 465 */ /* terminal 224 */ 0xE0, /* terminal 226 */ 0xE2, /* pos 01e4: 469 */ /* terminal 227 */ 0xE3, /* terminal 229 */ 0xE5, /* pos 01e6: 475 */ /* terminal 232 */ 0xE8, /* terminal 233 */ 0xE9, /* pos 01e8: 478 */ /* terminal 234 */ 0xEA, /* terminal 235 */ 0xEB, /* pos 01ea: 481 */ /* terminal 236 */ 0xEC, /* terminal 237 */ 0xED, /* pos 01ec: 484 */ /* terminal 238 */ 0xEE, /* terminal 240 */ 0xF0, /* pos 01ee: 488 */ /* terminal 241 */ 0xF1, /* terminal 244 */ 0xF4, /* pos 01f0: 490 */ /* terminal 242 */ 0xF2, /* terminal 243 */ 0xF3, /* pos 01f2: 494 */ /* 0 */ 0x01 /* (to 0x01F4 state 495) */, /* 1 */ 0x04 /* (to 0x01FA state 503) */, /* pos 01f4: 495 */ /* 0 */ 0x01 /* (to 0x01F6 state 496) */, /* 1 */ 0x02 /* (to 0x01F8 state 499) */, /* pos 01f6: 496 */ /* terminal 245 */ 0xF5, /* terminal 246 */ 0xF6, /* pos 01f8: 499 */ /* terminal 247 */ 0xF7, /* terminal 248 */ 0xF8, /* pos 01fa: 503 */ /* 0 */ 0x01 /* (to 0x01FC state 504) */, /* 1 */ 0x02 /* (to 0x01FE state 507) */, /* pos 01fc: 504 */ /* terminal 250 */ 0xFA, /* terminal 251 */ 0xFB, /* pos 01fe: 507 */ /* terminal 252 */ 0xFC, /* terminal 253 */ 0xFD, /* total size 512 bytes, biggest jump 200/256, fails=0 */ }; static unsigned char lextable_terms[] = { 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, 0x34, 0x0f, 0x43, 0x03, 0xf1, 0x3c, 0xfc, 0x3c, 0x0f, 0x30, 0x37, 0xf7, 0x0f, 0xc3, 0xcf, 0x03, 0x3c, 0xfc, 0xc0, 0xf3, 0xf0, 0x3c, 0xfc, 0xf0, 0xcf, 0xfc, 0xcc, 0xff, 0xfc, 0x0d, 0x34, 0xcc, 0xcf, 0x33, 0xf0, 0x33, 0x0c, 0x3f, 0xc3, 0x3f, 0xcc, 0x30, 0xfc, 0xcf, 0x3c, 0xf0, 0x0c, 0xcf, 0xd0, 0x03, 0x3f, 0x33, 0xff, 0xff, 0xc3, 0xf3, }; /* state that points to 0x100 for disambiguation with 0x0 */ #define HUFTABLE_0x100_PREV 118 |
Added undroid/libwebsockets/lib/lextable-strings.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* set of parsable strings -- ALL LOWER CASE */ static const char *set[] = { "get ", "post ", "options ", "host:", "connection:", "upgrade:", "origin:", "sec-websocket-draft:", "\x0d\x0a", "sec-websocket-extensions:", "sec-websocket-key1:", "sec-websocket-key2:", "sec-websocket-protocol:", "sec-websocket-accept:", "sec-websocket-nonce:", "http/1.1 ", "http2-settings:", "accept:", "access-control-request-headers:", "if-modified-since:", "if-none-match:", "accept-encoding:", "accept-language:", "pragma:", "cache-control:", "authorization:", "cookie:", "content-length:", "content-type:", "date:", "range:", "referer:", "sec-websocket-key:", "sec-websocket-version:", "sec-websocket-origin:", ":authority", ":method", ":path", ":scheme", ":status", "accept-charset:", "accept-ranges:", "access-control-allow-origin:", "age:", "allow:", "content-disposition:", "content-encoding:", "content-language:", "content-location:", "content-range:", "etag:", "expect:", "expires:", "from:", "if-match:", "if-range:", "if-unmodified-since:", "last-modified:", "link:", "location:", "max-forwards:", "proxy-authenticate:", "proxy-authorization:", "refresh:", "retry-after:", "server:", "set-cookie:", "strict-transport-security:", "transfer-encoding:", "user-agent:", "vary:", "via:", "www-authenticate:", "patch", "put", "delete", "uri-args", /* fake header used for uri-only storage */ "proxy ", "x-real-ip:", "http/1.0 ", "", /* not matchable */ }; |
Added undroid/libwebsockets/lib/lextable.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* pos 0000: 0 */ 0x67 /* 'g' */, 0x40, 0x00 /* (to 0x0040 state 1) */, 0x70 /* 'p' */, 0x42, 0x00 /* (to 0x0045 state 5) */, 0x6F /* 'o' */, 0x51, 0x00 /* (to 0x0057 state 10) */, 0x68 /* 'h' */, 0x5D, 0x00 /* (to 0x0066 state 18) */, 0x63 /* 'c' */, 0x66, 0x00 /* (to 0x0072 state 23) */, 0x75 /* 'u' */, 0x81, 0x00 /* (to 0x0090 state 34) */, 0x73 /* 's' */, 0x97, 0x00 /* (to 0x00A9 state 48) */, 0x0D /* '.' */, 0xD0, 0x00 /* (to 0x00E5 state 68) */, 0x61 /* 'a' */, 0x28, 0x01 /* (to 0x0140 state 129) */, 0x69 /* 'i' */, 0x67, 0x01 /* (to 0x0182 state 163) */, 0x64 /* 'd' */, 0x10, 0x02 /* (to 0x022E state 265) */, 0x72 /* 'r' */, 0x19, 0x02 /* (to 0x023A state 270) */, 0x3A /* ':' */, 0x4A, 0x02 /* (to 0x026E state 299) */, 0x65 /* 'e' */, 0xD6, 0x02 /* (to 0x02FD state 409) */, 0x66 /* 'f' */, 0xF2, 0x02 /* (to 0x031C state 425) */, 0x6C /* 'l' */, 0x14, 0x03 /* (to 0x0341 state 458) */, 0x6D /* 'm' */, 0x37, 0x03 /* (to 0x0367 state 484) */, 0x74 /* 't' */, 0xA6, 0x03 /* (to 0x03D9 state 578) */, 0x76 /* 'v' */, 0xC1, 0x03 /* (to 0x03F7 state 606) */, 0x77 /* 'w' */, 0xCE, 0x03 /* (to 0x0407 state 614) */, 0x78 /* 'x' */, 0xF5, 0x03 /* (to 0x0431 state 650) */, 0x08, /* fail */ /* pos 0040: 1 */ 0xE5 /* 'e' -> */, /* pos 0041: 2 */ 0xF4 /* 't' -> */, /* pos 0042: 3 */ 0xA0 /* ' ' -> */, /* pos 0043: 4 */ 0x00, 0x00 /* - terminal marker 0 - */, /* pos 0045: 5 */ 0x6F /* 'o' */, 0x0D, 0x00 /* (to 0x0052 state 6) */, 0x72 /* 'r' */, 0x8C, 0x01 /* (to 0x01D4 state 211) */, 0x61 /* 'a' */, 0xCE, 0x03 /* (to 0x0419 state 631) */, 0x75 /* 'u' */, 0xD0, 0x03 /* (to 0x041E state 635) */, 0x08, /* fail */ /* pos 0052: 6 */ 0xF3 /* 's' -> */, /* pos 0053: 7 */ 0xF4 /* 't' -> */, /* pos 0054: 8 */ 0xA0 /* ' ' -> */, /* pos 0055: 9 */ 0x00, 0x01 /* - terminal marker 1 - */, /* pos 0057: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x005E state 11) */, 0x72 /* 'r' */, 0x48, 0x00 /* (to 0x00A2 state 42) */, 0x08, /* fail */ /* pos 005e: 11 */ 0xF4 /* 't' -> */, /* pos 005f: 12 */ 0xE9 /* 'i' -> */, /* pos 0060: 13 */ 0xEF /* 'o' -> */, /* pos 0061: 14 */ 0xEE /* 'n' -> */, /* pos 0062: 15 */ 0xF3 /* 's' -> */, /* pos 0063: 16 */ 0xA0 /* ' ' -> */, /* pos 0064: 17 */ 0x00, 0x02 /* - terminal marker 2 - */, /* pos 0066: 18 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x006D state 19) */, 0x74 /* 't' */, 0xB6, 0x00 /* (to 0x011F state 110) */, 0x08, /* fail */ /* pos 006d: 19 */ 0xF3 /* 's' -> */, /* pos 006e: 20 */ 0xF4 /* 't' -> */, /* pos 006f: 21 */ 0xBA /* ':' -> */, /* pos 0070: 22 */ 0x00, 0x03 /* - terminal marker 3 - */, /* pos 0072: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0079 state 24) */, 0x61 /* 'a' */, 0x6C, 0x01 /* (to 0x01E1 state 217) */, 0x08, /* fail */ /* pos 0079: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0080 state 25) */, 0x6F /* 'o' */, 0x81, 0x01 /* (to 0x01FD state 243) */, 0x08, /* fail */ /* pos 0080: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0087 state 26) */, 0x74 /* 't' */, 0x80, 0x01 /* (to 0x0203 state 248) */, 0x08, /* fail */ /* pos 0087: 26 */ 0xE5 /* 'e' -> */, /* pos 0088: 27 */ 0xE3 /* 'c' -> */, /* pos 0089: 28 */ 0xF4 /* 't' -> */, /* pos 008a: 29 */ 0xE9 /* 'i' -> */, /* pos 008b: 30 */ 0xEF /* 'o' -> */, /* pos 008c: 31 */ 0xEE /* 'n' -> */, /* pos 008d: 32 */ 0xBA /* ':' -> */, /* pos 008e: 33 */ 0x00, 0x04 /* - terminal marker 4 - */, /* pos 0090: 34 */ 0x70 /* 'p' */, 0x0A, 0x00 /* (to 0x009A state 35) */, 0x73 /* 's' */, 0x59, 0x03 /* (to 0x03EC state 596) */, 0x72 /* 'r' */, 0x91, 0x03 /* (to 0x0427 state 642) */, 0x08, /* fail */ /* pos 009a: 35 */ 0xE7 /* 'g' -> */, /* pos 009b: 36 */ 0xF2 /* 'r' -> */, /* pos 009c: 37 */ 0xE1 /* 'a' -> */, /* pos 009d: 38 */ 0xE4 /* 'd' -> */, /* pos 009e: 39 */ 0xE5 /* 'e' -> */, /* pos 009f: 40 */ 0xBA /* ':' -> */, /* pos 00a0: 41 */ 0x00, 0x05 /* - terminal marker 5 - */, /* pos 00a2: 42 */ 0xE9 /* 'i' -> */, /* pos 00a3: 43 */ 0xE7 /* 'g' -> */, /* pos 00a4: 44 */ 0xE9 /* 'i' -> */, /* pos 00a5: 45 */ 0xEE /* 'n' -> */, /* pos 00a6: 46 */ 0xBA /* ':' -> */, /* pos 00a7: 47 */ 0x00, 0x06 /* - terminal marker 6 - */, /* pos 00a9: 48 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x00B0 state 49) */, 0x74 /* 't' */, 0x13, 0x03 /* (to 0x03BF state 553) */, 0x08, /* fail */ /* pos 00b0: 49 */ 0x63 /* 'c' */, 0x0A, 0x00 /* (to 0x00BA state 50) */, 0x72 /* 'r' */, 0xFC, 0x02 /* (to 0x03AF state 539) */, 0x74 /* 't' */, 0xFF, 0x02 /* (to 0x03B5 state 544) */, 0x08, /* fail */ /* pos 00ba: 50 */ 0xAD /* '-' -> */, /* pos 00bb: 51 */ 0xF7 /* 'w' -> */, /* pos 00bc: 52 */ 0xE5 /* 'e' -> */, /* pos 00bd: 53 */ 0xE2 /* 'b' -> */, /* pos 00be: 54 */ 0xF3 /* 's' -> */, /* pos 00bf: 55 */ 0xEF /* 'o' -> */, /* pos 00c0: 56 */ 0xE3 /* 'c' -> */, /* pos 00c1: 57 */ 0xEB /* 'k' -> */, /* pos 00c2: 58 */ 0xE5 /* 'e' -> */, /* pos 00c3: 59 */ 0xF4 /* 't' -> */, /* pos 00c4: 60 */ 0xAD /* '-' -> */, /* pos 00c5: 61 */ 0x64 /* 'd' */, 0x19, 0x00 /* (to 0x00DE state 62) */, 0x65 /* 'e' */, 0x20, 0x00 /* (to 0x00E8 state 70) */, 0x6B /* 'k' */, 0x29, 0x00 /* (to 0x00F4 state 81) */, 0x70 /* 'p' */, 0x38, 0x00 /* (to 0x0106 state 88) */, 0x61 /* 'a' */, 0x3F, 0x00 /* (to 0x0110 state 97) */, 0x6E /* 'n' */, 0x44, 0x00 /* (to 0x0118 state 104) */, 0x76 /* 'v' */, 0x86, 0x01 /* (to 0x025D state 284) */, 0x6F /* 'o' */, 0x8C, 0x01 /* (to 0x0266 state 292) */, 0x08, /* fail */ /* pos 00de: 62 */ 0xF2 /* 'r' -> */, /* pos 00df: 63 */ 0xE1 /* 'a' -> */, /* pos 00e0: 64 */ 0xE6 /* 'f' -> */, /* pos 00e1: 65 */ 0xF4 /* 't' -> */, /* pos 00e2: 66 */ 0xBA /* ':' -> */, /* pos 00e3: 67 */ 0x00, 0x07 /* - terminal marker 7 - */, /* pos 00e5: 68 */ 0x8A /* '.' -> */, /* pos 00e6: 69 */ 0x00, 0x08 /* - terminal marker 8 - */, /* pos 00e8: 70 */ 0xF8 /* 'x' -> */, /* pos 00e9: 71 */ 0xF4 /* 't' -> */, /* pos 00ea: 72 */ 0xE5 /* 'e' -> */, /* pos 00eb: 73 */ 0xEE /* 'n' -> */, /* pos 00ec: 74 */ 0xF3 /* 's' -> */, /* pos 00ed: 75 */ 0xE9 /* 'i' -> */, /* pos 00ee: 76 */ 0xEF /* 'o' -> */, /* pos 00ef: 77 */ 0xEE /* 'n' -> */, /* pos 00f0: 78 */ 0xF3 /* 's' -> */, /* pos 00f1: 79 */ 0xBA /* ':' -> */, /* pos 00f2: 80 */ 0x00, 0x09 /* - terminal marker 9 - */, /* pos 00f4: 81 */ 0xE5 /* 'e' -> */, /* pos 00f5: 82 */ 0xF9 /* 'y' -> */, /* pos 00f6: 83 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x0100 state 84) */, 0x32 /* '2' */, 0x0A, 0x00 /* (to 0x0103 state 86) */, 0x3A /* ':' */, 0x5F, 0x01 /* (to 0x025B state 283) */, 0x08, /* fail */ /* pos 0100: 84 */ 0xBA /* ':' -> */, /* pos 0101: 85 */ 0x00, 0x0A /* - terminal marker 10 - */, /* pos 0103: 86 */ 0xBA /* ':' -> */, /* pos 0104: 87 */ 0x00, 0x0B /* - terminal marker 11 - */, /* pos 0106: 88 */ 0xF2 /* 'r' -> */, /* pos 0107: 89 */ 0xEF /* 'o' -> */, /* pos 0108: 90 */ 0xF4 /* 't' -> */, /* pos 0109: 91 */ 0xEF /* 'o' -> */, /* pos 010a: 92 */ 0xE3 /* 'c' -> */, /* pos 010b: 93 */ 0xEF /* 'o' -> */, /* pos 010c: 94 */ 0xEC /* 'l' -> */, /* pos 010d: 95 */ 0xBA /* ':' -> */, /* pos 010e: 96 */ 0x00, 0x0C /* - terminal marker 12 - */, /* pos 0110: 97 */ 0xE3 /* 'c' -> */, /* pos 0111: 98 */ 0xE3 /* 'c' -> */, /* pos 0112: 99 */ 0xE5 /* 'e' -> */, /* pos 0113: 100 */ 0xF0 /* 'p' -> */, /* pos 0114: 101 */ 0xF4 /* 't' -> */, /* pos 0115: 102 */ 0xBA /* ':' -> */, /* pos 0116: 103 */ 0x00, 0x0D /* - terminal marker 13 - */, /* pos 0118: 104 */ 0xEF /* 'o' -> */, /* pos 0119: 105 */ 0xEE /* 'n' -> */, /* pos 011a: 106 */ 0xE3 /* 'c' -> */, /* pos 011b: 107 */ 0xE5 /* 'e' -> */, /* pos 011c: 108 */ 0xBA /* ':' -> */, /* pos 011d: 109 */ 0x00, 0x0E /* - terminal marker 14 - */, /* pos 011f: 110 */ 0xF4 /* 't' -> */, /* pos 0120: 111 */ 0xF0 /* 'p' -> */, /* pos 0121: 112 */ 0x2F /* '/' */, 0x07, 0x00 /* (to 0x0128 state 113) */, 0x32 /* '2' */, 0x10, 0x00 /* (to 0x0134 state 118) */, 0x08, /* fail */ /* pos 0128: 113 */ 0xB1 /* '1' -> */, /* pos 0129: 114 */ 0xAE /* '.' -> */, /* pos 012a: 115 */ 0x31 /* '1' */, 0x07, 0x00 /* (to 0x0131 state 116) */, 0x30 /* '0' */, 0x0F, 0x03 /* (to 0x043C state 660) */, 0x08, /* fail */ /* pos 0131: 116 */ 0xA0 /* ' ' -> */, /* pos 0132: 117 */ 0x00, 0x0F /* - terminal marker 15 - */, /* pos 0134: 118 */ 0xAD /* '-' -> */, /* pos 0135: 119 */ 0xF3 /* 's' -> */, /* pos 0136: 120 */ 0xE5 /* 'e' -> */, /* pos 0137: 121 */ 0xF4 /* 't' -> */, /* pos 0138: 122 */ 0xF4 /* 't' -> */, /* pos 0139: 123 */ 0xE9 /* 'i' -> */, /* pos 013a: 124 */ 0xEE /* 'n' -> */, /* pos 013b: 125 */ 0xE7 /* 'g' -> */, /* pos 013c: 126 */ 0xF3 /* 's' -> */, /* pos 013d: 127 */ 0xBA /* ':' -> */, /* pos 013e: 128 */ 0x00, 0x10 /* - terminal marker 16 - */, /* pos 0140: 129 */ 0x63 /* 'c' */, 0x0D, 0x00 /* (to 0x014D state 130) */, 0x75 /* 'u' */, 0xAC, 0x00 /* (to 0x01EF state 230) */, 0x67 /* 'g' */, 0x7D, 0x01 /* (to 0x02C3 state 358) */, 0x6C /* 'l' */, 0x7E, 0x01 /* (to 0x02C7 state 361) */, 0x08, /* fail */ /* pos 014d: 130 */ 0xE3 /* 'c' -> */, /* pos 014e: 131 */ 0xE5 /* 'e' -> */, /* pos 014f: 132 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0156 state 133) */, 0x73 /* 's' */, 0x0E, 0x00 /* (to 0x0160 state 136) */, 0x08, /* fail */ /* pos 0156: 133 */ 0xF4 /* 't' -> */, /* pos 0157: 134 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x015E state 135) */, 0x2D /* '-' */, 0x59, 0x00 /* (to 0x01B3 state 192) */, 0x08, /* fail */ /* pos 015e: 135 */ 0x00, 0x11 /* - terminal marker 17 - */, /* pos 0160: 136 */ 0xF3 /* 's' -> */, /* pos 0161: 137 */ 0xAD /* '-' -> */, /* pos 0162: 138 */ 0xE3 /* 'c' -> */, /* pos 0163: 139 */ 0xEF /* 'o' -> */, /* pos 0164: 140 */ 0xEE /* 'n' -> */, /* pos 0165: 141 */ 0xF4 /* 't' -> */, /* pos 0166: 142 */ 0xF2 /* 'r' -> */, /* pos 0167: 143 */ 0xEF /* 'o' -> */, /* pos 0168: 144 */ 0xEC /* 'l' -> */, /* pos 0169: 145 */ 0xAD /* '-' -> */, /* pos 016a: 146 */ 0x72 /* 'r' */, 0x07, 0x00 /* (to 0x0171 state 147) */, 0x61 /* 'a' */, 0x48, 0x01 /* (to 0x02B5 state 345) */, 0x08, /* fail */ /* pos 0171: 147 */ 0xE5 /* 'e' -> */, /* pos 0172: 148 */ 0xF1 /* 'q' -> */, /* pos 0173: 149 */ 0xF5 /* 'u' -> */, /* pos 0174: 150 */ 0xE5 /* 'e' -> */, /* pos 0175: 151 */ 0xF3 /* 's' -> */, /* pos 0176: 152 */ 0xF4 /* 't' -> */, /* pos 0177: 153 */ 0xAD /* '-' -> */, /* pos 0178: 154 */ 0xE8 /* 'h' -> */, /* pos 0179: 155 */ 0xE5 /* 'e' -> */, /* pos 017a: 156 */ 0xE1 /* 'a' -> */, /* pos 017b: 157 */ 0xE4 /* 'd' -> */, /* pos 017c: 158 */ 0xE5 /* 'e' -> */, /* pos 017d: 159 */ 0xF2 /* 'r' -> */, /* pos 017e: 160 */ 0xF3 /* 's' -> */, /* pos 017f: 161 */ 0xBA /* ':' -> */, /* pos 0180: 162 */ 0x00, 0x12 /* - terminal marker 18 - */, /* pos 0182: 163 */ 0xE6 /* 'f' -> */, /* pos 0183: 164 */ 0xAD /* '-' -> */, /* pos 0184: 165 */ 0x6D /* 'm' */, 0x0D, 0x00 /* (to 0x0191 state 166) */, 0x6E /* 'n' */, 0x20, 0x00 /* (to 0x01A7 state 181) */, 0x72 /* 'r' */, 0x9E, 0x01 /* (to 0x0328 state 435) */, 0x75 /* 'u' */, 0xA2, 0x01 /* (to 0x032F state 441) */, 0x08, /* fail */ /* pos 0191: 166 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0198 state 167) */, 0x61 /* 'a' */, 0x8E, 0x01 /* (to 0x0322 state 430) */, 0x08, /* fail */ /* pos 0198: 167 */ 0xE4 /* 'd' -> */, /* pos 0199: 168 */ 0xE9 /* 'i' -> */, /* pos 019a: 169 */ 0xE6 /* 'f' -> */, /* pos 019b: 170 */ 0xE9 /* 'i' -> */, /* pos 019c: 171 */ 0xE5 /* 'e' -> */, /* pos 019d: 172 */ 0xE4 /* 'd' -> */, /* pos 019e: 173 */ 0xAD /* '-' -> */, /* pos 019f: 174 */ 0xF3 /* 's' -> */, /* pos 01a0: 175 */ 0xE9 /* 'i' -> */, /* pos 01a1: 176 */ 0xEE /* 'n' -> */, /* pos 01a2: 177 */ 0xE3 /* 'c' -> */, /* pos 01a3: 178 */ 0xE5 /* 'e' -> */, /* pos 01a4: 179 */ 0xBA /* ':' -> */, /* pos 01a5: 180 */ 0x00, 0x13 /* - terminal marker 19 - */, /* pos 01a7: 181 */ 0xEF /* 'o' -> */, /* pos 01a8: 182 */ 0xEE /* 'n' -> */, /* pos 01a9: 183 */ 0xE5 /* 'e' -> */, /* pos 01aa: 184 */ 0xAD /* '-' -> */, /* pos 01ab: 185 */ 0xED /* 'm' -> */, /* pos 01ac: 186 */ 0xE1 /* 'a' -> */, /* pos 01ad: 187 */ 0xF4 /* 't' -> */, /* pos 01ae: 188 */ 0xE3 /* 'c' -> */, /* pos 01af: 189 */ 0xE8 /* 'h' -> */, /* pos 01b0: 190 */ 0xBA /* ':' -> */, /* pos 01b1: 191 */ 0x00, 0x14 /* - terminal marker 20 - */, /* pos 01b3: 192 */ 0x65 /* 'e' */, 0x0D, 0x00 /* (to 0x01C0 state 193) */, 0x6C /* 'l' */, 0x14, 0x00 /* (to 0x01CA state 202) */, 0x63 /* 'c' */, 0xEB, 0x00 /* (to 0x02A4 state 330) */, 0x72 /* 'r' */, 0xF1, 0x00 /* (to 0x02AD state 338) */, 0x08, /* fail */ /* pos 01c0: 193 */ 0xEE /* 'n' -> */, /* pos 01c1: 194 */ 0xE3 /* 'c' -> */, /* pos 01c2: 195 */ 0xEF /* 'o' -> */, /* pos 01c3: 196 */ 0xE4 /* 'd' -> */, /* pos 01c4: 197 */ 0xE9 /* 'i' -> */, /* pos 01c5: 198 */ 0xEE /* 'n' -> */, /* pos 01c6: 199 */ 0xE7 /* 'g' -> */, /* pos 01c7: 200 */ 0xBA /* ':' -> */, /* pos 01c8: 201 */ 0x00, 0x15 /* - terminal marker 21 - */, /* pos 01ca: 202 */ 0xE1 /* 'a' -> */, /* pos 01cb: 203 */ 0xEE /* 'n' -> */, /* pos 01cc: 204 */ 0xE7 /* 'g' -> */, /* pos 01cd: 205 */ 0xF5 /* 'u' -> */, /* pos 01ce: 206 */ 0xE1 /* 'a' -> */, /* pos 01cf: 207 */ 0xE7 /* 'g' -> */, /* pos 01d0: 208 */ 0xE5 /* 'e' -> */, /* pos 01d1: 209 */ 0xBA /* ':' -> */, /* pos 01d2: 210 */ 0x00, 0x16 /* - terminal marker 22 - */, /* pos 01d4: 211 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01DB state 212) */, 0x6F /* 'o' */, 0x9E, 0x01 /* (to 0x0375 state 497) */, 0x08, /* fail */ /* pos 01db: 212 */ 0xE7 /* 'g' -> */, /* pos 01dc: 213 */ 0xED /* 'm' -> */, /* pos 01dd: 214 */ 0xE1 /* 'a' -> */, /* pos 01de: 215 */ 0xBA /* ':' -> */, /* pos 01df: 216 */ 0x00, 0x17 /* - terminal marker 23 - */, /* pos 01e1: 217 */ 0xE3 /* 'c' -> */, /* pos 01e2: 218 */ 0xE8 /* 'h' -> */, /* pos 01e3: 219 */ 0xE5 /* 'e' -> */, /* pos 01e4: 220 */ 0xAD /* '-' -> */, /* pos 01e5: 221 */ 0xE3 /* 'c' -> */, /* pos 01e6: 222 */ 0xEF /* 'o' -> */, /* pos 01e7: 223 */ 0xEE /* 'n' -> */, /* pos 01e8: 224 */ 0xF4 /* 't' -> */, /* pos 01e9: 225 */ 0xF2 /* 'r' -> */, /* pos 01ea: 226 */ 0xEF /* 'o' -> */, /* pos 01eb: 227 */ 0xEC /* 'l' -> */, /* pos 01ec: 228 */ 0xBA /* ':' -> */, /* pos 01ed: 229 */ 0x00, 0x18 /* - terminal marker 24 - */, /* pos 01ef: 230 */ 0xF4 /* 't' -> */, /* pos 01f0: 231 */ 0xE8 /* 'h' -> */, /* pos 01f1: 232 */ 0xEF /* 'o' -> */, /* pos 01f2: 233 */ 0xF2 /* 'r' -> */, /* pos 01f3: 234 */ 0xE9 /* 'i' -> */, /* pos 01f4: 235 */ 0xFA /* 'z' -> */, /* pos 01f5: 236 */ 0xE1 /* 'a' -> */, /* pos 01f6: 237 */ 0xF4 /* 't' -> */, /* pos 01f7: 238 */ 0xE9 /* 'i' -> */, /* pos 01f8: 239 */ 0xEF /* 'o' -> */, /* pos 01f9: 240 */ 0xEE /* 'n' -> */, /* pos 01fa: 241 */ 0xBA /* ':' -> */, /* pos 01fb: 242 */ 0x00, 0x19 /* - terminal marker 25 - */, /* pos 01fd: 243 */ 0xEB /* 'k' -> */, /* pos 01fe: 244 */ 0xE9 /* 'i' -> */, /* pos 01ff: 245 */ 0xE5 /* 'e' -> */, /* pos 0200: 246 */ 0xBA /* ':' -> */, /* pos 0201: 247 */ 0x00, 0x1A /* - terminal marker 26 - */, /* pos 0203: 248 */ 0xE5 /* 'e' -> */, /* pos 0204: 249 */ 0xEE /* 'n' -> */, /* pos 0205: 250 */ 0xF4 /* 't' -> */, /* pos 0206: 251 */ 0xAD /* '-' -> */, /* pos 0207: 252 */ 0x6C /* 'l' */, 0x10, 0x00 /* (to 0x0217 state 253) */, 0x74 /* 't' */, 0x1E, 0x00 /* (to 0x0228 state 260) */, 0x64 /* 'd' */, 0xC0, 0x00 /* (to 0x02CD state 366) */, 0x65 /* 'e' */, 0xCA, 0x00 /* (to 0x02DA state 378) */, 0x72 /* 'r' */, 0xE3, 0x00 /* (to 0x02F6 state 403) */, 0x08, /* fail */ /* pos 0217: 253 */ 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x0221 state 254) */, 0x61 /* 'a' */, 0xCA, 0x00 /* (to 0x02E4 state 387) */, 0x6F /* 'o' */, 0xD0, 0x00 /* (to 0x02ED state 395) */, 0x08, /* fail */ /* pos 0221: 254 */ 0xEE /* 'n' -> */, /* pos 0222: 255 */ 0xE7 /* 'g' -> */, /* pos 0223: 256 */ 0xF4 /* 't' -> */, /* pos 0224: 257 */ 0xE8 /* 'h' -> */, /* pos 0225: 258 */ 0xBA /* ':' -> */, /* pos 0226: 259 */ 0x00, 0x1B /* - terminal marker 27 - */, /* pos 0228: 260 */ 0xF9 /* 'y' -> */, /* pos 0229: 261 */ 0xF0 /* 'p' -> */, /* pos 022a: 262 */ 0xE5 /* 'e' -> */, /* pos 022b: 263 */ 0xBA /* ':' -> */, /* pos 022c: 264 */ 0x00, 0x1C /* - terminal marker 28 - */, /* pos 022e: 265 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0235 state 266) */, 0x65 /* 'e' */, 0xF0, 0x01 /* (to 0x0421 state 637) */, 0x08, /* fail */ /* pos 0235: 266 */ 0xF4 /* 't' -> */, /* pos 0236: 267 */ 0xE5 /* 'e' -> */, /* pos 0237: 268 */ 0xBA /* ':' -> */, /* pos 0238: 269 */ 0x00, 0x1D /* - terminal marker 29 - */, /* pos 023a: 270 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0241 state 271) */, 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x0247 state 276) */, 0x08, /* fail */ /* pos 0241: 271 */ 0xEE /* 'n' -> */, /* pos 0242: 272 */ 0xE7 /* 'g' -> */, /* pos 0243: 273 */ 0xE5 /* 'e' -> */, /* pos 0244: 274 */ 0xBA /* ':' -> */, /* pos 0245: 275 */ 0x00, 0x1E /* - terminal marker 30 - */, /* pos 0247: 276 */ 0x66 /* 'f' */, 0x07, 0x00 /* (to 0x024E state 277) */, 0x74 /* 't' */, 0x5A, 0x01 /* (to 0x03A4 state 529) */, 0x08, /* fail */ /* pos 024e: 277 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0255 state 278) */, 0x72 /* 'r' */, 0x4D, 0x01 /* (to 0x039E state 524) */, 0x08, /* fail */ /* pos 0255: 278 */ 0xF2 /* 'r' -> */, /* pos 0256: 279 */ 0xE5 /* 'e' -> */, /* pos 0257: 280 */ 0xF2 /* 'r' -> */, /* pos 0258: 281 */ 0xBA /* ':' -> */, /* pos 0259: 282 */ 0x00, 0x1F /* - terminal marker 31 - */, /* pos 025b: 283 */ 0x00, 0x20 /* - terminal marker 32 - */, /* pos 025d: 284 */ 0xE5 /* 'e' -> */, /* pos 025e: 285 */ 0xF2 /* 'r' -> */, /* pos 025f: 286 */ 0xF3 /* 's' -> */, /* pos 0260: 287 */ 0xE9 /* 'i' -> */, /* pos 0261: 288 */ 0xEF /* 'o' -> */, /* pos 0262: 289 */ 0xEE /* 'n' -> */, /* pos 0263: 290 */ 0xBA /* ':' -> */, /* pos 0264: 291 */ 0x00, 0x21 /* - terminal marker 33 - */, /* pos 0266: 292 */ 0xF2 /* 'r' -> */, /* pos 0267: 293 */ 0xE9 /* 'i' -> */, /* pos 0268: 294 */ 0xE7 /* 'g' -> */, /* pos 0269: 295 */ 0xE9 /* 'i' -> */, /* pos 026a: 296 */ 0xEE /* 'n' -> */, /* pos 026b: 297 */ 0xBA /* ':' -> */, /* pos 026c: 298 */ 0x00, 0x22 /* - terminal marker 34 - */, /* pos 026e: 299 */ 0x61 /* 'a' */, 0x0D, 0x00 /* (to 0x027B state 300) */, 0x6D /* 'm' */, 0x14, 0x00 /* (to 0x0285 state 309) */, 0x70 /* 'p' */, 0x18, 0x00 /* (to 0x028C state 315) */, 0x73 /* 's' */, 0x1A, 0x00 /* (to 0x0291 state 319) */, 0x08, /* fail */ /* pos 027b: 300 */ 0xF5 /* 'u' -> */, /* pos 027c: 301 */ 0xF4 /* 't' -> */, /* pos 027d: 302 */ 0xE8 /* 'h' -> */, /* pos 027e: 303 */ 0xEF /* 'o' -> */, /* pos 027f: 304 */ 0xF2 /* 'r' -> */, /* pos 0280: 305 */ 0xE9 /* 'i' -> */, /* pos 0281: 306 */ 0xF4 /* 't' -> */, /* pos 0282: 307 */ 0xF9 /* 'y' -> */, /* pos 0283: 308 */ 0x00, 0x23 /* - terminal marker 35 - */, /* pos 0285: 309 */ 0xE5 /* 'e' -> */, /* pos 0286: 310 */ 0xF4 /* 't' -> */, /* pos 0287: 311 */ 0xE8 /* 'h' -> */, /* pos 0288: 312 */ 0xEF /* 'o' -> */, /* pos 0289: 313 */ 0xE4 /* 'd' -> */, /* pos 028a: 314 */ 0x00, 0x24 /* - terminal marker 36 - */, /* pos 028c: 315 */ 0xE1 /* 'a' -> */, /* pos 028d: 316 */ 0xF4 /* 't' -> */, /* pos 028e: 317 */ 0xE8 /* 'h' -> */, /* pos 028f: 318 */ 0x00, 0x25 /* - terminal marker 37 - */, /* pos 0291: 319 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x0298 state 320) */, 0x74 /* 't' */, 0x0A, 0x00 /* (to 0x029E state 325) */, 0x08, /* fail */ /* pos 0298: 320 */ 0xE8 /* 'h' -> */, /* pos 0299: 321 */ 0xE5 /* 'e' -> */, /* pos 029a: 322 */ 0xED /* 'm' -> */, /* pos 029b: 323 */ 0xE5 /* 'e' -> */, /* pos 029c: 324 */ 0x00, 0x26 /* - terminal marker 38 - */, /* pos 029e: 325 */ 0xE1 /* 'a' -> */, /* pos 029f: 326 */ 0xF4 /* 't' -> */, /* pos 02a0: 327 */ 0xF5 /* 'u' -> */, /* pos 02a1: 328 */ 0xF3 /* 's' -> */, /* pos 02a2: 329 */ 0x00, 0x27 /* - terminal marker 39 - */, /* pos 02a4: 330 */ 0xE8 /* 'h' -> */, /* pos 02a5: 331 */ 0xE1 /* 'a' -> */, /* pos 02a6: 332 */ 0xF2 /* 'r' -> */, /* pos 02a7: 333 */ 0xF3 /* 's' -> */, /* pos 02a8: 334 */ 0xE5 /* 'e' -> */, /* pos 02a9: 335 */ 0xF4 /* 't' -> */, /* pos 02aa: 336 */ 0xBA /* ':' -> */, /* pos 02ab: 337 */ 0x00, 0x28 /* - terminal marker 40 - */, /* pos 02ad: 338 */ 0xE1 /* 'a' -> */, /* pos 02ae: 339 */ 0xEE /* 'n' -> */, /* pos 02af: 340 */ 0xE7 /* 'g' -> */, /* pos 02b0: 341 */ 0xE5 /* 'e' -> */, /* pos 02b1: 342 */ 0xF3 /* 's' -> */, /* pos 02b2: 343 */ 0xBA /* ':' -> */, /* pos 02b3: 344 */ 0x00, 0x29 /* - terminal marker 41 - */, /* pos 02b5: 345 */ 0xEC /* 'l' -> */, /* pos 02b6: 346 */ 0xEC /* 'l' -> */, /* pos 02b7: 347 */ 0xEF /* 'o' -> */, /* pos 02b8: 348 */ 0xF7 /* 'w' -> */, /* pos 02b9: 349 */ 0xAD /* '-' -> */, /* pos 02ba: 350 */ 0xEF /* 'o' -> */, /* pos 02bb: 351 */ 0xF2 /* 'r' -> */, /* pos 02bc: 352 */ 0xE9 /* 'i' -> */, /* pos 02bd: 353 */ 0xE7 /* 'g' -> */, /* pos 02be: 354 */ 0xE9 /* 'i' -> */, /* pos 02bf: 355 */ 0xEE /* 'n' -> */, /* pos 02c0: 356 */ 0xBA /* ':' -> */, /* pos 02c1: 357 */ 0x00, 0x2A /* - terminal marker 42 - */, /* pos 02c3: 358 */ 0xE5 /* 'e' -> */, /* pos 02c4: 359 */ 0xBA /* ':' -> */, /* pos 02c5: 360 */ 0x00, 0x2B /* - terminal marker 43 - */, /* pos 02c7: 361 */ 0xEC /* 'l' -> */, /* pos 02c8: 362 */ 0xEF /* 'o' -> */, /* pos 02c9: 363 */ 0xF7 /* 'w' -> */, /* pos 02ca: 364 */ 0xBA /* ':' -> */, /* pos 02cb: 365 */ 0x00, 0x2C /* - terminal marker 44 - */, /* pos 02cd: 366 */ 0xE9 /* 'i' -> */, /* pos 02ce: 367 */ 0xF3 /* 's' -> */, /* pos 02cf: 368 */ 0xF0 /* 'p' -> */, /* pos 02d0: 369 */ 0xEF /* 'o' -> */, /* pos 02d1: 370 */ 0xF3 /* 's' -> */, /* pos 02d2: 371 */ 0xE9 /* 'i' -> */, /* pos 02d3: 372 */ 0xF4 /* 't' -> */, /* pos 02d4: 373 */ 0xE9 /* 'i' -> */, /* pos 02d5: 374 */ 0xEF /* 'o' -> */, /* pos 02d6: 375 */ 0xEE /* 'n' -> */, /* pos 02d7: 376 */ 0xBA /* ':' -> */, /* pos 02d8: 377 */ 0x00, 0x2D /* - terminal marker 45 - */, /* pos 02da: 378 */ 0xEE /* 'n' -> */, /* pos 02db: 379 */ 0xE3 /* 'c' -> */, /* pos 02dc: 380 */ 0xEF /* 'o' -> */, /* pos 02dd: 381 */ 0xE4 /* 'd' -> */, /* pos 02de: 382 */ 0xE9 /* 'i' -> */, /* pos 02df: 383 */ 0xEE /* 'n' -> */, /* pos 02e0: 384 */ 0xE7 /* 'g' -> */, /* pos 02e1: 385 */ 0xBA /* ':' -> */, /* pos 02e2: 386 */ 0x00, 0x2E /* - terminal marker 46 - */, /* pos 02e4: 387 */ 0xEE /* 'n' -> */, /* pos 02e5: 388 */ 0xE7 /* 'g' -> */, /* pos 02e6: 389 */ 0xF5 /* 'u' -> */, /* pos 02e7: 390 */ 0xE1 /* 'a' -> */, /* pos 02e8: 391 */ 0xE7 /* 'g' -> */, /* pos 02e9: 392 */ 0xE5 /* 'e' -> */, /* pos 02ea: 393 */ 0xBA /* ':' -> */, /* pos 02eb: 394 */ 0x00, 0x2F /* - terminal marker 47 - */, /* pos 02ed: 395 */ 0xE3 /* 'c' -> */, /* pos 02ee: 396 */ 0xE1 /* 'a' -> */, /* pos 02ef: 397 */ 0xF4 /* 't' -> */, /* pos 02f0: 398 */ 0xE9 /* 'i' -> */, /* pos 02f1: 399 */ 0xEF /* 'o' -> */, /* pos 02f2: 400 */ 0xEE /* 'n' -> */, /* pos 02f3: 401 */ 0xBA /* ':' -> */, /* pos 02f4: 402 */ 0x00, 0x30 /* - terminal marker 48 - */, /* pos 02f6: 403 */ 0xE1 /* 'a' -> */, /* pos 02f7: 404 */ 0xEE /* 'n' -> */, /* pos 02f8: 405 */ 0xE7 /* 'g' -> */, /* pos 02f9: 406 */ 0xE5 /* 'e' -> */, /* pos 02fa: 407 */ 0xBA /* ':' -> */, /* pos 02fb: 408 */ 0x00, 0x31 /* - terminal marker 49 - */, /* pos 02fd: 409 */ 0x74 /* 't' */, 0x07, 0x00 /* (to 0x0304 state 410) */, 0x78 /* 'x' */, 0x09, 0x00 /* (to 0x0309 state 414) */, 0x08, /* fail */ /* pos 0304: 410 */ 0xE1 /* 'a' -> */, /* pos 0305: 411 */ 0xE7 /* 'g' -> */, /* pos 0306: 412 */ 0xBA /* ':' -> */, /* pos 0307: 413 */ 0x00, 0x32 /* - terminal marker 50 - */, /* pos 0309: 414 */ 0xF0 /* 'p' -> */, /* pos 030a: 415 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0311 state 416) */, 0x69 /* 'i' */, 0x09, 0x00 /* (to 0x0316 state 420) */, 0x08, /* fail */ /* pos 0311: 416 */ 0xE3 /* 'c' -> */, /* pos 0312: 417 */ 0xF4 /* 't' -> */, /* pos 0313: 418 */ 0xBA /* ':' -> */, /* pos 0314: 419 */ 0x00, 0x33 /* - terminal marker 51 - */, /* pos 0316: 420 */ 0xF2 /* 'r' -> */, /* pos 0317: 421 */ 0xE5 /* 'e' -> */, /* pos 0318: 422 */ 0xF3 /* 's' -> */, /* pos 0319: 423 */ 0xBA /* ':' -> */, /* pos 031a: 424 */ 0x00, 0x34 /* - terminal marker 52 - */, /* pos 031c: 425 */ 0xF2 /* 'r' -> */, /* pos 031d: 426 */ 0xEF /* 'o' -> */, /* pos 031e: 427 */ 0xED /* 'm' -> */, /* pos 031f: 428 */ 0xBA /* ':' -> */, /* pos 0320: 429 */ 0x00, 0x35 /* - terminal marker 53 - */, /* pos 0322: 430 */ 0xF4 /* 't' -> */, /* pos 0323: 431 */ 0xE3 /* 'c' -> */, /* pos 0324: 432 */ 0xE8 /* 'h' -> */, /* pos 0325: 433 */ 0xBA /* ':' -> */, /* pos 0326: 434 */ 0x00, 0x36 /* - terminal marker 54 - */, /* pos 0328: 435 */ 0xE1 /* 'a' -> */, /* pos 0329: 436 */ 0xEE /* 'n' -> */, /* pos 032a: 437 */ 0xE7 /* 'g' -> */, /* pos 032b: 438 */ 0xE5 /* 'e' -> */, /* pos 032c: 439 */ 0xBA /* ':' -> */, /* pos 032d: 440 */ 0x00, 0x37 /* - terminal marker 55 - */, /* pos 032f: 441 */ 0xEE /* 'n' -> */, /* pos 0330: 442 */ 0xED /* 'm' -> */, /* pos 0331: 443 */ 0xEF /* 'o' -> */, /* pos 0332: 444 */ 0xE4 /* 'd' -> */, /* pos 0333: 445 */ 0xE9 /* 'i' -> */, /* pos 0334: 446 */ 0xE6 /* 'f' -> */, /* pos 0335: 447 */ 0xE9 /* 'i' -> */, /* pos 0336: 448 */ 0xE5 /* 'e' -> */, /* pos 0337: 449 */ 0xE4 /* 'd' -> */, /* pos 0338: 450 */ 0xAD /* '-' -> */, /* pos 0339: 451 */ 0xF3 /* 's' -> */, /* pos 033a: 452 */ 0xE9 /* 'i' -> */, /* pos 033b: 453 */ 0xEE /* 'n' -> */, /* pos 033c: 454 */ 0xE3 /* 'c' -> */, /* pos 033d: 455 */ 0xE5 /* 'e' -> */, /* pos 033e: 456 */ 0xBA /* ':' -> */, /* pos 033f: 457 */ 0x00, 0x38 /* - terminal marker 56 - */, /* pos 0341: 458 */ 0x61 /* 'a' */, 0x0A, 0x00 /* (to 0x034B state 459) */, 0x69 /* 'i' */, 0x15, 0x00 /* (to 0x0359 state 472) */, 0x6F /* 'o' */, 0x17, 0x00 /* (to 0x035E state 476) */, 0x08, /* fail */ /* pos 034b: 459 */ 0xF3 /* 's' -> */, /* pos 034c: 460 */ 0xF4 /* 't' -> */, /* pos 034d: 461 */ 0xAD /* '-' -> */, /* pos 034e: 462 */ 0xED /* 'm' -> */, /* pos 034f: 463 */ 0xEF /* 'o' -> */, /* pos 0350: 464 */ 0xE4 /* 'd' -> */, /* pos 0351: 465 */ 0xE9 /* 'i' -> */, /* pos 0352: 466 */ 0xE6 /* 'f' -> */, /* pos 0353: 467 */ 0xE9 /* 'i' -> */, /* pos 0354: 468 */ 0xE5 /* 'e' -> */, /* pos 0355: 469 */ 0xE4 /* 'd' -> */, /* pos 0356: 470 */ 0xBA /* ':' -> */, /* pos 0357: 471 */ 0x00, 0x39 /* - terminal marker 57 - */, /* pos 0359: 472 */ 0xEE /* 'n' -> */, /* pos 035a: 473 */ 0xEB /* 'k' -> */, /* pos 035b: 474 */ 0xBA /* ':' -> */, /* pos 035c: 475 */ 0x00, 0x3A /* - terminal marker 58 - */, /* pos 035e: 476 */ 0xE3 /* 'c' -> */, /* pos 035f: 477 */ 0xE1 /* 'a' -> */, /* pos 0360: 478 */ 0xF4 /* 't' -> */, /* pos 0361: 479 */ 0xE9 /* 'i' -> */, /* pos 0362: 480 */ 0xEF /* 'o' -> */, /* pos 0363: 481 */ 0xEE /* 'n' -> */, /* pos 0364: 482 */ 0xBA /* ':' -> */, /* pos 0365: 483 */ 0x00, 0x3B /* - terminal marker 59 - */, /* pos 0367: 484 */ 0xE1 /* 'a' -> */, /* pos 0368: 485 */ 0xF8 /* 'x' -> */, /* pos 0369: 486 */ 0xAD /* '-' -> */, /* pos 036a: 487 */ 0xE6 /* 'f' -> */, /* pos 036b: 488 */ 0xEF /* 'o' -> */, /* pos 036c: 489 */ 0xF2 /* 'r' -> */, /* pos 036d: 490 */ 0xF7 /* 'w' -> */, /* pos 036e: 491 */ 0xE1 /* 'a' -> */, /* pos 036f: 492 */ 0xF2 /* 'r' -> */, /* pos 0370: 493 */ 0xE4 /* 'd' -> */, /* pos 0371: 494 */ 0xF3 /* 's' -> */, /* pos 0372: 495 */ 0xBA /* ':' -> */, /* pos 0373: 496 */ 0x00, 0x3C /* - terminal marker 60 - */, /* pos 0375: 497 */ 0xF8 /* 'x' -> */, /* pos 0376: 498 */ 0xF9 /* 'y' -> */, /* pos 0377: 499 */ 0x2D /* '-' */, 0x07, 0x00 /* (to 0x037E state 500) */, 0x20 /* ' ' */, 0xB5, 0x00 /* (to 0x042F state 649) */, 0x08, /* fail */ /* pos 037e: 500 */ 0xE1 /* 'a' -> */, /* pos 037f: 501 */ 0xF5 /* 'u' -> */, /* pos 0380: 502 */ 0xF4 /* 't' -> */, /* pos 0381: 503 */ 0xE8 /* 'h' -> */, /* pos 0382: 504 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0389 state 505) */, 0x6F /* 'o' */, 0x0E, 0x00 /* (to 0x0393 state 514) */, 0x08, /* fail */ /* pos 0389: 505 */ 0xEE /* 'n' -> */, /* pos 038a: 506 */ 0xF4 /* 't' -> */, /* pos 038b: 507 */ 0xE9 /* 'i' -> */, /* pos 038c: 508 */ 0xE3 /* 'c' -> */, /* pos 038d: 509 */ 0xE1 /* 'a' -> */, /* pos 038e: 510 */ 0xF4 /* 't' -> */, /* pos 038f: 511 */ 0xE5 /* 'e' -> */, /* pos 0390: 512 */ 0xBA /* ':' -> */, /* pos 0391: 513 */ 0x00, 0x3D /* - terminal marker 61 - */, /* pos 0393: 514 */ 0xF2 /* 'r' -> */, /* pos 0394: 515 */ 0xE9 /* 'i' -> */, /* pos 0395: 516 */ 0xFA /* 'z' -> */, /* pos 0396: 517 */ 0xE1 /* 'a' -> */, /* pos 0397: 518 */ 0xF4 /* 't' -> */, /* pos 0398: 519 */ 0xE9 /* 'i' -> */, /* pos 0399: 520 */ 0xEF /* 'o' -> */, /* pos 039a: 521 */ 0xEE /* 'n' -> */, /* pos 039b: 522 */ 0xBA /* ':' -> */, /* pos 039c: 523 */ 0x00, 0x3E /* - terminal marker 62 - */, /* pos 039e: 524 */ 0xE5 /* 'e' -> */, /* pos 039f: 525 */ 0xF3 /* 's' -> */, /* pos 03a0: 526 */ 0xE8 /* 'h' -> */, /* pos 03a1: 527 */ 0xBA /* ':' -> */, /* pos 03a2: 528 */ 0x00, 0x3F /* - terminal marker 63 - */, /* pos 03a4: 529 */ 0xF2 /* 'r' -> */, /* pos 03a5: 530 */ 0xF9 /* 'y' -> */, /* pos 03a6: 531 */ 0xAD /* '-' -> */, /* pos 03a7: 532 */ 0xE1 /* 'a' -> */, /* pos 03a8: 533 */ 0xE6 /* 'f' -> */, /* pos 03a9: 534 */ 0xF4 /* 't' -> */, /* pos 03aa: 535 */ 0xE5 /* 'e' -> */, /* pos 03ab: 536 */ 0xF2 /* 'r' -> */, /* pos 03ac: 537 */ 0xBA /* ':' -> */, /* pos 03ad: 538 */ 0x00, 0x40 /* - terminal marker 64 - */, /* pos 03af: 539 */ 0xF6 /* 'v' -> */, /* pos 03b0: 540 */ 0xE5 /* 'e' -> */, /* pos 03b1: 541 */ 0xF2 /* 'r' -> */, /* pos 03b2: 542 */ 0xBA /* ':' -> */, /* pos 03b3: 543 */ 0x00, 0x41 /* - terminal marker 65 - */, /* pos 03b5: 544 */ 0xAD /* '-' -> */, /* pos 03b6: 545 */ 0xE3 /* 'c' -> */, /* pos 03b7: 546 */ 0xEF /* 'o' -> */, /* pos 03b8: 547 */ 0xEF /* 'o' -> */, /* pos 03b9: 548 */ 0xEB /* 'k' -> */, /* pos 03ba: 549 */ 0xE9 /* 'i' -> */, /* pos 03bb: 550 */ 0xE5 /* 'e' -> */, /* pos 03bc: 551 */ 0xBA /* ':' -> */, /* pos 03bd: 552 */ 0x00, 0x42 /* - terminal marker 66 - */, /* pos 03bf: 553 */ 0xF2 /* 'r' -> */, /* pos 03c0: 554 */ 0xE9 /* 'i' -> */, /* pos 03c1: 555 */ 0xE3 /* 'c' -> */, /* pos 03c2: 556 */ 0xF4 /* 't' -> */, /* pos 03c3: 557 */ 0xAD /* '-' -> */, /* pos 03c4: 558 */ 0xF4 /* 't' -> */, /* pos 03c5: 559 */ 0xF2 /* 'r' -> */, /* pos 03c6: 560 */ 0xE1 /* 'a' -> */, /* pos 03c7: 561 */ 0xEE /* 'n' -> */, /* pos 03c8: 562 */ 0xF3 /* 's' -> */, /* pos 03c9: 563 */ 0xF0 /* 'p' -> */, /* pos 03ca: 564 */ 0xEF /* 'o' -> */, /* pos 03cb: 565 */ 0xF2 /* 'r' -> */, /* pos 03cc: 566 */ 0xF4 /* 't' -> */, /* pos 03cd: 567 */ 0xAD /* '-' -> */, /* pos 03ce: 568 */ 0xF3 /* 's' -> */, /* pos 03cf: 569 */ 0xE5 /* 'e' -> */, /* pos 03d0: 570 */ 0xE3 /* 'c' -> */, /* pos 03d1: 571 */ 0xF5 /* 'u' -> */, /* pos 03d2: 572 */ 0xF2 /* 'r' -> */, /* pos 03d3: 573 */ 0xE9 /* 'i' -> */, /* pos 03d4: 574 */ 0xF4 /* 't' -> */, /* pos 03d5: 575 */ 0xF9 /* 'y' -> */, /* pos 03d6: 576 */ 0xBA /* ':' -> */, /* pos 03d7: 577 */ 0x00, 0x43 /* - terminal marker 67 - */, /* pos 03d9: 578 */ 0xF2 /* 'r' -> */, /* pos 03da: 579 */ 0xE1 /* 'a' -> */, /* pos 03db: 580 */ 0xEE /* 'n' -> */, /* pos 03dc: 581 */ 0xF3 /* 's' -> */, /* pos 03dd: 582 */ 0xE6 /* 'f' -> */, /* pos 03de: 583 */ 0xE5 /* 'e' -> */, /* pos 03df: 584 */ 0xF2 /* 'r' -> */, /* pos 03e0: 585 */ 0xAD /* '-' -> */, /* pos 03e1: 586 */ 0xE5 /* 'e' -> */, /* pos 03e2: 587 */ 0xEE /* 'n' -> */, /* pos 03e3: 588 */ 0xE3 /* 'c' -> */, /* pos 03e4: 589 */ 0xEF /* 'o' -> */, /* pos 03e5: 590 */ 0xE4 /* 'd' -> */, /* pos 03e6: 591 */ 0xE9 /* 'i' -> */, /* pos 03e7: 592 */ 0xEE /* 'n' -> */, /* pos 03e8: 593 */ 0xE7 /* 'g' -> */, /* pos 03e9: 594 */ 0xBA /* ':' -> */, /* pos 03ea: 595 */ 0x00, 0x44 /* - terminal marker 68 - */, /* pos 03ec: 596 */ 0xE5 /* 'e' -> */, /* pos 03ed: 597 */ 0xF2 /* 'r' -> */, /* pos 03ee: 598 */ 0xAD /* '-' -> */, /* pos 03ef: 599 */ 0xE1 /* 'a' -> */, /* pos 03f0: 600 */ 0xE7 /* 'g' -> */, /* pos 03f1: 601 */ 0xE5 /* 'e' -> */, /* pos 03f2: 602 */ 0xEE /* 'n' -> */, /* pos 03f3: 603 */ 0xF4 /* 't' -> */, /* pos 03f4: 604 */ 0xBA /* ':' -> */, /* pos 03f5: 605 */ 0x00, 0x45 /* - terminal marker 69 - */, /* pos 03f7: 606 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x03FE state 607) */, 0x69 /* 'i' */, 0x09, 0x00 /* (to 0x0403 state 611) */, 0x08, /* fail */ /* pos 03fe: 607 */ 0xF2 /* 'r' -> */, /* pos 03ff: 608 */ 0xF9 /* 'y' -> */, /* pos 0400: 609 */ 0xBA /* ':' -> */, /* pos 0401: 610 */ 0x00, 0x46 /* - terminal marker 70 - */, /* pos 0403: 611 */ 0xE1 /* 'a' -> */, /* pos 0404: 612 */ 0xBA /* ':' -> */, /* pos 0405: 613 */ 0x00, 0x47 /* - terminal marker 71 - */, /* pos 0407: 614 */ 0xF7 /* 'w' -> */, /* pos 0408: 615 */ 0xF7 /* 'w' -> */, /* pos 0409: 616 */ 0xAD /* '-' -> */, /* pos 040a: 617 */ 0xE1 /* 'a' -> */, /* pos 040b: 618 */ 0xF5 /* 'u' -> */, /* pos 040c: 619 */ 0xF4 /* 't' -> */, /* pos 040d: 620 */ 0xE8 /* 'h' -> */, /* pos 040e: 621 */ 0xE5 /* 'e' -> */, /* pos 040f: 622 */ 0xEE /* 'n' -> */, /* pos 0410: 623 */ 0xF4 /* 't' -> */, /* pos 0411: 624 */ 0xE9 /* 'i' -> */, /* pos 0412: 625 */ 0xE3 /* 'c' -> */, /* pos 0413: 626 */ 0xE1 /* 'a' -> */, /* pos 0414: 627 */ 0xF4 /* 't' -> */, /* pos 0415: 628 */ 0xE5 /* 'e' -> */, /* pos 0416: 629 */ 0xBA /* ':' -> */, /* pos 0417: 630 */ 0x00, 0x48 /* - terminal marker 72 - */, /* pos 0419: 631 */ 0xF4 /* 't' -> */, /* pos 041a: 632 */ 0xE3 /* 'c' -> */, /* pos 041b: 633 */ 0xE8 /* 'h' -> */, /* pos 041c: 634 */ 0x00, 0x49 /* - terminal marker 73 - */, /* pos 041e: 635 */ 0xF4 /* 't' -> */, /* pos 041f: 636 */ 0x00, 0x4A /* - terminal marker 74 - */, /* pos 0421: 637 */ 0xEC /* 'l' -> */, /* pos 0422: 638 */ 0xE5 /* 'e' -> */, /* pos 0423: 639 */ 0xF4 /* 't' -> */, /* pos 0424: 640 */ 0xE5 /* 'e' -> */, /* pos 0425: 641 */ 0x00, 0x4B /* - terminal marker 75 - */, /* pos 0427: 642 */ 0xE9 /* 'i' -> */, /* pos 0428: 643 */ 0xAD /* '-' -> */, /* pos 0429: 644 */ 0xE1 /* 'a' -> */, /* pos 042a: 645 */ 0xF2 /* 'r' -> */, /* pos 042b: 646 */ 0xE7 /* 'g' -> */, /* pos 042c: 647 */ 0xF3 /* 's' -> */, /* pos 042d: 648 */ 0x00, 0x4C /* - terminal marker 76 - */, /* pos 042f: 649 */ 0x00, 0x4D /* - terminal marker 77 - */, /* pos 0431: 650 */ 0xAD /* '-' -> */, /* pos 0432: 651 */ 0xF2 /* 'r' -> */, /* pos 0433: 652 */ 0xE5 /* 'e' -> */, /* pos 0434: 653 */ 0xE1 /* 'a' -> */, /* pos 0435: 654 */ 0xEC /* 'l' -> */, /* pos 0436: 655 */ 0xAD /* '-' -> */, /* pos 0437: 656 */ 0xE9 /* 'i' -> */, /* pos 0438: 657 */ 0xF0 /* 'p' -> */, /* pos 0439: 658 */ 0xBA /* ':' -> */, /* pos 043a: 659 */ 0x00, 0x4E /* - terminal marker 78 - */, /* pos 043c: 660 */ 0xA0 /* ' ' -> */, /* pos 043d: 661 */ 0x00, 0x4F /* - terminal marker 79 - */, /* total size 1087 bytes */ |
Added undroid/libwebsockets/lib/libev.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" void lws_feature_status_libev(struct lws_context_creation_info *info) { if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEV)) lwsl_notice("libev support compiled in and enabled\n"); else lwsl_notice("libev support compiled in but disabled\n"); } static void lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { struct lws_io_watcher *lws_io = lws_container_of(watcher, struct lws_io_watcher, ev_watcher); struct lws_context *context = lws_io->context; struct lws_pollfd eventfd; if (revents & EV_ERROR) return; eventfd.fd = watcher->fd; eventfd.events = 0; eventfd.revents = EV_NONE; if (revents & EV_READ) { eventfd.events |= LWS_POLLIN; eventfd.revents |= LWS_POLLIN; } if (revents & EV_WRITE) { eventfd.events |= LWS_POLLOUT; eventfd.revents |= LWS_POLLOUT; } lws_service_fd(context, &eventfd); } LWS_VISIBLE void lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents) { ev_break(loop, EVBREAK_ALL); } LWS_VISIBLE int lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint, lws_ev_signal_cb_t *cb) { context->use_ev_sigint = use_ev_sigint; if (cb) context->lws_ev_sigint_cb = cb; else context->lws_ev_sigint_cb = &lws_ev_sigint_cb; return 0; } LWS_VISIBLE int lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi) { struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev_watcher; struct ev_io *w_accept = &context->pt[tsi].w_accept.ev_watcher; struct lws_vhost *vh = context->vhost_list; const char * backend_name; int status = 0; int backend; if (!loop) loop = ev_loop_new(0); else context->pt[tsi].ev_loop_foreign = 1; context->pt[tsi].io_loop_ev = loop; /* * Initialize the accept w_accept with all the listening sockets * and register a callback for read operations */ while (vh) { if (vh->lserv_wsi) { vh->lserv_wsi->w_read.context = context; ev_io_init(w_accept, lws_accept_cb, vh->lserv_wsi->sock, EV_READ); } vh = vh->vhost_next; } ev_io_start(context->pt[tsi].io_loop_ev, w_accept); /* Register the signal watcher unless the user says not to */ if (context->use_ev_sigint) { ev_signal_init(w_sigint, context->lws_ev_sigint_cb, SIGINT); ev_signal_start(context->pt[tsi].io_loop_ev, w_sigint); } backend = ev_backend(loop); switch (backend) { case EVBACKEND_SELECT: backend_name = "select"; break; case EVBACKEND_POLL: backend_name = "poll"; break; case EVBACKEND_EPOLL: backend_name = "epoll"; break; case EVBACKEND_KQUEUE: backend_name = "kqueue"; break; case EVBACKEND_DEVPOLL: backend_name = "/dev/poll"; break; case EVBACKEND_PORT: backend_name = "Solaris 10 \"port\""; break; default: backend_name = "Unknown libev backend"; break; } lwsl_notice(" libev backend: %s\n", backend_name); return status; } void lws_libev_destroyloop(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV)) return; if (!pt->io_loop_ev) return; ev_io_stop(pt->io_loop_ev, &pt->w_accept.ev_watcher); if (context->use_ev_sigint) ev_signal_stop(pt->io_loop_ev, &pt->w_sigint.ev_watcher); if (!pt->ev_loop_foreign) ev_loop_destroy(pt->io_loop_ev); } LWS_VISIBLE void lws_libev_accept(struct lws *new_wsi, int accept_fd) { struct lws_context *context = lws_get_context(new_wsi); struct ev_io *r = &new_wsi->w_read.ev_watcher; struct ev_io *w = &new_wsi->w_write.ev_watcher; if (!LWS_LIBEV_ENABLED(context)) return; new_wsi->w_read.context = context; new_wsi->w_write.context = context; ev_io_init(r, lws_accept_cb, accept_fd, EV_READ); ev_io_init(w, lws_accept_cb, accept_fd, EV_WRITE); } LWS_VISIBLE void lws_libev_io(struct lws *wsi, int flags) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; if (!LWS_LIBEV_ENABLED(context)) return; if (!pt->io_loop_ev || context->being_destroyed) return; assert((flags & (LWS_EV_START | LWS_EV_STOP)) && (flags & (LWS_EV_READ | LWS_EV_WRITE))); if (flags & LWS_EV_START) { if (flags & LWS_EV_WRITE) ev_io_start(pt->io_loop_ev, &wsi->w_write.ev_watcher); if (flags & LWS_EV_READ) ev_io_start(pt->io_loop_ev, &wsi->w_read.ev_watcher); } else { if (flags & LWS_EV_WRITE) ev_io_stop(pt->io_loop_ev, &wsi->w_write.ev_watcher); if (flags & LWS_EV_READ) ev_io_stop(pt->io_loop_ev, &wsi->w_read.ev_watcher); } } LWS_VISIBLE int lws_libev_init_fd_table(struct lws_context *context) { int n; if (!LWS_LIBEV_ENABLED(context)) return 0; for (n = 0; n < context->count_threads; n++) { context->pt[n].w_accept.context = context; context->pt[n].w_sigint.context = context; } return 1; } LWS_VISIBLE void lws_libev_run(const struct lws_context *context, int tsi) { if (context->pt[tsi].io_loop_ev && LWS_LIBEV_ENABLED(context)) ev_run(context->pt[tsi].io_loop_ev, 0); } |
Added undroid/libwebsockets/lib/libuv.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" void lws_feature_status_libuv(struct lws_context_creation_info *info) { if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) lwsl_notice("libuv support compiled in and enabled\n"); else lwsl_notice("libuv support compiled in but disabled\n"); } static void lws_uv_idle(uv_idle_t *handle #if UV_VERSION_MAJOR == 0 , int status #endif ) { struct lws_context_per_thread *pt = lws_container_of(handle, struct lws_context_per_thread, uv_idle); lwsl_debug("%s\n", __func__); /* * is there anybody with pending stuff that needs service forcing? */ if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { /* -1 timeout means just do forced service */ lws_plat_service_tsi(pt->context, -1, pt->tid); /* still somebody left who wants forced service? */ if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) /* yes... come back again later */ lwsl_debug("%s: done again\n", __func__); return; } /* there is nobody who needs service forcing, shut down idle */ uv_idle_stop(handle); lwsl_debug("%s: done stop\n", __func__); } static void lws_io_cb(uv_poll_t *watcher, int status, int revents) { struct lws_io_watcher *lws_io = lws_container_of(watcher, struct lws_io_watcher, uv_watcher); struct lws *wsi = lws_container_of(lws_io, struct lws, w_read); struct lws_context *context = lws_io->context; struct lws_pollfd eventfd; #if defined(WIN32) || defined(_WIN32) eventfd.fd = watcher->socket; #else eventfd.fd = watcher->io_watcher.fd; #endif eventfd.events = 0; eventfd.revents = 0; if (status < 0) { /* at this point status will be an UV error, like UV_EBADF, we treat all errors as LWS_POLLHUP */ /* you might want to return; instead of servicing the fd in some cases */ if (status == UV_EAGAIN) return; eventfd.events |= LWS_POLLHUP; eventfd.revents |= LWS_POLLHUP; } else { if (revents & UV_READABLE) { eventfd.events |= LWS_POLLIN; eventfd.revents |= LWS_POLLIN; } if (revents & UV_WRITABLE) { eventfd.events |= LWS_POLLOUT; eventfd.revents |= LWS_POLLOUT; } } lws_service_fd(context, &eventfd); uv_idle_start(&context->pt[(int)wsi->tsi].uv_idle, lws_uv_idle); } LWS_VISIBLE void lws_uv_sigint_cb(uv_signal_t *watcher, int signum) { lwsl_err("internal signal handler caught signal %d\n", signum); lws_libuv_stop(watcher->data); } LWS_VISIBLE int lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint, uv_signal_cb cb) { context->use_ev_sigint = use_uv_sigint; if (cb) context->lws_uv_sigint_cb = cb; else context->lws_uv_sigint_cb = &lws_uv_sigint_cb; return 0; } static void lws_uv_timeout_cb(uv_timer_t *timer #if UV_VERSION_MAJOR == 0 , int status #endif ) { struct lws_context_per_thread *pt = lws_container_of(timer, struct lws_context_per_thread, uv_timeout_watcher); if (pt->context->requested_kill) return; lwsl_debug("%s\n", __func__); lws_service_fd_tsi(pt->context, NULL, pt->tid); } static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE }; LWS_VISIBLE int lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_vhost *vh = context->vhost_list; int status = 0, n; if (!loop) { loop = lws_malloc(sizeof(*loop)); if (!loop) { lwsl_err("OOM\n"); return -1; } #if UV_VERSION_MAJOR > 0 uv_loop_init(loop); #else lwsl_err("This libuv is too old to work...\n"); return 1; #endif pt->ev_loop_foreign = 0; } else { lwsl_notice(" Using foreign event loop...\n"); pt->ev_loop_foreign = 1; } pt->io_loop_uv = loop; uv_idle_init(loop, &pt->uv_idle); if (pt->context->use_ev_sigint) { assert(ARRAY_SIZE(sigs) <= ARRAY_SIZE(pt->signals)); for (n = 0; n < ARRAY_SIZE(sigs); n++) { uv_signal_init(loop, &pt->signals[n]); pt->signals[n].data = pt->context; uv_signal_start(&pt->signals[n], context->lws_uv_sigint_cb, sigs[n]); } } /* * Initialize the accept wsi read watcher with all the listening sockets * and register a callback for read operations * * We have to do it here because the uv loop(s) are not * initialized until after context creation. */ while (vh) { if (vh->lserv_wsi) { vh->lserv_wsi->w_read.context = context; n = uv_poll_init_socket(pt->io_loop_uv, &vh->lserv_wsi->w_read.uv_watcher, vh->lserv_wsi->sock); if (n) { lwsl_err("uv_poll_init failed %d, sockfd=%p\n", n, (void *)(long)vh->lserv_wsi->sock); return -1; } lws_libuv_io(vh->lserv_wsi, LWS_EV_START | LWS_EV_READ); } vh = vh->vhost_next; } uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher); uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 10, 1000); return status; } static void lws_uv_close_cb(uv_handle_t *handle) { //lwsl_err("%s: handle %p\n", __func__, handle); } static void lws_uv_walk_cb(uv_handle_t *handle, void *arg) { uv_close(handle, lws_uv_close_cb); } void lws_libuv_destroyloop(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; int m, budget = 100; if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)) return; if (!pt->io_loop_uv) return; if (context->use_ev_sigint) { uv_signal_stop(&pt->w_sigint.uv_watcher); for (m = 0; m < ARRAY_SIZE(sigs); m++) { uv_signal_stop(&pt->signals[m]); uv_close((uv_handle_t *)&pt->signals[m], lws_uv_close_cb); } } uv_timer_stop(&pt->uv_timeout_watcher); uv_close((uv_handle_t *)&pt->uv_timeout_watcher, lws_uv_close_cb); uv_idle_stop(&pt->uv_idle); uv_close((uv_handle_t *)&pt->uv_idle, lws_uv_close_cb); while (budget-- && uv_run(pt->io_loop_uv, UV_RUN_NOWAIT)) ; if (pt->ev_loop_foreign) return; uv_stop(pt->io_loop_uv); uv_walk(pt->io_loop_uv, lws_uv_walk_cb, NULL); while (uv_run(pt->io_loop_uv, UV_RUN_NOWAIT)) ; #if UV_VERSION_MAJOR > 0 m = uv_loop_close(pt->io_loop_uv); if (m == UV_EBUSY) lwsl_err("%s: uv_loop_close: UV_EBUSY\n", __func__); #endif lws_free(pt->io_loop_uv); } void lws_libuv_accept(struct lws *wsi, int accept_fd) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; if (!LWS_LIBUV_ENABLED(context)) return; lwsl_debug("%s: new wsi %p\n", __func__, wsi); wsi->w_read.context = context; uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher, accept_fd); } void lws_libuv_io(struct lws *wsi, int flags) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; #if defined(WIN32) || defined(_WIN32) int current_events = wsi->w_read.uv_watcher.events & (UV_READABLE | UV_WRITABLE); #else int current_events = wsi->w_read.uv_watcher.io_watcher.pevents & (UV_READABLE | UV_WRITABLE); #endif struct lws_io_watcher *w = &wsi->w_read; if (!LWS_LIBUV_ENABLED(context)) return; // lwsl_notice("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags); if (!pt->io_loop_uv) { lwsl_info("%s: no io loop yet\n", __func__); return; } if (!((flags & (LWS_EV_START | LWS_EV_STOP)) && (flags & (LWS_EV_READ | LWS_EV_WRITE)))) { lwsl_err("%s: assert: flags %d", __func__, flags); assert(0); } if (flags & LWS_EV_START) { if (flags & LWS_EV_WRITE) current_events |= UV_WRITABLE; if (flags & LWS_EV_READ) current_events |= UV_READABLE; uv_poll_start(&w->uv_watcher, current_events, lws_io_cb); } else { if (flags & LWS_EV_WRITE) current_events &= ~UV_WRITABLE; if (flags & LWS_EV_READ) current_events &= ~UV_READABLE; if (!(current_events & (UV_READABLE | UV_WRITABLE))) uv_poll_stop(&w->uv_watcher); else uv_poll_start(&w->uv_watcher, current_events, lws_io_cb); } } int lws_libuv_init_fd_table(struct lws_context *context) { int n; if (!LWS_LIBUV_ENABLED(context)) return 0; for (n = 0; n < context->count_threads; n++) context->pt[n].w_sigint.context = context; return 1; } LWS_VISIBLE void lws_libuv_run(const struct lws_context *context, int tsi) { if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context)) uv_run(context->pt[tsi].io_loop_uv, 0); } static void lws_libuv_kill(const struct lws_context *context) { int n; for (n = 0; n < context->count_threads; n++) if (context->pt[n].io_loop_uv && LWS_LIBUV_ENABLED(context) && !context->pt[n].ev_loop_foreign) uv_stop(context->pt[n].io_loop_uv); } /* * This does not actually stop the event loop. The reason is we have to pass * libuv handle closures through its event loop. So this tries to close all * wsi, and set a flag; when all the wsi closures are finalized then we * actually stop the libuv event loops. */ LWS_VISIBLE void lws_libuv_stop(struct lws_context *context) { struct lws_context_per_thread *pt; int n, m; if (context->requested_kill) return; context->requested_kill = 1; m = context->count_threads; context->being_destroyed = 1; while (m--) { pt = &context->pt[m]; for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) { struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd); if (!wsi) continue; lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY /* no protocol close */); n--; } } lwsl_info("%s: feels everything closed\n", __func__); if (context->count_wsi_allocated == 0) lws_libuv_kill(context); } LWS_VISIBLE uv_loop_t * lws_uv_getloop(struct lws_context *context, int tsi) { if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context)) return context->pt[tsi].io_loop_uv; return NULL; } static void lws_libuv_closewsi(uv_handle_t* handle) { struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) - (char *)(&n->w_read.uv_watcher)); struct lws_context *context = lws_get_context(wsi); lws_close_free_wsi_final(wsi); if (context->requested_kill && context->count_wsi_allocated == 0) lws_libuv_kill(context); } void lws_libuv_closehandle(struct lws *wsi) { struct lws_context *context = lws_get_context(wsi); /* required to defer actual deletion until libuv has processed it */ uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi); if (context->requested_kill && context->count_wsi_allocated == 0) lws_libuv_kill(context); } #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0) LWS_VISIBLE int lws_plat_plugins_init(struct lws_context * context, const char * const *d) { struct lws_plugin_capability lcaps; struct lws_plugin *plugin; lws_plugin_init_func initfunc; int m, ret = 0; void *v; uv_dirent_t dent; uv_fs_t req; char path[256]; uv_loop_t loop; uv_lib_t lib; lib.errmsg = NULL; lib.handle = NULL; uv_loop_init(&loop); lwsl_notice(" Plugins:\n"); while (d && *d) { lwsl_notice(" Scanning %s\n", *d); m =uv_fs_scandir(&loop, &req, *d, 0, NULL); if (m < 1) { lwsl_err("Scandir on %s failed\n", *d); return 1; } while (uv_fs_scandir_next(&req, &dent) != UV_EOF) { if (strlen(dent.name) < 7) continue; lwsl_notice(" %s\n", dent.name); lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d, dent.name); if (uv_dlopen(path, &lib)) { uv_dlerror(&lib); lwsl_err("Error loading DSO: %s\n", lib.errmsg); goto bail; } /* we could open it, can we get his init function? */ m = lws_snprintf(path, sizeof(path) - 1, "init_%s", dent.name + 3 /* snip lib... */); path[m - 3] = '\0'; /* snip the .so */ if (uv_dlsym(&lib, path, &v)) { uv_dlerror(&lib); lwsl_err("Failed to get init on %s: %s", dent.name, lib.errmsg); goto bail; } initfunc = (lws_plugin_init_func)v; lcaps.api_magic = LWS_PLUGIN_API_MAGIC; m = initfunc(context, &lcaps); if (m) { lwsl_err("Initializing %s failed %d\n", dent.name, m); goto skip; } plugin = lws_malloc(sizeof(*plugin)); if (!plugin) { lwsl_err("OOM\n"); goto bail; } plugin->list = context->plugin_list; context->plugin_list = plugin; strncpy(plugin->name, dent.name, sizeof(plugin->name) - 1); plugin->name[sizeof(plugin->name) - 1] = '\0'; plugin->lib = lib; plugin->caps = lcaps; context->plugin_protocol_count += lcaps.count_protocols; context->plugin_extension_count += lcaps.count_extensions; continue; skip: uv_dlclose(&lib); } bail: uv_fs_req_cleanup(&req); d++; } uv_loop_close(&loop); return ret; } LWS_VISIBLE int lws_plat_plugins_destroy(struct lws_context * context) { struct lws_plugin *plugin = context->plugin_list, *p; lws_plugin_destroy_func func; char path[256]; void *v; int m; if (!plugin) return 0; // lwsl_notice("%s\n", __func__); while (plugin) { p = plugin; m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3); path[m - 3] = '\0'; if (uv_dlsym(&plugin->lib, path, &v)) { uv_dlerror(&plugin->lib); lwsl_err("Failed to get init on %s: %s", plugin->name, plugin->lib.errmsg); } else { func = (lws_plugin_destroy_func)v; m = func(context); if (m) lwsl_err("Destroying %s failed %d\n", plugin->name, m); } uv_dlclose(&p->lib); plugin = p->list; p->list = NULL; free(p); } context->plugin_list = NULL; return 0; } #endif |
Added undroid/libwebsockets/lib/libwebsockets.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #ifdef LWS_HAVE_SYS_TYPES_H #include <sys/types.h> #endif #if defined(WIN32) || defined(_WIN32) #else #include <sys/wait.h> #endif int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE; static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr; static const char * const log_level_names[] = { "ERR", "WARN", "NOTICE", "INFO", "DEBUG", "PARSER", "HEADER", "EXTENSION", "CLIENT", "LATENCY", }; void lws_free_wsi(struct lws *wsi) { if (!wsi) return; /* Protocol user data may be allocated either internally by lws * or by specified the user. * We should only free what we allocated. */ if (wsi->protocol && wsi->protocol->per_session_data_size && wsi->user_space && !wsi->user_space_externally_allocated) lws_free(wsi->user_space); lws_free_set_NULL(wsi->rxflow_buffer); lws_free_set_NULL(wsi->trunc_alloc); if (wsi->u.hdr.ah) /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; /* we may not have an ah, but may be on the waiting list... */ lws_header_table_detach(wsi, 0); wsi->context->count_wsi_allocated--; lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi, wsi->context->count_wsi_allocated); lws_free(wsi); } static void lws_remove_from_timeout_list(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; if (!wsi->timeout_list_prev) /* ie, not part of the list */ return; lws_pt_lock(pt); /* if we have a next guy, set his prev to our prev */ if (wsi->timeout_list) wsi->timeout_list->timeout_list_prev = wsi->timeout_list_prev; /* set our prev guy to our next guy instead of us */ *wsi->timeout_list_prev = wsi->timeout_list; /* we're out of the list, we should not point anywhere any more */ wsi->timeout_list_prev = NULL; wsi->timeout_list = NULL; lws_pt_unlock(pt); } /** * lws_set_timeout() - marks the wsi as subject to a timeout * * You will not need this unless you are doing something special * * @wsi: Websocket connection instance * @reason: timeout reason * @secs: how many seconds */ LWS_VISIBLE void lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; time_t now; lws_pt_lock(pt); time(&now); if (reason && !wsi->timeout_list_prev) { /* our next guy is current first guy */ wsi->timeout_list = pt->timeout_list; /* if there is a next guy, set his prev ptr to our next ptr */ if (wsi->timeout_list) wsi->timeout_list->timeout_list_prev = &wsi->timeout_list; /* our prev ptr is first ptr */ wsi->timeout_list_prev = &pt->timeout_list; /* set the first guy to be us */ *wsi->timeout_list_prev = wsi; } lwsl_debug("%s: %p: %d secs\n", __func__, wsi, secs); wsi->pending_timeout_limit = now + secs; wsi->pending_timeout = reason; lws_pt_unlock(pt); if (!reason) lws_remove_from_timeout_list(wsi); } void lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason) { struct lws_context_per_thread *pt; struct lws **pwsi, *wsi1, *wsi2; struct lws_context *context; struct lws_tokens eff_buf; int n, m, ret; if (!wsi) return; lws_access_log(wsi); context = wsi->context; pt = &context->pt[(int)wsi->tsi]; /* if we have children, close them first */ if (wsi->child_list) { wsi2 = wsi->child_list; while (wsi2) { //lwsl_notice("%s: closing %p: close child %p\n", // __func__, wsi, wsi2); wsi1 = wsi2->sibling_list; //lwsl_notice("%s: closing %p: next sibling %p\n", // __func__, wsi2, wsi1); wsi2->parent = NULL; /* stop it doing shutdown processing */ wsi2->socket_is_permanently_unusable = 1; lws_close_free_wsi(wsi2, reason); wsi2 = wsi1; } wsi->child_list = NULL; } #ifdef LWS_WITH_CGI if (wsi->mode == LWSCM_CGI) { /* we are not a network connection, but a handler for CGI io */ if (wsi->parent && wsi->parent->cgi) /* end the binding between us and master */ wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL; wsi->socket_is_permanently_unusable = 1; lwsl_debug("------ %s: detected cgi fdhandler wsi %p\n", __func__, wsi); goto just_kill_connection; } if (wsi->cgi) { struct lws_cgi **pcgi = &pt->cgi_list; /* remove us from the cgi list */ lwsl_notice("%s: remove cgi %p from list\n", __func__, wsi->cgi); while (*pcgi) { if (*pcgi == wsi->cgi) { /* drop us from the pt cgi list */ *pcgi = (*pcgi)->cgi_list; break; } pcgi = &(*pcgi)->cgi_list; } /* we have a cgi going, we must kill it */ wsi->cgi->being_closed = 1; lws_cgi_kill(wsi); } #endif if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED && wsi->u.http.fd != LWS_INVALID_FILE) { lws_plat_file_close(wsi, wsi->u.http.fd); wsi->u.http.fd = LWS_INVALID_FILE; wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0); } if (wsi->socket_is_permanently_unusable || reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY || wsi->state == LWSS_SHUTDOWN) goto just_kill_connection; wsi->state_pre_close = wsi->state; switch (wsi->state_pre_close) { case LWSS_DEAD_SOCKET: return; /* we tried the polite way... */ case LWSS_AWAITING_CLOSE_ACK: goto just_kill_connection; case LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE: if (wsi->trunc_len) { lws_callback_on_writable(wsi); return; } lwsl_info("wsi %p completed LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); goto just_kill_connection; default: if (wsi->trunc_len) { lwsl_info("wsi %p entering LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); wsi->state = LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE; lws_set_timeout(wsi, PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5); return; } break; } if (wsi->mode == LWSCM_WSCL_WAITING_CONNECT || wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE) goto just_kill_connection; if (wsi->mode == LWSCM_HTTP_SERVING) wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0); if (wsi->mode == LWSCM_HTTP_CLIENT) wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLOSED_CLIENT_HTTP, wsi->user_space, NULL, 0); /* * are his extensions okay with him closing? Eg he might be a mux * parent and just his ch1 aspect is closing? */ if (lws_ext_cb_active(wsi, LWS_EXT_CB_CHECK_OK_TO_REALLY_CLOSE, NULL, 0) > 0) { lwsl_ext("extension vetoed close\n"); return; } /* * flush any tx pending from extensions, since we may send close packet * if there are problems with send, just nuke the connection */ do { ret = 0; eff_buf.token = NULL; eff_buf.token_len = 0; /* show every extension the new incoming data */ m = lws_ext_cb_active(wsi, LWS_EXT_CB_FLUSH_PENDING_TX, &eff_buf, 0); if (m < 0) { lwsl_ext("Extension reports fatal error\n"); goto just_kill_connection; } if (m) /* * at least one extension told us he has more * to spill, so we will go around again after */ ret = 1; /* assuming they left us something to send, send it */ if (eff_buf.token_len) if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, eff_buf.token_len) != eff_buf.token_len) { lwsl_debug("close: ext spill failed\n"); goto just_kill_connection; } } while (ret); /* * signal we are closing, lws_write will * add any necessary version-specific stuff. If the write fails, * no worries we are closing anyway. If we didn't initiate this * close, then our state has been changed to * LWSS_RETURNED_CLOSE_ALREADY and we will skip this. * * Likewise if it's a second call to close this connection after we * sent the close indication to the peer already, we are in state * LWSS_AWAITING_CLOSE_ACK and will skip doing this a second time. */ if (wsi->state_pre_close == LWSS_ESTABLISHED && (wsi->u.ws.close_in_ping_buffer_len || /* already a reason */ (reason != LWS_CLOSE_STATUS_NOSTATUS && (reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY)))) { lwsl_debug("sending close indication...\n"); /* if no prepared close reason, use 1000 and no aux data */ if (!wsi->u.ws.close_in_ping_buffer_len) { wsi->u.ws.close_in_ping_buffer_len = 2; wsi->u.ws.ping_payload_buf[LWS_PRE] = (reason >> 16) & 0xff; wsi->u.ws.ping_payload_buf[LWS_PRE + 1] = reason & 0xff; } n = lws_write(wsi, &wsi->u.ws.ping_payload_buf[LWS_PRE], wsi->u.ws.close_in_ping_buffer_len, LWS_WRITE_CLOSE); if (n >= 0) { /* * we have sent a nice protocol level indication we * now wish to close, we should not send anything more */ wsi->state = LWSS_AWAITING_CLOSE_ACK; /* * ...and we should wait for a reply for a bit * out of politeness */ lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 1); lwsl_debug("sent close indication, awaiting ack\n"); return; } lwsl_info("close: sending close packet failed, hanging up\n"); /* else, the send failed and we should just hang up */ } just_kill_connection: if (wsi->parent) { /* detach ourselves from parent's child list */ pwsi = &wsi->parent->child_list; while (*pwsi) { if (*pwsi == wsi) { lwsl_notice("%s: detach %p from parent %p\n", __func__, wsi, wsi->parent); *pwsi = wsi->sibling_list; break; } pwsi = &(*pwsi)->sibling_list; } if (*pwsi) lwsl_err("%s: failed to detach from parent\n", __func__); } #if LWS_POSIX /* * Testing with ab shows that we have to stage the socket close when * the system is under stress... shutdown any further TX, change the * state to one that won't emit anything more, and wait with a timeout * for the POLLIN to show a zero-size rx before coming back and doing * the actual close. */ if (wsi->state != LWSS_SHUTDOWN && wsi->state != LWSS_CLIENT_UNCONNECTED && reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY && !wsi->socket_is_permanently_unusable) { lwsl_info("%s: shutting down connection: %p (sock %d, state %d)\n", __func__, wsi, wsi->sock, wsi->state); n = shutdown(wsi->sock, SHUT_WR); if (n) lwsl_debug("closing: shutdown (state %d) ret %d\n", wsi->state, LWS_ERRNO); // This causes problems with disconnection when the events are half closing connection // FD_READ | FD_CLOSE (33) #ifndef _WIN32_WCE /* libuv: no event available to guarantee completion */ if (!LWS_LIBUV_ENABLED(context)) { lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN); wsi->state = LWSS_SHUTDOWN; lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH, context->timeout_secs); return; } #endif } #endif lwsl_info("%s: real just_kill_connection: %p (sockfd %d)\n", __func__, wsi, wsi->sock); #ifdef LWS_WITH_HTTP_PROXY if (wsi->rw) { lws_rewrite_destroy(wsi->rw); wsi->rw = NULL; } #endif /* * we won't be servicing or receiving anything further from this guy * delete socket from the internal poll list if still present */ lws_ssl_remove_wsi_from_buffered_list(wsi); lws_remove_from_timeout_list(wsi); /* checking return redundant since we anyway close */ if (wsi->sock != LWS_SOCK_INVALID) remove_wsi_socket_from_fds(wsi); wsi->state = LWSS_DEAD_SOCKET; lws_free_set_NULL(wsi->rxflow_buffer); if (wsi->state_pre_close == LWSS_ESTABLISHED || wsi->mode == LWSCM_WS_SERVING || wsi->mode == LWSCM_WS_CLIENT) { if (wsi->u.ws.rx_draining_ext) { struct lws **w = &pt->rx_draining_ext_list; wsi->u.ws.rx_draining_ext = 0; /* remove us from context draining ext list */ while (*w) { if (*w == wsi) { *w = wsi->u.ws.rx_draining_ext_list; break; } w = &((*w)->u.ws.rx_draining_ext_list); } wsi->u.ws.rx_draining_ext_list = NULL; } if (wsi->u.ws.tx_draining_ext) { struct lws **w = &pt->tx_draining_ext_list; wsi->u.ws.tx_draining_ext = 0; /* remove us from context draining ext list */ while (*w) { if (*w == wsi) { *w = wsi->u.ws.tx_draining_ext_list; break; } w = &((*w)->u.ws.tx_draining_ext_list); } wsi->u.ws.tx_draining_ext_list = NULL; } lws_free_set_NULL(wsi->u.ws.rx_ubuf); if (wsi->trunc_alloc) /* not going to be completed... nuke it */ lws_free_set_NULL(wsi->trunc_alloc); wsi->u.ws.ping_payload_len = 0; wsi->u.ws.ping_pending_flag = 0; } /* tell the user it's all over for this guy */ if (wsi->protocol && wsi->protocol->callback && ((wsi->state_pre_close == LWSS_ESTABLISHED) || (wsi->state_pre_close == LWSS_RETURNED_CLOSE_ALREADY) || (wsi->state_pre_close == LWSS_AWAITING_CLOSE_ACK) || (wsi->state_pre_close == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) || (wsi->mode == LWSCM_WS_CLIENT && wsi->state_pre_close == LWSS_HTTP) || (wsi->mode == LWSCM_WS_SERVING && wsi->state_pre_close == LWSS_HTTP))) { lwsl_debug("calling back CLOSED\n"); wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED, wsi->user_space, NULL, 0); } else if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED) { lwsl_debug("calling back CLOSED_HTTP\n"); wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0 ); } else if (wsi->mode == LWSCM_WSCL_WAITING_SERVER_REPLY || wsi->mode == LWSCM_WSCL_WAITING_CONNECT) { char* errorString; lwsl_debug("Connection closed before server reply\n"); errorString = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP); if (errorString) { wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, errorString, (unsigned int)strlen(errorString)); } else { wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); } } else lwsl_debug("not calling back closed mode=%d state=%d\n", wsi->mode, wsi->state_pre_close); /* deallocate any active extension contexts */ if (lws_ext_cb_active(wsi, LWS_EXT_CB_DESTROY, NULL, 0) < 0) lwsl_warn("extension destruction failed\n"); /* * inform all extensions in case they tracked this guy out of band * even though not active on him specifically */ if (lws_ext_cb_all_exts(context, wsi, LWS_EXT_CB_DESTROY_ANY_WSI_CLOSING, NULL, 0) < 0) lwsl_warn("ext destroy wsi failed\n"); wsi->socket_is_permanently_unusable = 1; #ifdef LWS_USE_LIBUV if (LWS_LIBUV_ENABLED(context)) { lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi); /* libuv has to do his own close handle processing asynchronously */ lws_libuv_closehandle(wsi); return; } #endif lws_close_free_wsi_final(wsi); } void lws_close_free_wsi_final(struct lws *wsi) { int n; if (!lws_ssl_close(wsi) && lws_socket_is_valid(wsi->sock)) { #if LWS_POSIX //lwsl_err("*** closing sockfd %d\n", wsi->sock); n = compatible_close(wsi->sock); if (n) lwsl_debug("closing: close ret %d\n", LWS_ERRNO); #else compatible_close(wsi->sock); #endif wsi->sock = LWS_SOCK_INVALID; } /* outermost destroy notification for wsi (user_space still intact) */ wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, wsi->user_space, NULL, 0); #ifdef LWS_WITH_CGI if (wsi->cgi) { for (n = 0; n < 6; n++) if (wsi->cgi->pipe_fds[n / 2][n & 1] >= 0) close(wsi->cgi->pipe_fds[n / 2][n & 1]); lws_free(wsi->cgi); } #endif lws_free_wsi(wsi); } #if LWS_POSIX LWS_VISIBLE int interface_to_sa(struct lws_context *context, const char *ifname, struct sockaddr_in *addr, size_t addrlen) { int ipv6 = 0; #ifdef LWS_USE_IPV6 ipv6 = LWS_IPV6_ENABLED(context); #endif (void)context; return lws_interface_to_sa(ipv6, ifname, addr, addrlen); } #endif LWS_VISIBLE int lws_get_addresses(struct lws_context *context, void *ads, char *name, int name_len, char *rip, int rip_len) { #if LWS_POSIX struct addrinfo ai, *res; struct sockaddr_in addr4; if (rip) rip[0] = '\0'; name[0] = '\0'; addr4.sin_family = AF_UNSPEC; #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { if (!lws_plat_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)ads)->sin6_addr, rip, rip_len)) { lwsl_err("inet_ntop", strerror(LWS_ERRNO)); return -1; } // Strip off the IPv4 to IPv6 header if one exists if (strncmp(rip, "::ffff:", 7) == 0) memmove(rip, rip + 7, strlen(rip) - 6); getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6), name, name_len, NULL, 0, 0); return 0; } else #endif { struct addrinfo *result; memset(&ai, 0, sizeof ai); ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; ai.ai_flags = AI_CANONNAME; if (getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in), name, name_len, NULL, 0, 0)) return -1; if (!rip) return 0; if (getaddrinfo(name, NULL, &ai, &result)) return -1; res = result; while (addr4.sin_family == AF_UNSPEC && res) { switch (res->ai_family) { case AF_INET: addr4.sin_addr = ((struct sockaddr_in *)res->ai_addr)->sin_addr; addr4.sin_family = AF_INET; break; } res = res->ai_next; } freeaddrinfo(result); } if (addr4.sin_family == AF_UNSPEC) return -1; if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip, rip_len) == NULL) return -1; return 0; #else (void)context; (void)ads; (void)name; (void)name_len; (void)rip; (void)rip_len; return -1; #endif } const char * lws_get_peer_simple(struct lws *wsi, char *name, int namelen) { #if LWS_POSIX socklen_t len, olen; #ifdef LWS_USE_IPV6 struct sockaddr_in6 sin6; #endif struct sockaddr_in sin4; int af = AF_INET; void *p, *q; #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(wsi->context)) { len = sizeof(sin6); p = &sin6; af = AF_INET6; q = &sin6.sin6_addr; } else #endif { len = sizeof(sin4); p = &sin4; q = &sin4.sin_addr; } olen = len; if (getpeername(wsi->sock, p, &len) < 0 || len > olen) { lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); return NULL; } return lws_plat_inet_ntop(af, q, name, namelen); #else return NULL; #endif } /** * lws_get_peer_addresses() - Get client address information * @wsi: Local struct lws associated with * @fd: Connection socket descriptor * @name: Buffer to take client address name * @name_len: Length of client address name buffer * @rip: Buffer to take client address IP dotted quad * @rip_len: Length of client address IP buffer * * This function fills in @name and @rip with the name and IP of * the client connected with socket descriptor @fd. Names may be * truncated if there is not enough room. If either cannot be * determined, they will be returned as valid zero-length strings. */ LWS_VISIBLE void lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name, int name_len, char *rip, int rip_len) { #if LWS_POSIX socklen_t len; #ifdef LWS_USE_IPV6 struct sockaddr_in6 sin6; #endif struct sockaddr_in sin4; struct lws_context *context = wsi->context; int ret = -1; void *p; rip[0] = '\0'; name[0] = '\0'; lws_latency_pre(context, wsi); #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { len = sizeof(sin6); p = &sin6; } else #endif { len = sizeof(sin4); p = &sin4; } if (getpeername(fd, p, &len) < 0) { lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); goto bail; } ret = lws_get_addresses(context, p, name, name_len, rip, rip_len); bail: lws_latency(context, wsi, "lws_get_peer_addresses", ret, 1); #else (void)wsi; (void)fd; (void)name; (void)name_len; (void)rip; (void)rip_len; #endif } /** * lws_context_user() - get the user data associated with the context * @context: Websocket context * * This returns the optional user allocation that can be attached to * the context the sockets live in at context_create time. It's a way * to let all sockets serviced in the same context share data without * using globals statics in the user code. */ LWS_EXTERN void * lws_context_user(struct lws_context *context) { return context->user_space; } LWS_VISIBLE struct lws_vhost * lws_vhost_get(struct lws *wsi) { return wsi->vhost; } LWS_VISIBLE const struct lws_protocols * lws_protocol_get(struct lws *wsi) { return wsi->protocol; } /** * lws_callback_all_protocol() - Callback all connections using * the given protocol with the given reason * * @protocol: Protocol whose connections will get callbacks * @reason: Callback reason index */ LWS_VISIBLE int lws_callback_all_protocol(struct lws_context *context, const struct lws_protocols *protocol, int reason) { struct lws_context_per_thread *pt = &context->pt[0]; unsigned int n, m = context->count_threads; struct lws *wsi; while (m--) { for (n = 0; n < pt->fds_count; n++) { wsi = wsi_from_fd(context, pt->fds[n].fd); if (!wsi) continue; if (wsi->protocol == protocol) protocol->callback(wsi, reason, wsi->user_space, NULL, 0); } pt++; } return 0; } /** * lws_callback_all_protocol_vhost() - Callback all connections using * the given protocol with the given reason * * @vh: Vhost whose connections will get callbacks * @protocol: Which protocol to match * @reason: Callback reason index */ LWS_VISIBLE int lws_callback_all_protocol_vhost(struct lws_vhost *vh, const struct lws_protocols *protocol, int reason) { struct lws_context *context = vh->context; struct lws_context_per_thread *pt = &context->pt[0]; unsigned int n, m = context->count_threads; struct lws *wsi; while (m--) { for (n = 0; n < pt->fds_count; n++) { wsi = wsi_from_fd(context, pt->fds[n].fd); if (!wsi) continue; if (wsi->vhost == vh && wsi->protocol == protocol) protocol->callback(wsi, reason, wsi->user_space, NULL, 0); } pt++; } return 0; } #if LWS_POSIX /** * lws_get_socket_fd() - returns the socket file descriptor * * You will not need this unless you are doing something special * * @wsi: Websocket connection instance */ LWS_VISIBLE int lws_get_socket_fd(struct lws *wsi) { return wsi->sock; } #endif #ifdef LWS_LATENCY void lws_latency(struct lws_context *context, struct lws *wsi, const char *action, int ret, int completed) { unsigned long long u; char buf[256]; u = time_in_microseconds(); if (!action) { wsi->latency_start = u; if (!wsi->action_start) wsi->action_start = u; return; } if (completed) { if (wsi->action_start == wsi->latency_start) sprintf(buf, "Completion first try lat %lluus: %p: ret %d: %s\n", u - wsi->latency_start, (void *)wsi, ret, action); else sprintf(buf, "Completion %lluus: lat %lluus: %p: ret %d: %s\n", u - wsi->action_start, u - wsi->latency_start, (void *)wsi, ret, action); wsi->action_start = 0; } else sprintf(buf, "lat %lluus: %p: ret %d: %s\n", u - wsi->latency_start, (void *)wsi, ret, action); if (u - wsi->latency_start > context->worst_latency) { context->worst_latency = u - wsi->latency_start; strcpy(context->worst_latency_info, buf); } lwsl_latency("%s", buf); } #endif /** * lws_rx_flow_control() - Enable and disable socket servicing for * received packets. * * If the output side of a server process becomes choked, this allows flow * control for the input side. * * @wsi: Websocket connection instance to get callback for * @enable: 0 = disable read servicing for this connection, 1 = enable */ LWS_VISIBLE int lws_rx_flow_control(struct lws *wsi, int enable) { if (enable == (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) return 0; lwsl_info("%s: (0x%p, %d)\n", __func__, wsi, enable); wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !!enable; return 0; } /** * lws_rx_flow_allow_all_protocol() - Allow all connections with this protocol to receive * * When the user server code realizes it can accept more input, it can * call this to have the RX flow restriction removed from all connections using * the given protocol. * * @protocol: all connections using this protocol will be allowed to receive */ LWS_VISIBLE void lws_rx_flow_allow_all_protocol(const struct lws_context *context, const struct lws_protocols *protocol) { const struct lws_context_per_thread *pt = &context->pt[0]; struct lws *wsi; unsigned int n, m = context->count_threads; while (m--) { for (n = 0; n < pt->fds_count; n++) { wsi = wsi_from_fd(context, pt->fds[n].fd); if (!wsi) continue; if (wsi->protocol == protocol) lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW); } pt++; } } /** * lws_canonical_hostname() - returns this host's hostname * * This is typically used by client code to fill in the host parameter * when making a client connection. You can only call it after the context * has been created. * * @context: Websocket context */ LWS_VISIBLE extern const char * lws_canonical_hostname(struct lws_context *context) { return (const char *)context->canonical_hostname; } int user_callback_handle_rxflow(lws_callback_function callback_function, struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { int n; n = callback_function(wsi, reason, user, in, len); if (!n) n = _lws_rx_flow_control(wsi); return n; } /** * lws_set_proxy() - Setups proxy to lws_context. * @context: pointer to struct lws_context you want set proxy to * @proxy: pointer to c string containing proxy in format address:port * * Returns 0 if proxy string was parsed and proxy was setup. * Returns -1 if @proxy is NULL or has incorrect format. * * This is only required if your OS does not provide the http_proxy * environment variable (eg, OSX) * * IMPORTANT! You should call this function right after creation of the * lws_context and before call to connect. If you call this * function after connect behavior is undefined. * This function will override proxy settings made on lws_context * creation with genenv() call. */ LWS_VISIBLE int lws_set_proxy(struct lws_vhost *vhost, const char *proxy) { char *p; char authstring[96]; if (!proxy) return -1; p = strchr(proxy, '@'); if (p) { /* auth is around */ if ((unsigned int)(p - proxy) > sizeof(authstring) - 1) goto auth_too_long; strncpy(authstring, proxy, p - proxy); // null termination not needed on input if (lws_b64_encode_string(authstring, (p - proxy), vhost->proxy_basic_auth_token, sizeof vhost->proxy_basic_auth_token) < 0) goto auth_too_long; lwsl_notice(" Proxy auth in use\n"); proxy = p + 1; } else vhost->proxy_basic_auth_token[0] = '\0'; strncpy(vhost->http_proxy_address, proxy, sizeof(vhost->http_proxy_address) - 1); vhost->http_proxy_address[ sizeof(vhost->http_proxy_address) - 1] = '\0'; p = strchr(vhost->http_proxy_address, ':'); if (!p && !vhost->http_proxy_port) { lwsl_err("http_proxy needs to be ads:port\n"); return -1; } else { if (p) { *p = '\0'; vhost->http_proxy_port = atoi(p + 1); } } lwsl_notice(" Proxy %s:%u\n", vhost->http_proxy_address, vhost->http_proxy_port); return 0; auth_too_long: lwsl_err("proxy auth too long\n"); return -1; } /** * lws_get_protocol() - Returns a protocol pointer from a websocket * connection. * @wsi: pointer to struct websocket you want to know the protocol of * * * Some apis can act on all live connections of a given protocol, * this is how you can get a pointer to the active protocol if needed. */ LWS_VISIBLE const struct lws_protocols * lws_get_protocol(struct lws *wsi) { return wsi->protocol; } LWS_VISIBLE int lws_is_final_fragment(struct lws *wsi) { lwsl_info("%s: final %d, rx pk length %d, draining %d", __func__, wsi->u.ws.final, wsi->u.ws.rx_packet_length, wsi->u.ws.rx_draining_ext); return wsi->u.ws.final && !wsi->u.ws.rx_packet_length && !wsi->u.ws.rx_draining_ext; } LWS_VISIBLE unsigned char lws_get_reserved_bits(struct lws *wsi) { return wsi->u.ws.rsv; } int lws_ensure_user_space(struct lws *wsi) { lwsl_info("%s: %p protocol %p\n", __func__, wsi, wsi->protocol); if (!wsi->protocol) return 1; /* allocate the per-connection user memory (if any) */ if (wsi->protocol->per_session_data_size && !wsi->user_space) { wsi->user_space = lws_zalloc(wsi->protocol->per_session_data_size); if (wsi->user_space == NULL) { lwsl_err("Out of memory for conn user space\n"); return 1; } } else lwsl_info("%s: %p protocol pss %u, user_space=%d\n", __func__, wsi, wsi->protocol->per_session_data_size, wsi->user_space); return 0; } /** * lwsl_timestamp: generate logging timestamp string * * @level: logging level * @p: char * buffer to take timestamp * @len: length of p * * returns length written in p */ LWS_VISIBLE int lwsl_timestamp(int level, char *p, int len) { time_t o_now = time(NULL); unsigned long long now; struct tm *ptm = NULL; #ifndef WIN32 struct tm tm; #endif int n; #ifndef _WIN32_WCE #ifdef WIN32 ptm = localtime(&o_now); #else if (localtime_r(&o_now, &tm)) ptm = &tm; #endif #endif p[0] = '\0'; for (n = 0; n < LLL_COUNT; n++) { if (level != (1 << n)) continue; now = time_in_microseconds() / 100; if (ptm) n = lws_snprintf(p, len, "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(now % 10000), log_level_names[n]); else n = lws_snprintf(p, len, "[%llu:%04d] %s: ", (unsigned long long) now / 10000, (int)(now % 10000), log_level_names[n]); return n; } return 0; } LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line) { char buf[50]; lwsl_timestamp(level, buf, sizeof(buf)); fprintf(stderr, "%s%s", buf, line); } LWS_VISIBLE void _lws_logv(int filter, const char *format, va_list vl) { char buf[256]; if (!(log_level & filter)) return; vsnprintf(buf, sizeof(buf), format, vl); buf[sizeof(buf) - 1] = '\0'; lwsl_emit(filter, buf); } LWS_VISIBLE void _lws_log(int filter, const char *format, ...) { va_list ap; va_start(ap, format); _lws_logv(filter, format, ap); va_end(ap); } /** * lws_set_log_level() - Set the logging bitfield * @level: OR together the LLL_ debug contexts you want output from * @log_emit_function: NULL to leave it as it is, or a user-supplied * function to perform log string emission instead of * the default stderr one. * * log level defaults to "err", "warn" and "notice" contexts enabled and * emission on stderr. */ LWS_VISIBLE void lws_set_log_level(int level, void (*func)(int level, const char *line)) { log_level = level; if (func) lwsl_emit = func; } /** * lws_use_ssl() - Find out if connection is using SSL * @wsi: websocket connection to check * * Returns 0 if the connection is not using SSL, 1 if using SSL and * using verified cert, and 2 if using SSL but the cert was not * checked (appears for client wsi told to skip check on connection) */ LWS_VISIBLE int lws_is_ssl(struct lws *wsi) { #ifdef LWS_OPENSSL_SUPPORT return wsi->use_ssl; #else (void)wsi; return 0; #endif } /** * lws_partial_buffered() - find out if lws buffered the last write * @wsi: websocket connection to check * * Returns 1 if you cannot use lws_write because the last * write on this connection is still buffered, and can't be cleared without * returning to the service loop and waiting for the connection to be * writeable again. * * If you will try to do >1 lws_write call inside a single * WRITEABLE callback, you must check this after every write and bail if * set, ask for a new writeable callback and continue writing from there. * * This is never set at the start of a writeable callback, but any write * may set it. */ LWS_VISIBLE int lws_partial_buffered(struct lws *wsi) { return !!wsi->trunc_len; } void lws_set_protocol_write_pending(struct lws *wsi, enum lws_pending_protocol_send pend) { lwsl_info("setting pps %d\n", pend); if (wsi->pps) lwsl_err("pps overwrite\n"); wsi->pps = pend; lws_rx_flow_control(wsi, 0); lws_callback_on_writable(wsi); } LWS_VISIBLE size_t lws_get_peer_write_allowance(struct lws *wsi) { #ifdef LWS_USE_HTTP2 /* only if we are using HTTP2 on this connection */ if (wsi->mode != LWSCM_HTTP2_SERVING) return -1; /* user is only interested in how much he can send, or that he can't */ if (wsi->u.http2.tx_credit <= 0) return 0; return wsi->u.http2.tx_credit; #else (void)wsi; return -1; #endif } LWS_VISIBLE void lws_union_transition(struct lws *wsi, enum connection_mode mode) { lwsl_debug("%s: %p: mode %d\n", __func__, wsi, mode); memset(&wsi->u, 0, sizeof(wsi->u)); wsi->mode = mode; } LWS_VISIBLE struct lws_plat_file_ops * lws_get_fops(struct lws_context *context) { return &context->fops; } /** * lws_get_context - Allow geting lws_context from a Websocket connection * instance * * With this function, users can access context in the callback function. * Otherwise users may have to declare context as a global variable. * * @wsi: Websocket connection instance */ LWS_VISIBLE LWS_EXTERN struct lws_context * lws_get_context(const struct lws *wsi) { return wsi->context; } LWS_VISIBLE LWS_EXTERN int lws_get_count_threads(struct lws_context *context) { return context->count_threads; } LWS_VISIBLE LWS_EXTERN void * lws_wsi_user(struct lws *wsi) { return wsi->user_space; } LWS_VISIBLE LWS_EXTERN struct lws * lws_get_parent(const struct lws *wsi) { return wsi->parent; } LWS_VISIBLE LWS_EXTERN struct lws * lws_get_child(const struct lws *wsi) { return wsi->child_list; } LWS_VISIBLE LWS_EXTERN void lws_close_reason(struct lws *wsi, enum lws_close_status status, unsigned char *buf, size_t len) { unsigned char *p, *start; int budget = sizeof(wsi->u.ws.ping_payload_buf) - LWS_PRE; assert(wsi->mode == LWSCM_WS_SERVING || wsi->mode == LWSCM_WS_CLIENT); start = p = &wsi->u.ws.ping_payload_buf[LWS_PRE]; *p++ = (((int)status) >> 8) & 0xff; *p++ = ((int)status) & 0xff; if (buf) while (len-- && p < start + budget) *p++ = *buf++; wsi->u.ws.close_in_ping_buffer_len = p - start; } LWS_EXTERN int _lws_rx_flow_control(struct lws *wsi) { /* there is no pending change */ if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)) { lwsl_debug("%s: no pending change\n", __func__); return 0; } /* stuff is still buffered, not ready to really accept new input */ if (wsi->rxflow_buffer) { /* get ourselves called back to deal with stashed buffer */ lws_callback_on_writable(wsi); return 0; } /* pending is cleared, we can change rxflow state */ wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE; lwsl_info("rxflow: wsi %p change_to %d\n", wsi, wsi->rxflow_change_to & LWS_RXFLOW_ALLOW); /* adjust the pollfd for this wsi */ if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_info("%s: fail\n", __func__); return -1; } } else if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) return -1; return 0; } LWS_EXTERN int lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len) { static const unsigned char e0f4[] = { 0xa0 | ((2 - 1) << 2) | 1, /* e0 */ 0x80 | ((4 - 1) << 2) | 1, /* e1 */ 0x80 | ((4 - 1) << 2) | 1, /* e2 */ 0x80 | ((4 - 1) << 2) | 1, /* e3 */ 0x80 | ((4 - 1) << 2) | 1, /* e4 */ 0x80 | ((4 - 1) << 2) | 1, /* e5 */ 0x80 | ((4 - 1) << 2) | 1, /* e6 */ 0x80 | ((4 - 1) << 2) | 1, /* e7 */ 0x80 | ((4 - 1) << 2) | 1, /* e8 */ 0x80 | ((4 - 1) << 2) | 1, /* e9 */ 0x80 | ((4 - 1) << 2) | 1, /* ea */ 0x80 | ((4 - 1) << 2) | 1, /* eb */ 0x80 | ((4 - 1) << 2) | 1, /* ec */ 0x80 | ((2 - 1) << 2) | 1, /* ed */ 0x80 | ((4 - 1) << 2) | 1, /* ee */ 0x80 | ((4 - 1) << 2) | 1, /* ef */ 0x90 | ((3 - 1) << 2) | 2, /* f0 */ 0x80 | ((4 - 1) << 2) | 2, /* f1 */ 0x80 | ((4 - 1) << 2) | 2, /* f2 */ 0x80 | ((4 - 1) << 2) | 2, /* f3 */ 0x80 | ((1 - 1) << 2) | 2, /* f4 */ 0, /* s0 */ 0x80 | ((4 - 1) << 2) | 0, /* s2 */ 0x80 | ((4 - 1) << 2) | 1, /* s3 */ }; unsigned char s = *state; while (len--) { unsigned char c = *buf++; if (!s) { if (c >= 0x80) { if (c < 0xc2 || c > 0xf4) return 1; if (c < 0xe0) s = 0x80 | ((4 - 1) << 2); else s = e0f4[c - 0xe0]; } } else { if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30)) return 1; s = e0f4[21 + (s & 3)]; } } *state = s; return 0; } /** * lws_parse_uri: cut up prot:/ads:port/path into pieces * Notice it does so by dropping '\0' into input string * and the leading / on the path is consequently lost * * @p: incoming uri string.. will get written to * @prot: result pointer for protocol part (https://) * @ads: result pointer for address part * @port: result pointer for port part * @path: result pointer for path part */ LWS_VISIBLE LWS_EXTERN int lws_parse_uri(char *p, const char **prot, const char **ads, int *port, const char **path) { const char *end; static const char *slash = "/"; /* cut up the location into address, port and path */ *prot = p; while (*p && (*p != ':' || p[1] != '/' || p[2] != '/')) p++; if (!*p) { end = p; p = (char *)*prot; *prot = end; } else { *p = '\0'; p += 3; } *ads = p; if (!strcmp(*prot, "http") || !strcmp(*prot, "ws")) *port = 80; else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss")) *port = 443; while (*p && *p != ':' && *p != '/') p++; if (*p == ':') { *p++ = '\0'; *port = atoi(p); while (*p && *p != '/') p++; } *path = slash; if (*p) { *p++ = '\0'; if (*p) *path = p; } return 0; } #ifdef LWS_NO_EXTENSIONS /* we need to provide dummy callbacks for internal exts * so user code runs when faced with a lib compiled with * extensions disabled. */ int lws_extension_callback_pm_deflate(struct lws_context *context, const struct lws_extension *ext, struct lws *wsi, enum lws_extension_callback_reasons reason, void *user, void *in, size_t len) { (void)context; (void)ext; (void)wsi; (void)reason; (void)user; (void)in; (void)len; return 0; } #endif LWS_EXTERN int lws_socket_bind(struct lws_vhost *vhost, int sockfd, int port, const char *iface) { #if LWS_POSIX #ifdef LWS_USE_UNIX_SOCK struct sockaddr_un serv_unix; #endif #ifdef LWS_USE_IPV6 struct sockaddr_in6 serv_addr6; #endif struct sockaddr_in serv_addr4; socklen_t len = sizeof(struct sockaddr); int n; struct sockaddr_in sin; struct sockaddr *v; #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(vhost)) { v = (struct sockaddr *)&serv_unix; n = sizeof(struct sockaddr_un); bzero((char *) &serv_unix, sizeof(serv_unix)); serv_unix.sun_family = AF_UNIX; if (sizeof(serv_unix.sun_path) <= strlen(iface)) { lwsl_err("\"%s\" too long for UNIX domain socket\n", iface); return -1; } strcpy(serv_unix.sun_path, iface); if (serv_unix.sun_path[0] == '@') serv_unix.sun_path[0] = '\0'; } else #endif #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(vhost->context)) { v = (struct sockaddr *)&serv_addr6; n = sizeof(struct sockaddr_in6); bzero((char *) &serv_addr6, sizeof(serv_addr6)); serv_addr6.sin6_addr = in6addr_any; serv_addr6.sin6_family = AF_INET6; serv_addr6.sin6_port = htons(port); } else #endif { v = (struct sockaddr *)&serv_addr4; n = sizeof(serv_addr4); bzero((char *) &serv_addr4, sizeof(serv_addr4)); serv_addr4.sin_addr.s_addr = INADDR_ANY; serv_addr4.sin_family = AF_INET; if (iface && interface_to_sa(vhost->context, iface, (struct sockaddr_in *)v, n) < 0) { lwsl_err("Unable to find interface %s\n", iface); return -1; } serv_addr4.sin_port = htons(port); } /* ipv4 */ n = bind(sockfd, v, n); #ifdef LWS_USE_UNIX_SOCK if (n < 0 && LWS_UNIX_SOCK_ENABLED(vhost)) { lwsl_err("ERROR on binding fd %d to \"%s\" (%d %d)\n", sockfd, iface, n, LWS_ERRNO); return -1; } else #endif if (n < 0) { lwsl_err("ERROR on binding fd %d to port %d (%d %d)\n", sockfd, port, n, LWS_ERRNO); return -1; } if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1) lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO)); else port = ntohs(sin.sin_port); #endif return port; } LWS_VISIBLE LWS_EXTERN int lws_urlencode(const char *in, int inlen, char *out, int outlen) { const char *hex = "0123456789ABCDEF"; char *start = out, *end = out + outlen; while (inlen-- && out < end - 4) { if ((*in >= 'A' && *in <= 'Z') || (*in >= 'a' && *in <= 'z') || (*in >= '0' && *in <= '9') || *in == '-' || *in == '_' || *in == '.' || *in == '~') *out++ = *in++; else { *out++ = '%'; *out++ = hex[(*in) >> 4]; *out++ = hex[(*in++) & 15]; } } *out = '\0'; if (out >= end - 4) return -1; return out - start; } LWS_VISIBLE LWS_EXTERN int lws_finalize_startup(struct lws_context *context) { struct lws_context_creation_info info; info.uid = context->uid; info.gid = context->gid; if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) lws_plat_drop_app_privileges(&info); return 0; } int lws_snprintf(char *str, size_t size, const char *format, ...) { va_list ap; int n; if (!size) return 0; va_start(ap, format); n = vsnprintf(str, size, format, ap); va_end(ap); if (n >= size) return size; return n; } LWS_VISIBLE LWS_EXTERN int lws_is_cgi(struct lws *wsi) { #ifdef LWS_WITH_CGI return !!wsi->cgi; #else return 0; #endif } #ifdef LWS_WITH_CGI static struct lws * lws_create_basic_wsi(struct lws_context *context, int tsi) { struct lws *new_wsi; if ((unsigned int)context->pt[tsi].fds_count == context->fd_limit_per_thread - 1) { lwsl_err("no space for new conn\n"); return NULL; } new_wsi = lws_zalloc(sizeof(struct lws)); if (new_wsi == NULL) { lwsl_err("Out of memory for new connection\n"); return NULL; } new_wsi->tsi = tsi; new_wsi->context = context; new_wsi->pending_timeout = NO_PENDING_TIMEOUT; new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; /* intialize the instance struct */ new_wsi->state = LWSS_CGI; new_wsi->mode = LWSCM_CGI; new_wsi->hdr_parsing_completed = 0; new_wsi->position_in_fds_table = -1; /* * these can only be set once the protocol is known * we set an unestablished connection's protocol pointer * to the start of the defauly vhost supported list, so it can look * for matching ones during the handshake */ new_wsi->protocol = context->vhost_list->protocols; new_wsi->user_space = NULL; new_wsi->ietf_spec_revision = 0; new_wsi->sock = LWS_SOCK_INVALID; context->count_wsi_allocated++; return new_wsi; } /** * lws_cgi: spawn network-connected cgi process * * @wsi: connection to own the process * @exec_array: array of "exec-name" "arg1" ... "argn" NULL */ LWS_VISIBLE LWS_EXTERN int lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len, int timeout_secs, const struct lws_protocol_vhost_options *mp_cgienv) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; char *env_array[30], cgi_path[400], e[1024], *p = e, *end = p + sizeof(e) - 1, tok[256], *t; struct lws_cgi *cgi; int n, m, i, uritok = WSI_TOKEN_GET_URI; /* * give the master wsi a cgi struct */ wsi->cgi = lws_zalloc(sizeof(*wsi->cgi)); if (!wsi->cgi) { lwsl_err("%s: OOM\n", __func__); return -1; } cgi = wsi->cgi; cgi->wsi = wsi; /* set cgi's owning wsi */ /* create pipes for [stdin|stdout] and [stderr] */ for (n = 0; n < 3; n++) if (pipe(cgi->pipe_fds[n]) == -1) goto bail1; /* create cgi wsis for each stdin/out/err fd */ for (n = 0; n < 3; n++) { cgi->stdwsi[n] = lws_create_basic_wsi(wsi->context, wsi->tsi); if (!cgi->stdwsi[n]) goto bail2; cgi->stdwsi[n]->cgi_channel = n; cgi->stdwsi[n]->vhost = wsi->vhost; // lwsl_err("%s: cgi %p: pipe fd %d -> fd %d / %d\n", __func__, wsi, n, // cgi->pipe_fds[n][!!(n == 0)], cgi->pipe_fds[n][!(n == 0)]); /* read side is 0, stdin we want the write side, others read */ cgi->stdwsi[n]->sock = cgi->pipe_fds[n][!!(n == 0)]; if (fcntl(cgi->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK) < 0) { lwsl_err("%s: setting NONBLOCK failed\n", __func__); goto bail2; } } for (n = 0; n < 3; n++) { lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->sock); if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n])) goto bail3; cgi->stdwsi[n]->parent = wsi; cgi->stdwsi[n]->sibling_list = wsi->child_list; wsi->child_list = cgi->stdwsi[n]; } lws_change_pollfd(cgi->stdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT); lws_change_pollfd(cgi->stdwsi[LWS_STDOUT], LWS_POLLOUT, LWS_POLLIN); lws_change_pollfd(cgi->stdwsi[LWS_STDERR], LWS_POLLOUT, LWS_POLLIN); lwsl_debug("%s: fds in %d, out %d, err %d\n", __func__, cgi->stdwsi[LWS_STDIN]->sock, cgi->stdwsi[LWS_STDOUT]->sock, cgi->stdwsi[LWS_STDERR]->sock); lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs); /* the cgi stdout is always sending us http1.x header data first */ wsi->hdr_state = LCHS_HEADER; /* add us to the pt list of active cgis */ lwsl_debug("%s: adding cgi %p to list\n", __func__, wsi->cgi); cgi->cgi_list = pt->cgi_list; pt->cgi_list = cgi; /* prepare his CGI env */ n = 0; if (lws_is_ssl(wsi)) env_array[n++] = "HTTPS=ON"; if (wsi->u.hdr.ah) { if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) uritok = WSI_TOKEN_POST_URI; lws_snprintf(cgi_path, sizeof(cgi_path) - 1, "REQUEST_URI=%s", lws_hdr_simple_ptr(wsi, uritok)); cgi_path[sizeof(cgi_path) - 1] = '\0'; env_array[n++] = cgi_path; if (uritok == WSI_TOKEN_POST_URI) env_array[n++] = "REQUEST_METHOD=POST"; else env_array[n++] = "REQUEST_METHOD=GET"; env_array[n++] = p; p += lws_snprintf(p, end - p, "QUERY_STRING="); /* dump the individual URI Arg parameters */ m = 0; while (1) { i = lws_hdr_copy_fragment(wsi, tok, sizeof(tok), WSI_TOKEN_HTTP_URI_ARGS, m); if (i < 0) break; t = tok; while (*t && *t != '=' && p < end - 4) *p++ = *t++; if (*t == '=') *p++ = *t++; i = lws_urlencode(t, i- (t - tok), p, end - p); if (i > 0) { p += i; *p++ = '&'; } m++; } if (m) p--; *p++ = '\0'; env_array[n++] = p; p += lws_snprintf(p, end - p, "PATH_INFO=%s", lws_hdr_simple_ptr(wsi, uritok) + script_uri_path_len); p++; } if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "HTTP_REFERER=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER)); p++; } if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "HTTP_HOST=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); p++; } if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "HTTP_COOKIE=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE)); p++; } if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "USER_AGENT=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT)); p++; } if (uritok == WSI_TOKEN_POST_URI) { if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "CONTENT_TYPE=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)); p++; } if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "CONTENT_LENGTH=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)); p++; } } env_array[n++] = p; p += lws_snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]) + 1; while (mp_cgienv) { env_array[n++] = p; p += lws_snprintf(p, end - p, "%s=%s", mp_cgienv->name, mp_cgienv->value); lwsl_debug(" Applying mount-specific cgi env '%s'\n", env_array[n - 1]); p++; mp_cgienv = mp_cgienv->next; } env_array[n++] = "SERVER_SOFTWARE=libwebsockets"; env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin"; env_array[n] = NULL; #if 0 for (m = 0; m < n; m++) lwsl_err(" %s\n", env_array[m]); #endif /* * Actually having made the env, as a cgi we don't need the ah * any more */ if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen) lws_header_table_detach(wsi, 0); /* we are ready with the redirection pipes... run the thing */ #if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE) cgi->pid = fork(); #else cgi->pid = vfork(); #endif if (cgi->pid < 0) { lwsl_err("fork failed, errno %d", errno); goto bail3; } #if defined(__linux__) prctl(PR_SET_PDEATHSIG, SIGTERM); #endif setpgrp(); if (cgi->pid) { /* we are the parent process */ wsi->context->count_cgi_spawned++; lwsl_debug("%s: cgi %p spawned PID %d\n", __func__, cgi, cgi->pid); return 0; } /* somewhere we can at least read things and enter it */ if (chdir("/tmp")) lwsl_notice("%s: Failed to chdir\n", __func__); /* We are the forked process, redirect and kill inherited things. * * Because of vfork(), we cannot do anything that changes pages in * the parent environment. Stuff that changes kernel state for the * process is OK. Stuff that happens after the execvpe() is OK. */ for (n = 0; n < 3; n++) if (dup2(cgi->pipe_fds[n][!(n == 0)], n) < 0) { lwsl_err("%s: stdin dup2 failed\n", __func__); goto bail3; } #if !defined(LWS_HAVE_VFORK) || !defined(LWS_HAVE_EXECVPE) for (m = 0; m < n; m++) { p = strchr(env_array[m], '='); *p++ = '\0'; setenv(env_array[m], p, 1); } execvp(exec_array[0], (char * const *)&exec_array[0]); #else execvpe(exec_array[0], (char * const *)&exec_array[0], &env_array[0]); #endif exit(1); bail3: /* drop us from the pt cgi list */ pt->cgi_list = cgi->cgi_list; while (--n >= 0) remove_wsi_socket_from_fds(wsi->cgi->stdwsi[n]); bail2: for (n = 0; n < 3; n++) if (wsi->cgi->stdwsi[n]) lws_free_wsi(cgi->stdwsi[n]); bail1: for (n = 0; n < 3; n++) { if (cgi->pipe_fds[n][0]) close(cgi->pipe_fds[n][0]); if (cgi->pipe_fds[n][1]) close(cgi->pipe_fds[n][1]); } lws_free_set_NULL(wsi->cgi); lwsl_err("%s: failed\n", __func__); return -1; } /** * lws_cgi_write_split_headers: write cgi output accounting for header part * * @wsi: connection to own the process */ LWS_VISIBLE LWS_EXTERN int lws_cgi_write_split_stdout_headers(struct lws *wsi) { int n, m, match = 0, lp = 0; static const char * const content_length = "content-length: "; char buf[LWS_PRE + 1024], *start = &buf[LWS_PRE], *p = start, *end = &buf[sizeof(buf) - 1 - LWS_PRE], c, l[12]; if (!wsi->cgi) return -1; while (wsi->hdr_state != LHCS_PAYLOAD) { /* we have to separate header / finalize and * payload chunks, since they need to be * handled separately */ n = read(lws_get_socket_fd(wsi->cgi->stdwsi[LWS_STDOUT]), &c, 1); if (n < 0) { if (errno != EAGAIN) { lwsl_debug("%s: read says %d\n", __func__, n); return -1; } else n = 0; } if (n) { lwsl_debug("-- 0x%02X %c\n", (unsigned char)c, c); switch (wsi->hdr_state) { case LCHS_HEADER: if (!content_length[match] && (c >= '0' && c <= '9') && lp < sizeof(l) - 1) { l[lp++] = c; l[lp] = '\0'; wsi->cgi->content_length = atol(l); } if (tolower(c) == content_length[match]) match++; else match = 0; /* some cgi only send us \x0a for EOL */ if (c == '\x0a') { wsi->hdr_state = LCHS_SINGLE_0A; *p++ = '\x0d'; } *p++ = c; if (c == '\x0d') { wsi->hdr_state = LCHS_LF1; break; } break; case LCHS_LF1: *p++ = c; if (c == '\x0a') { wsi->hdr_state = LCHS_CR2; break; } /* we got \r[^\n]... it's unreasonable */ lwsl_debug("%s: funny CRLF 0x%02X\n", __func__, (unsigned char)c); return -1; case LCHS_CR2: if (c == '\x0d') { /* drop the \x0d */ wsi->hdr_state = LCHS_LF2; break; } wsi->hdr_state = LCHS_HEADER; match = 0; *p++ = c; break; case LCHS_LF2: case LCHS_SINGLE_0A: m = wsi->hdr_state; if (c == '\x0a') { lwsl_debug("Content-Length: %ld\n", wsi->cgi->content_length); wsi->hdr_state = LHCS_PAYLOAD; /* drop the \0xa ... finalize will add it if needed */ if (lws_finalize_http_header(wsi, (unsigned char **)&p, (unsigned char *)end)) return -1; break; } if (m == LCHS_LF2) /* we got \r\n\r[^\n]... it's unreasonable */ return -1; /* we got \x0anext header, it's reasonable */ *p++ = c; wsi->hdr_state = LCHS_HEADER; break; case LHCS_PAYLOAD: break; } } /* ran out of input, ended the headers, or filled up the headers buf */ if (!n || wsi->hdr_state == LHCS_PAYLOAD || (p + 4) == end) { m = lws_write(wsi, (unsigned char *)start, p - start, LWS_WRITE_HTTP_HEADERS); if (m < 0) { lwsl_debug("%s: write says %d\n", __func__, m); return -1; } /* writeability becomes uncertain now we wrote * something, we must return to the event loop */ return 0; } } n = read(lws_get_socket_fd(wsi->cgi->stdwsi[LWS_STDOUT]), start, sizeof(buf) - LWS_PRE); if (n < 0 && errno != EAGAIN) { lwsl_debug("%s: stdout read says %d\n", __func__, n); return -1; } if (n > 0) { m = lws_write(wsi, (unsigned char *)start, n, LWS_WRITE_HTTP); //lwsl_notice("write %d\n", m); if (m < 0) { lwsl_debug("%s: stdout write says %d\n", __func__, m); return -1; } wsi->cgi->content_length_seen += m; } return 0; } /** * lws_cgi_kill: terminate cgi process associated with wsi * * @wsi: connection to own the process */ LWS_VISIBLE LWS_EXTERN int lws_cgi_kill(struct lws *wsi) { struct lws_cgi_args args; int status, n; lwsl_debug("%s: %p\n", __func__, wsi); if (!wsi->cgi) return 0; if (wsi->cgi->pid > 0) { n = waitpid(wsi->cgi->pid, &status, WNOHANG); if (n > 0) { lwsl_debug("%s: PID %d reaped\n", __func__, wsi->cgi->pid); goto handled; } /* kill the process group */ n = kill(-wsi->cgi->pid, SIGTERM); lwsl_debug("%s: SIGTERM child PID %d says %d (errno %d)\n", __func__, wsi->cgi->pid, n, errno); if (n < 0) { /* * hum seen errno=3 when process is listed in ps, * it seems we don't always retain process grouping * * Direct these fallback attempt to the exact child */ n = kill(wsi->cgi->pid, SIGTERM); if (n < 0) { n = kill(wsi->cgi->pid, SIGPIPE); if (n < 0) { n = kill(wsi->cgi->pid, SIGKILL); if (n < 0) lwsl_err("%s: SIGKILL PID %d failed errno %d (maybe zombie)\n", __func__, wsi->cgi->pid, errno); } } } /* He could be unkillable because he's a zombie */ n = 1; while (n > 0) { n = waitpid(-wsi->cgi->pid, &status, WNOHANG); if (n > 0) lwsl_debug("%s: reaped PID %d\n", __func__, n); if (n <= 0) { n = waitpid(wsi->cgi->pid, &status, WNOHANG); if (n > 0) lwsl_debug("%s: reaped PID %d\n", __func__, n); } } } handled: args.stdwsi = &wsi->cgi->stdwsi[0]; if (wsi->cgi->pid != -1 && user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_CGI_TERMINATED, wsi->user_space, (void *)&args, 0)) { wsi->cgi->pid = -1; if (!wsi->cgi->being_closed) lws_close_free_wsi(wsi, 0); } return 0; } LWS_EXTERN int lws_cgi_kill_terminated(struct lws_context_per_thread *pt) { struct lws_cgi **pcgi, *cgi = NULL; int status, n = 1; while (n > 0) { /* find finished guys but don't reap yet */ n = waitpid(-1, &status, WNOHANG | WNOWAIT); if (n <= 0) continue; lwsl_debug("%s: observed PID %d terminated\n", __func__, n); pcgi = &pt->cgi_list; /* check all the subprocesses on the cgi list */ while (*pcgi) { /* get the next one first as list may change */ cgi = *pcgi; pcgi = &(*pcgi)->cgi_list; if (cgi->pid <= 0) continue; /* wait for stdout to be drained */ if (cgi->content_length > cgi->content_length_seen) continue; if (cgi->content_length) { lwsl_debug("%s: wsi %p: expected content length seen: %ld\n", __func__, cgi->wsi, cgi->content_length_seen); } /* reap it */ waitpid(n, &status, WNOHANG); /* * he's already terminated so no need for kill() * but we should do the terminated cgi callback * and close him if he's not already closing */ if (n == cgi->pid) { lwsl_debug("%s: found PID %d on cgi list\n", __func__, n); /* defeat kill() */ cgi->pid = 0; lws_cgi_kill(cgi->wsi); break; } cgi = NULL; } /* if not found on the cgi list, as he's one of ours, reap */ if (!cgi) { lwsl_debug("%s: reading PID %d although no cgi match\n", __func__, n); waitpid(n, &status, WNOHANG); } } /* disable this to confirm timeout cgi cleanup flow */ #if 1 pcgi = &pt->cgi_list; /* check all the subprocesses on the cgi list */ while (*pcgi) { /* get the next one first as list may change */ cgi = *pcgi; pcgi = &(*pcgi)->cgi_list; if (cgi->pid <= 0) continue; /* wait for stdout to be drained */ if (cgi->content_length > cgi->content_length_seen) continue; if (cgi->content_length) { lwsl_debug("%s: wsi %p: expected content length seen: %ld\n", __func__, cgi->wsi, cgi->content_length_seen); } /* reap it */ if (waitpid(cgi->pid, &status, WNOHANG) > 0) { lwsl_debug("%s: found PID %d on cgi list\n", __func__, cgi->pid); /* defeat kill() */ cgi->pid = 0; lws_cgi_kill(cgi->wsi); break; } } #endif /* general anti zombie defence */ n = waitpid(-1, &status, WNOHANG); if (n > 0) lwsl_notice("%s: anti-zombie wait says %d\n", __func__, n); return 0; } #endif #ifdef LWS_NO_EXTENSIONS LWS_EXTERN int lws_set_extension_option(struct lws *wsi, const char *ext_name, const char *opt_name, const char *opt_val) { return -1; } #endif #ifdef LWS_WITH_ACCESS_LOG int lws_access_log(struct lws *wsi) { char *p = wsi->access_log.user_agent, ass[512]; int l; if (!wsi->access_log_pending) return 0; if (!wsi->access_log.header_log) return 0; if (!p) p = ""; l = lws_snprintf(ass, sizeof(ass) - 1, "%s %d %lu %s\n", wsi->access_log.header_log, wsi->access_log.response, wsi->access_log.sent, p); if (wsi->vhost->log_fd != LWS_INVALID_FILE) { if (write(wsi->vhost->log_fd, ass, l) != l) lwsl_err("Failed to write log\n"); } else lwsl_err("%s", ass); if (wsi->access_log.header_log) { lws_free(wsi->access_log.header_log); wsi->access_log.header_log = NULL; } if (wsi->access_log.user_agent) { lws_free(wsi->access_log.user_agent); wsi->access_log.user_agent = NULL; } wsi->access_log_pending = 0; return 0; } #endif #ifdef LWS_WITH_SERVER_STATUS LWS_EXTERN int lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len) { static const char * const prots[] = { "http://", "https://", "file://", "cgi://", ">http://", ">https://", }; char *orig = buf, *end = buf + len - 1, first = 1; int n = 0; if (len < 100) return 0; buf += lws_snprintf(buf, end - buf, "{\n \"name\":\"%s\",\n" " \"port\":\"%d\",\n" " \"use_ssl\":\"%d\",\n" " \"sts\":\"%d\",\n" " \"rx\":\"%llu\",\n" " \"tx\":\"%llu\",\n" " \"conn\":\"%lu\",\n" " \"trans\":\"%lu\",\n" " \"ws_upg\":\"%lu\",\n" " \"http2_upg\":\"%lu\"" , vh->name, vh->listen_port, #ifdef LWS_OPENSSL_SUPPORT vh->use_ssl, #else 0, #endif !!(vh->options & LWS_SERVER_OPTION_STS), vh->rx, vh->tx, vh->conn, vh->trans, vh->ws_upgrades, vh->http2_upgrades ); if (vh->mount_list) { const struct lws_http_mount *m = vh->mount_list; buf += lws_snprintf(buf, end - buf, ",\n \"mounts\":["); while (m) { if (!first) buf += lws_snprintf(buf, end - buf, ","); buf += lws_snprintf(buf, end - buf, "\n {\n \"mountpoint\":\"%s\",\n" " \"origin\":\"%s%s\",\n" " \"cache_max_age\":\"%d\",\n" " \"cache_reuse\":\"%d\",\n" " \"cache_revalidate\":\"%d\",\n" " \"cache_intermediaries\":\"%d\"\n" , m->mountpoint, prots[m->origin_protocol], m->origin, m->cache_max_age, m->cache_reusable, m->cache_revalidate, m->cache_intermediaries); if (m->def) buf += lws_snprintf(buf, end - buf, ",\n \"default\":\"%s\"", m->def); buf += lws_snprintf(buf, end - buf, "\n }"); first = 0; m = m->mount_next; } buf += lws_snprintf(buf, end - buf, "\n ]"); } if (vh->protocols) { n = 0; first = 1; buf += lws_snprintf(buf, end - buf, ",\n \"ws-protocols\":["); while (n < vh->count_protocols) { if (!first) buf += lws_snprintf(buf, end - buf, ","); buf += lws_snprintf(buf, end - buf, "\n {\n \"%s\":\{\n" " \"status\":\"ok\"\n }\n }" , vh->protocols[n].name); first = 0; n++; } buf += lws_snprintf(buf, end - buf, "\n ]"); } buf += lws_snprintf(buf, end - buf, "\n}"); return buf - orig; } LWS_EXTERN LWS_VISIBLE int lws_json_dump_context(const struct lws_context *context, char *buf, int len) { char *orig = buf, *end = buf + len - 1, first = 1; const struct lws_vhost *vh = context->vhost_list; #ifdef LWS_WITH_CGI struct lws_cgi * const *pcgi; #endif const struct lws_context_per_thread *pt; time_t t = time(NULL); int listening = 0, cgi_count = 0, n; buf += lws_snprintf(buf, end - buf, "{ " "\"version\":\"%s\",\n" "\"uptime\":\"%ld\",\n" "\"cgi_spawned\":\"%d\",\n" "\"pt_fd_max\":\"%d\",\n" "\"ah_pool_max\":\"%d\",\n" "\"wsi_alive\":\"%d\",\n", lws_get_library_version(), (unsigned long)(t - context->time_up), context->count_cgi_spawned, context->fd_limit_per_thread, context->max_http_header_pool, context->count_wsi_allocated); #ifdef LWS_HAVE_GETLOADAVG { double d[3]; int m; m = getloadavg(d, 3); for (n = 0; n < m; n++) { buf += lws_snprintf(buf, end - buf, "\"l%d\":\"%.2f\",\n", n + 1, d[n]); } } #endif buf += lws_snprintf(buf, end - buf, "\"pt\":[\n "); for (n = 0; n < context->count_threads; n++) { pt = &context->pt[n]; if (n) buf += lws_snprintf(buf, end - buf, ","); buf += lws_snprintf(buf, end - buf, "\n {\n" " \"fds_count\":\"%d\",\n" " \"ah_pool_inuse\":\"%d\",\n" " \"ah_wait_list\":\"%d\"\n" " }", pt->fds_count, pt->ah_count_in_use, pt->ah_wait_list_length); } buf += lws_snprintf(buf, end - buf, "], \"vhosts\":[\n "); while (vh) { if (!first) if(buf != end) *buf++ = ','; buf += lws_json_dump_vhost(vh, buf, end - buf); first = 0; if (vh->lserv_wsi) listening++; vh = vh->vhost_next; } buf += lws_snprintf(buf, end - buf, "],\n\"listen_wsi\":\"%d\"", listening); #ifdef LWS_WITH_CGI for (n = 0; n < context->count_threads; n++) { pt = &context->pt[n]; pcgi = &pt->cgi_list; while (*pcgi) { pcgi = &(*pcgi)->cgi_list; cgi_count++; } } #endif buf += lws_snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ", cgi_count); buf += lws_snprintf(buf, end - buf, "}\n "); return buf - orig; } #endif |
Added undroid/libwebsockets/lib/libwebsockets.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #ifndef LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C #define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C #ifdef __cplusplus #include <cstddef> #include <cstdarg> #ifdef MBED_OPERATORS #include "mbed-drivers/mbed.h" #include "sal-iface-eth/EthernetInterface.h" #include "sockets/TCPListener.h" #include "sal-stack-lwip/lwipv4_init.h" namespace { } using namespace mbed::Sockets::v0; struct sockaddr_in; struct lws; class lws_conn { public: lws_conn(): ts(NULL), wsi(NULL), writeable(1), awaiting_on_writeable(0) { } public: void set_wsi(struct lws *_wsi) { wsi = _wsi; } int actual_onRX(Socket *s); void onRX(Socket *s); void onError(Socket *s, socket_error_t err); void onDisconnect(TCPStream *s); void onSent(Socket *s, uint16_t len); void serialized_writeable(struct lws *wsi); public: TCPStream *ts; public: struct lws *wsi; char writeable; char awaiting_on_writeable; }; class lws_conn_listener : lws_conn { public: lws_conn_listener(): srv(SOCKET_STACK_LWIP_IPV4) { srv.setOnError(TCPStream::ErrorHandler_t(this, &lws_conn_listener::onError)); } void start(const uint16_t port); protected: void onRX(Socket *s); void onError(Socket *s, socket_error_t err); void onIncoming(TCPListener *s, void *impl); void onDisconnect(TCPStream *s); public: TCPListener srv; }; #endif extern "C" { #else #include <stdarg.h> #endif #ifdef MBED_OPERATORS struct sockaddr_in; #define LWS_POSIX 0 #else #define LWS_POSIX 1 #endif #include "lws_config.h" #if defined(WIN32) || defined(_WIN32) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <winsock2.h> #include <ws2tcpip.h> #include <stddef.h> #include <basetsd.h> #ifndef _WIN32_WCE #include <fcntl.h> #else #define _O_RDONLY 0x0000 #define O_RDONLY _O_RDONLY #endif // Visual studio older than 2015 and WIN_CE has only _stricmp #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE) #define strcasecmp _stricmp #else #define strcasecmp stricmp #endif #define getdtablesize() 30000 #define LWS_INLINE __inline #define LWS_VISIBLE #define LWS_WARN_UNUSED_RESULT #define LWS_WARN_DEPRECATED #ifdef LWS_DLL #ifdef LWS_INTERNAL #define LWS_EXTERN extern __declspec(dllexport) #else #define LWS_EXTERN extern __declspec(dllimport) #endif #else #define LWS_EXTERN #endif #define LWS_INVALID_FILE INVALID_HANDLE_VALUE #define LWS_O_RDONLY _O_RDONLY #if !defined(_MSC_VER) || _MSC_VER < 1900 /* Visual Studio 2015 already defines this in <stdio.h> */ #define lws_snprintf _snprintf #endif #ifndef __func__ #define __func__ __FUNCTION__ #endif #else /* NOT WIN32 */ #include <unistd.h> #if defined(__NetBSD__) || defined(__FreeBSD__) #include <netinet/in.h> #endif #define LWS_INLINE inline #define LWS_O_RDONLY O_RDONLY #ifndef MBED_OPERATORS #include <poll.h> #include <netdb.h> #define LWS_INVALID_FILE -1 #else #define getdtablesize() (20) #define LWS_INVALID_FILE NULL #endif #if defined(__GNUC__) /* warn_unused_result attribute only supported by GCC 3.4 or later */ #if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) #define LWS_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define LWS_WARN_UNUSED_RESULT #endif #define LWS_VISIBLE __attribute__((visibility("default"))) #define LWS_WARN_DEPRECATED __attribute__ ((deprecated)) #else #define LWS_VISIBLE #define LWS_WARN_UNUSED_RESULT #define LWS_WARN_DEPRECATED #endif #if defined(__ANDROID__) #include <unistd.h> #define getdtablesize() sysconf(_SC_OPEN_MAX) #endif #endif #ifdef LWS_USE_LIBEV #include <ev.h> #endif /* LWS_USE_LIBEV */ #ifdef LWS_USE_LIBUV #include <uv.h> #endif /* LWS_USE_LIBUV */ #ifndef LWS_EXTERN #define LWS_EXTERN extern #endif #ifdef _WIN32 #define random rand #else #include <sys/time.h> #include <unistd.h> #endif #ifdef LWS_OPENSSL_SUPPORT #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL #include <cyassl/openssl/ssl.h> #include <cyassl/error-ssl.h> #else #include <wolfssl/openssl/ssl.h> #include <wolfssl/error-ssl.h> #endif /* not USE_OLD_CYASSL */ #else #if defined(LWS_USE_POLARSSL) #include <polarssl/ssl.h> struct lws_polarssl_context { x509_crt ca; x509_crt certificate; rsa_context key; }; typedef struct lws_polarssl_context SSL_CTX; typedef ssl_context SSL; #else #if defined(LWS_USE_MBEDTLS) #include <mbedtls/ssl.h> #else #include <openssl/ssl.h> #include <openssl/err.h> #endif /* not USE_MBEDTLS */ #endif /* not USE_POLARSSL */ #endif /* not USE_WOLFSSL */ #endif #define CONTEXT_PORT_NO_LISTEN -1 enum lws_log_levels { LLL_ERR = 1 << 0, LLL_WARN = 1 << 1, LLL_NOTICE = 1 << 2, LLL_INFO = 1 << 3, LLL_DEBUG = 1 << 4, LLL_PARSER = 1 << 5, LLL_HEADER = 1 << 6, LLL_EXT = 1 << 7, LLL_CLIENT = 1 << 8, LLL_LATENCY = 1 << 9, LLL_COUNT = 10 /* set to count of valid flags */ }; LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl); LWS_VISIBLE LWS_EXTERN int lwsl_timestamp(int level, char *p, int len); /* notice, warn and log are always compiled in */ #define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) #define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) #define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) /* * weaker logging can be deselected at configure time using --disable-debug * that gets rid of the overhead of checking while keeping _warn and _err * active */ #ifdef _DEBUG #define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) #define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) #define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) #define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) #define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) #define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) #define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); #else /* no debug */ #define lwsl_info(...) {} #define lwsl_debug(...) {} #define lwsl_parser(...) {} #define lwsl_header(...) {} #define lwsl_ext(...) {} #define lwsl_client(...) {} #define lwsl_latency(...) {} #define lwsl_hexdump(a, b) #endif #include <stddef.h> #ifndef lws_container_of #define lws_container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M))) #endif struct lws; #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif /* api change list for user code to test against */ #define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG /* the struct lws_protocols has the id field present */ #define LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD /* you can call lws_get_peer_write_allowance */ #define LWS_FEATURE_PROTOCOLS_HAS_PEER_WRITE_ALLOWANCE /* extra parameter introduced in 917f43ab821 */ #define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_LEN /* File operations stuff exists */ #define LWS_FEATURE_FOPS /* * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum lws_context_options { LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = (1 << 1) | (1 << 12), LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = (1 << 2), LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = (1 << 3) | (1 << 12), LWS_SERVER_OPTION_LIBEV = (1 << 4), LWS_SERVER_OPTION_DISABLE_IPV6 = (1 << 5), LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS = (1 << 6), LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED = (1 << 7), LWS_SERVER_OPTION_VALIDATE_UTF8 = (1 << 8), LWS_SERVER_OPTION_SSL_ECDH = (1 << 9) | (1 << 12), LWS_SERVER_OPTION_LIBUV = (1 << 10), LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS = (1 << 11) | (1 << 3) | (1 << 12), LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT = (1 << 12), LWS_SERVER_OPTION_EXPLICIT_VHOSTS = (1 << 13), LWS_SERVER_OPTION_UNIX_SOCK = (1 << 14), LWS_SERVER_OPTION_STS = (1 << 15), /****** add new things just above ---^ ******/ }; #define lws_check_opt(c, f) (((c) & (f)) == (f)) /* * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum lws_callback_reasons { LWS_CALLBACK_ESTABLISHED = 0, LWS_CALLBACK_CLIENT_CONNECTION_ERROR = 1, LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH = 2, LWS_CALLBACK_CLIENT_ESTABLISHED = 3, LWS_CALLBACK_CLOSED = 4, LWS_CALLBACK_CLOSED_HTTP = 5, LWS_CALLBACK_RECEIVE = 6, LWS_CALLBACK_RECEIVE_PONG = 7, LWS_CALLBACK_CLIENT_RECEIVE = 8, LWS_CALLBACK_CLIENT_RECEIVE_PONG = 9, LWS_CALLBACK_CLIENT_WRITEABLE = 10, LWS_CALLBACK_SERVER_WRITEABLE = 11, LWS_CALLBACK_HTTP = 12, LWS_CALLBACK_HTTP_BODY = 13, LWS_CALLBACK_HTTP_BODY_COMPLETION = 14, LWS_CALLBACK_HTTP_FILE_COMPLETION = 15, LWS_CALLBACK_HTTP_WRITEABLE = 16, LWS_CALLBACK_FILTER_NETWORK_CONNECTION = 17, LWS_CALLBACK_FILTER_HTTP_CONNECTION = 18, LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED = 19, LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION = 20, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS = 21, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS = 22, LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION = 23, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER = 24, LWS_CALLBACK_CONFIRM_EXTENSION_OKAY = 25, LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED = 26, LWS_CALLBACK_PROTOCOL_INIT = 27, LWS_CALLBACK_PROTOCOL_DESTROY = 28, LWS_CALLBACK_WSI_CREATE /* always protocol[0] */ = 29, LWS_CALLBACK_WSI_DESTROY /* always protocol[0] */ = 30, LWS_CALLBACK_GET_THREAD_ID = 31, /* external poll() management support */ LWS_CALLBACK_ADD_POLL_FD = 32, LWS_CALLBACK_DEL_POLL_FD = 33, LWS_CALLBACK_CHANGE_MODE_POLL_FD = 34, LWS_CALLBACK_LOCK_POLL = 35, LWS_CALLBACK_UNLOCK_POLL = 36, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY = 37, LWS_CALLBACK_WS_PEER_INITIATED_CLOSE = 38, LWS_CALLBACK_WS_EXT_DEFAULTS = 39, LWS_CALLBACK_CGI = 40, LWS_CALLBACK_CGI_TERMINATED = 41, LWS_CALLBACK_CGI_STDIN_DATA = 42, LWS_CALLBACK_CGI_STDIN_COMPLETED = 43, LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP = 44, LWS_CALLBACK_CLOSED_CLIENT_HTTP = 45, LWS_CALLBACK_RECEIVE_CLIENT_HTTP = 46, LWS_CALLBACK_COMPLETED_CLIENT_HTTP = 47, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ = 48, /****** add new things just above ---^ ******/ LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ }; #if defined(_WIN32) typedef SOCKET lws_sockfd_type; typedef HANDLE lws_filefd_type; #define lws_sockfd_valid(sfd) (!!sfd) struct lws_pollfd { lws_sockfd_type fd; SHORT events; SHORT revents; }; #else #if defined(MBED_OPERATORS) /* it's a class lws_conn * */ typedef void * lws_sockfd_type; typedef void * lws_filefd_type; #define lws_sockfd_valid(sfd) (!!sfd) struct pollfd { lws_sockfd_type fd; short events; short revents; }; #define POLLIN 0x0001 #define POLLPRI 0x0002 #define POLLOUT 0x0004 #define POLLERR 0x0008 #define POLLHUP 0x0010 #define POLLNVAL 0x0020 struct lws; void * mbed3_create_tcp_stream_socket(void); void mbed3_delete_tcp_stream_socket(void *sockfd); void mbed3_tcp_stream_bind(void *sock, int port, struct lws *); void mbed3_tcp_stream_accept(void *sock, struct lws *); #else typedef int lws_sockfd_type; typedef int lws_filefd_type; #define lws_sockfd_valid(sfd) (sfd >= 0) #endif #define lws_pollfd pollfd #endif /* argument structure for all external poll related calls * passed in via 'in' */ struct lws_pollargs { lws_sockfd_type fd; /* applicable socket descriptor */ int events; /* the new event mask */ int prev_events; /* the previous event mask */ }; /** * struct lws_plat_file_ops - Platform-specific file operations * * These provide platform-agnostic ways to deal with filesystem access in the * library and in the user code. * * @open: Open file (always binary access if plat supports it) * filelen is filled on exit to be the length of the file * flags should be set to O_RDONLY or O_RDWR * @close: Close file * @seek_cur: Seek from current position * @read: Read fron file *amount is set on exit to amount read * @write: Write to file *amount is set on exit as amount written */ struct lws_plat_file_ops { lws_filefd_type (*open)(struct lws *wsi, const char *filename, unsigned long *filelen, int flags); int (*close)(struct lws *wsi, lws_filefd_type fd); unsigned long (*seek_cur)(struct lws *wsi, lws_filefd_type fd, long offset_from_cur_pos); int (*read)(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len); int (*write)(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len); /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility */ }; /* * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum lws_extension_callback_reasons { LWS_EXT_CB_SERVER_CONTEXT_CONSTRUCT = 0, LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT = 1, LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT = 2, LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT = 3, LWS_EXT_CB_CONSTRUCT = 4, LWS_EXT_CB_CLIENT_CONSTRUCT = 5, LWS_EXT_CB_CHECK_OK_TO_REALLY_CLOSE = 6, LWS_EXT_CB_CHECK_OK_TO_PROPOSE_EXTENSION = 7, LWS_EXT_CB_DESTROY = 8, LWS_EXT_CB_DESTROY_ANY_WSI_CLOSING = 9, LWS_EXT_CB_ANY_WSI_ESTABLISHED = 10, LWS_EXT_CB_PACKET_RX_PREPARSE = 11, LWS_EXT_CB_PACKET_TX_PRESEND = 12, LWS_EXT_CB_PACKET_TX_DO_SEND = 13, LWS_EXT_CB_HANDSHAKE_REPLY_TX = 14, LWS_EXT_CB_FLUSH_PENDING_TX = 15, LWS_EXT_CB_EXTENDED_PAYLOAD_RX = 16, LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION = 17, LWS_EXT_CB_1HZ = 18, LWS_EXT_CB_REQUEST_ON_WRITEABLE = 19, LWS_EXT_CB_IS_WRITEABLE = 20, LWS_EXT_CB_PAYLOAD_TX = 21, LWS_EXT_CB_PAYLOAD_RX = 22, LWS_EXT_CB_OPTION_DEFAULT = 23, LWS_EXT_CB_OPTION_SET = 24, LWS_EXT_CB_OPTION_CONFIRM = 25, LWS_EXT_CB_NAMED_OPTION_SET = 26, /****** add new things just above ---^ ******/ }; /* * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum lws_write_protocol { LWS_WRITE_TEXT = 0, LWS_WRITE_BINARY = 1, LWS_WRITE_CONTINUATION = 2, LWS_WRITE_HTTP = 3, /* special 04+ opcodes */ /* LWS_WRITE_CLOSE is handled by lws_close_reason() */ LWS_WRITE_PING = 5, LWS_WRITE_PONG = 6, /* Same as write_http but we know this write ends the transaction */ LWS_WRITE_HTTP_FINAL = 7, /* HTTP2 */ LWS_WRITE_HTTP_HEADERS = 8, /****** add new things just above ---^ ******/ /* flags */ LWS_WRITE_NO_FIN = 0x40, /* * client packet payload goes out on wire unmunged * only useful for security tests since normal servers cannot * decode the content if used */ LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 }; /* * you need these to look at headers that have been parsed if using the * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum * list below is absent, .token = NULL and token_len = 0. Otherwise .token * points to .token_len chars containing that header content. */ struct lws_tokens { char *token; int token_len; }; /* * these have to be kept in sync with lextable.h / minilex.c * * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum lws_token_indexes { WSI_TOKEN_GET_URI = 0, WSI_TOKEN_POST_URI = 1, WSI_TOKEN_OPTIONS_URI = 2, WSI_TOKEN_HOST = 3, WSI_TOKEN_CONNECTION = 4, WSI_TOKEN_UPGRADE = 5, WSI_TOKEN_ORIGIN = 6, WSI_TOKEN_DRAFT = 7, WSI_TOKEN_CHALLENGE = 8, WSI_TOKEN_EXTENSIONS = 9, WSI_TOKEN_KEY1 = 10, WSI_TOKEN_KEY2 = 11, WSI_TOKEN_PROTOCOL = 12, WSI_TOKEN_ACCEPT = 13, WSI_TOKEN_NONCE = 14, WSI_TOKEN_HTTP = 15, WSI_TOKEN_HTTP2_SETTINGS = 16, WSI_TOKEN_HTTP_ACCEPT = 17, WSI_TOKEN_HTTP_AC_REQUEST_HEADERS = 18, WSI_TOKEN_HTTP_IF_MODIFIED_SINCE = 19, WSI_TOKEN_HTTP_IF_NONE_MATCH = 20, WSI_TOKEN_HTTP_ACCEPT_ENCODING = 21, WSI_TOKEN_HTTP_ACCEPT_LANGUAGE = 22, WSI_TOKEN_HTTP_PRAGMA = 23, WSI_TOKEN_HTTP_CACHE_CONTROL = 24, WSI_TOKEN_HTTP_AUTHORIZATION = 25, WSI_TOKEN_HTTP_COOKIE = 26, WSI_TOKEN_HTTP_CONTENT_LENGTH = 27, WSI_TOKEN_HTTP_CONTENT_TYPE = 28, WSI_TOKEN_HTTP_DATE = 29, WSI_TOKEN_HTTP_RANGE = 30, WSI_TOKEN_HTTP_REFERER = 31, WSI_TOKEN_KEY = 32, WSI_TOKEN_VERSION = 33, WSI_TOKEN_SWORIGIN = 34, WSI_TOKEN_HTTP_COLON_AUTHORITY = 35, WSI_TOKEN_HTTP_COLON_METHOD = 36, WSI_TOKEN_HTTP_COLON_PATH = 37, WSI_TOKEN_HTTP_COLON_SCHEME = 38, WSI_TOKEN_HTTP_COLON_STATUS = 39, WSI_TOKEN_HTTP_ACCEPT_CHARSET = 40, WSI_TOKEN_HTTP_ACCEPT_RANGES = 41, WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN = 42, WSI_TOKEN_HTTP_AGE = 43, WSI_TOKEN_HTTP_ALLOW = 44, WSI_TOKEN_HTTP_CONTENT_DISPOSITION = 45, WSI_TOKEN_HTTP_CONTENT_ENCODING = 46, WSI_TOKEN_HTTP_CONTENT_LANGUAGE = 47, WSI_TOKEN_HTTP_CONTENT_LOCATION = 48, WSI_TOKEN_HTTP_CONTENT_RANGE = 49, WSI_TOKEN_HTTP_ETAG = 50, WSI_TOKEN_HTTP_EXPECT = 51, WSI_TOKEN_HTTP_EXPIRES = 52, WSI_TOKEN_HTTP_FROM = 53, WSI_TOKEN_HTTP_IF_MATCH = 54, WSI_TOKEN_HTTP_IF_RANGE = 55, WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE = 56, WSI_TOKEN_HTTP_LAST_MODIFIED = 57, WSI_TOKEN_HTTP_LINK = 58, WSI_TOKEN_HTTP_LOCATION = 59, WSI_TOKEN_HTTP_MAX_FORWARDS = 60, WSI_TOKEN_HTTP_PROXY_AUTHENTICATE = 61, WSI_TOKEN_HTTP_PROXY_AUTHORIZATION = 62, WSI_TOKEN_HTTP_REFRESH = 63, WSI_TOKEN_HTTP_RETRY_AFTER = 64, WSI_TOKEN_HTTP_SERVER = 65, WSI_TOKEN_HTTP_SET_COOKIE = 66, WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY = 67, WSI_TOKEN_HTTP_TRANSFER_ENCODING = 68, WSI_TOKEN_HTTP_USER_AGENT = 69, WSI_TOKEN_HTTP_VARY = 70, WSI_TOKEN_HTTP_VIA = 71, WSI_TOKEN_HTTP_WWW_AUTHENTICATE = 72, WSI_TOKEN_PATCH_URI = 73, WSI_TOKEN_PUT_URI = 74, WSI_TOKEN_DELETE_URI = 75, WSI_TOKEN_HTTP_URI_ARGS = 76, WSI_TOKEN_PROXY = 77, WSI_TOKEN_HTTP_X_REAL_IP = 78, WSI_TOKEN_HTTP1_0 = 79, /****** add new things just above ---^ ******/ /* use token storage to stash these internally, not for * user use */ _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, _WSI_TOKEN_CLIENT_PEER_ADDRESS, _WSI_TOKEN_CLIENT_URI, _WSI_TOKEN_CLIENT_HOST, _WSI_TOKEN_CLIENT_ORIGIN, _WSI_TOKEN_CLIENT_METHOD, /* always last real token index*/ WSI_TOKEN_COUNT, /* parser state additions, no storage associated */ WSI_TOKEN_NAME_PART, WSI_TOKEN_SKIPPING, WSI_TOKEN_SKIPPING_SAW_CR, WSI_PARSING_COMPLETE, WSI_INIT_TOKEN_MUXURL, }; struct lws_token_limits { unsigned short token_limit[WSI_TOKEN_COUNT]; }; /* * From RFC 6455 1000 1000 indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled. 1001 1001 indicates that an endpoint is "going away", such as a server going down or a browser having navigated away from a page. 1002 1002 indicates that an endpoint is terminating the connection due to a protocol error. 1003 1003 indicates that an endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message). 1004 Reserved. The specific meaning might be defined in the future. 1005 1005 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that no status code was actually present. 1006 1006 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that the connection was closed abnormally, e.g., without sending or receiving a Close control frame. 1007 1007 indicates that an endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [RFC3629] data within a text message). 1008 1008 indicates that an endpoint is terminating the connection because it has received a message that violates its policy. This is a generic status code that can be returned when there is no other more suitable status code (e.g., 1003 or 1009) or if there is a need to hide specific details about the policy. 1009 1009 indicates that an endpoint is terminating the connection because it has received a message that is too big for it to process. 1010 1010 indicates that an endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the server didn't return them in the response message of the WebSocket handshake. The list of extensions that are needed SHOULD appear in the /reason/ part of the Close frame. Note that this status code is not used by the server, because it can fail the WebSocket handshake instead. 1011 1011 indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request. 1015 1015 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified). */ /* * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum lws_close_status { LWS_CLOSE_STATUS_NOSTATUS = 0, LWS_CLOSE_STATUS_NORMAL = 1000, LWS_CLOSE_STATUS_GOINGAWAY = 1001, LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, LWS_CLOSE_STATUS_RESERVED = 1004, LWS_CLOSE_STATUS_NO_STATUS = 1005, LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, LWS_CLOSE_STATUS_TLS_FAILURE = 1015, /****** add new things just above ---^ ******/ LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY = 9999, }; enum http_status { HTTP_STATUS_OK = 200, HTTP_STATUS_NO_CONTENT = 204, HTTP_STATUS_MOVED_PERMANENTLY = 301, HTTP_STATUS_FOUND = 302, HTTP_STATUS_SEE_OTHER = 303, HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_UNAUTHORIZED, HTTP_STATUS_PAYMENT_REQUIRED, HTTP_STATUS_FORBIDDEN, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_METHOD_NOT_ALLOWED, HTTP_STATUS_NOT_ACCEPTABLE, HTTP_STATUS_PROXY_AUTH_REQUIRED, HTTP_STATUS_REQUEST_TIMEOUT, HTTP_STATUS_CONFLICT, HTTP_STATUS_GONE, HTTP_STATUS_LENGTH_REQUIRED, HTTP_STATUS_PRECONDITION_FAILED, HTTP_STATUS_REQ_ENTITY_TOO_LARGE, HTTP_STATUS_REQ_URI_TOO_LONG, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, HTTP_STATUS_EXPECTATION_FAILED, HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, HTTP_STATUS_NOT_IMPLEMENTED, HTTP_STATUS_BAD_GATEWAY, HTTP_STATUS_SERVICE_UNAVAILABLE, HTTP_STATUS_GATEWAY_TIMEOUT, HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, }; struct lws; struct lws_context; /* needed even with extensions disabled for create context */ struct lws_extension; /** * typedef lws_callback_function() - User server actions * @wsi: Opaque websocket instance pointer * @reason: The reason for the call * @user: Pointer to per-session user data allocated by library * @in: Pointer used for some callback reasons * @len: Length set for some callback reasons * * This callback is the way the user controls what is served. All the * protocol detail is hidden and handled by the library. * * For each connection / session there is user data allocated that is * pointed to by "user". You set the size of this user data area when * the library is initialized with lws_create_server. * * You get an opportunity to initialize user data when called back with * LWS_CALLBACK_ESTABLISHED reason. * * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with * an incoming client. If you built the library * with ssl support, @in is a pointer to the * ssl struct associated with the connection or * NULL. * * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has * been unable to complete a handshake with the remote server. If * in is non-NULL, you can find an error string of length len where * it points to. * * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the * client user code to examine the http headers * and decide to reject the connection. If the * content in the headers is interesting to the * client (url, etc) it needs to copy it out at * this point since it will be destroyed before * the CLIENT_ESTABLISHED call * * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed * a handshake with the remote server * * LWS_CALLBACK_CLOSED: when the websocket session ends * * LWS_CALLBACK_CLOSED_HTTP: when a HTTP (non-websocket) session ends * * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a * remote client, it can be found at *in and is * len bytes long * * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, * they appear with this callback reason. PONG * packets only exist in 04+ protocol * * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the * client connection, it can be found at *in and * is len bytes long * * LWS_CALLBACK_HTTP: an http request has come from a client that is not * asking to upgrade the connection to a websocket * one. This is a chance to serve http content, * for example, to send a script to the client * which will then open the websockets connection. * @in points to the URI path requested and * lws_serve_http_file() makes it very * simple to send back a file to the client. * Normally after sending the file you are done * with the http connection, since the rest of the * activity will come by websockets from the script * that was delivered by http, so you will want to * return 1; to close and free up the connection. * That's important because it uses a slot in the * total number of client connections allowed set * by MAX_CLIENTS. * * LWS_CALLBACK_HTTP_BODY: the next @len bytes data from the http * request body HTTP connection is now available in @in. * * LWS_CALLBACK_HTTP_BODY_COMPLETION: the expected amount of http request * body has been delivered * * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol * link now. * * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down * http link has completed. * * LWS_CALLBACK_CLIENT_WRITEABLE: * LWS_CALLBACK_SERVER_WRITEABLE: If you call * lws_callback_on_writable() on a connection, you will * get one of these callbacks coming when the connection socket * is able to accept another write packet without blocking. * If it already was able to take another packet without blocking, * you'll get this callback at the next call to the service loop * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE * and servers get LWS_CALLBACK_SERVER_WRITEABLE. * * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to * the server at network level; the connection is accepted but then * passed to this callback to decide whether to hang up immediately * or not, based on the client IP. @in contains the connection * socket's descriptor. Since the client connection information is * not available yet, @wsi still pointing to the main server socket. * Return non-zero to terminate the connection before sending or * receiving anything. Because this happens immediately after the * network connection from the client, there's no websocket protocol * selected yet so this callback is issued only to protocol 0. * * LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: A new client just had * been connected, accepted, and instantiated into the pool. This * callback allows setting any relevant property to it. Because this * happens immediately after the instantiation of a new client, * there's no websocket protocol selected yet so this callback is * issued only to protocol 0. Only @wsi is defined, pointing to the * new client, and the return value is ignored. * * LWS_CALLBACK_FILTER_HTTP_CONNECTION: called when the request has * been received and parsed from the client, but the response is * not sent yet. Return non-zero to disallow the connection. * @user is a pointer to the connection user space allocation, * @in is the URI, eg, "/" * In your handler you can use the public APIs * lws_hdr_total_length() / lws_hdr_copy() to access all of the * headers using the header enums lws_token_indexes from * libwebsockets.h to check for and read the supported header * presence and content before deciding to allow the http * connection to proceed or to kill the connection. * * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has * been received and parsed from the client, but the response is * not sent yet. Return non-zero to disallow the connection. * @user is a pointer to the connection user space allocation, * @in is the requested protocol name * In your handler you can use the public APIs * lws_hdr_total_length() / lws_hdr_copy() to access all of the * headers using the header enums lws_token_indexes from * libwebsockets.h to check for and read the supported header * presence and content before deciding to allow the handshake * to proceed or to kill the connection. * * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for * including OpenSSL support, this callback allows your user code * to perform extra SSL_CTX_load_verify_locations() or similar * calls to direct OpenSSL where to find certificates the client * can use to confirm the remote server identity. @user is the * OpenSSL SSL_CTX* * * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for * including OpenSSL support, this callback allows your user code * to load extra certifcates into the server which allow it to * verify the validity of certificates returned by clients. @user * is the server's OpenSSL SSL_CTX* * * LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY: if configured for * including OpenSSL support but no private key file has been * specified (ssl_private_key_filepath is NULL), this is called to * allow the user to set the private key directly via libopenssl * and perform further operations if required; this might be useful * in situations where the private key is not directly accessible * by the OS, for example if it is stored on a smartcard * @user is the server's OpenSSL SSL_CTX* * * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the * libwebsockets context was created with the option * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this * callback is generated during OpenSSL verification of the cert * sent from the client. It is sent to protocol[0] callback as * no protocol has been negotiated on the connection yet. * Notice that the libwebsockets context and wsi are both NULL * during this callback. See * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html * to understand more detail about the OpenSSL callback that * generates this libwebsockets callback and the meanings of the * arguments passed. In this callback, @user is the x509_ctx, * @in is the ssl pointer and @len is preverify_ok * Notice that this callback maintains libwebsocket return * conventions, return 0 to mean the cert is OK or 1 to fail it. * This also means that if you don't handle this callback then * the default callback action of returning 0 allows the client * certificates. * * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens * when a client handshake is being compiled. @user is NULL, * @in is a char **, it's pointing to a char * which holds the * next location in the header buffer where you can add * headers, and @len is the remaining space in the header buffer, * which is typically some hundreds of bytes. So, to add a canned * cookie, your handler code might look similar to: * * char **p = (char **)in; * * if (len < 100) * return 1; * * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); * * return 0; * * Notice if you add anything, you just have to take care about * the CRLF on the line you added. Obviously this callback is * optional, if you don't handle it everything is fine. * * Notice the callback is coming to protocols[0] all the time, * because there is no specific protocol handshook yet. * * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code * sees that it does support a requested extension, before * accepting the extension by additing to the list sent back to * the client it gives this callback just to check that it's okay * to use that extension. It calls back to the requested protocol * and with @in being the extension name, @len is 0 and @user is * valid. Note though at this time the ESTABLISHED callback hasn't * happened yet so if you initialize @user content there, @user * content during this callback might not be useful for anything. * Notice this callback comes to protocols[0]. * * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client * connection is being prepared to start a handshake to a server, * each supported extension is checked with protocols[0] callback * with this reason, giving the user code a chance to suppress the * claim to support that extension by returning non-zero. If * unhandled, by default 0 will be returned and the extension * support included in the header to the server. Notice this * callback comes to protocols[0]. * * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can * do initial setup / allocations etc * * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating * this protocol won't get used at all after this callback, the * context is getting destroyed. Take the opportunity to * deallocate everything that was allocated by the protocol. * * LWS_CALLBACK_WSI_CREATE: outermost (earliest) wsi create notification * * LWS_CALLBACK_WSI_DESTROY: outermost (latest) wsi destroy notification * * The next five reasons are optional and only need taking care of if you * will be integrating libwebsockets sockets into an external polling * array. * * For these calls, @in points to a struct lws_pollargs that * contains @fd, @events and @prev_events members * * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop * internally, but in the case you are integrating with another * server you will need to have libwebsocket sockets share a * polling array with the other server. This and the other * POLL_FD related callbacks let you put your specialized * poll array interface code in the callback for protocol 0, the * first protocol you support, usually the HTTP protocol in the * serving case. * This callback happens when a socket needs to be * added to the polling loop: @in points to a struct * lws_pollargs; the @fd member of the struct is the file * descriptor, and @events contains the active events. * * If you are using the internal polling loop (the "service" * callback), you can just ignore these callbacks. * * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor * needs to be removed from an external polling array. @in is * again the struct lws_pollargs containing the @fd member * to be removed. If you are using the internal polling * loop, you can just ignore it. * * LWS_CALLBACK_CHANGE_MODE_POLL_FD: This callback happens when * libwebsockets wants to modify the events for a connectiion. * @in is the struct lws_pollargs with the @fd to change. * The new event mask is in @events member and the old mask is in * the @prev_events member. * If you are using the internal polling loop, you can just ignore * it. * * LWS_CALLBACK_LOCK_POLL: * LWS_CALLBACK_UNLOCK_POLL: These allow the external poll changes driven * by libwebsockets to participate in an external thread locking * scheme around the changes, so the whole thing is threadsafe. * These are called around three activities in the library, * - inserting a new wsi in the wsi / fd table (len=1) * - deleting a wsi from the wsi / fd table (len=1) * - changing a wsi's POLLIN/OUT state (len=0) * Locking and unlocking external synchronization objects when * len == 1 allows external threads to be synchronized against * wsi lifecycle changes if it acquires the same lock for the * duration of wsi dereference from the other thread context. * * LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: * The peer has sent an unsolicited Close WS packet. @in and * @len are the optional close code (first 2 bytes, network * order) and the optional additional information which is not * defined in the standard, and may be a string or non-human- * readble data. * If you return 0 lws will echo the close and then close the * connection. If you return nonzero lws will just close the * connection. */ typedef int lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); /** * typedef lws_extension_callback_function() - Hooks to allow extensions to operate * @context: Websockets context * @ext: This extension * @wsi: Opaque websocket instance pointer * @reason: The reason for the call * @user: Pointer to ptr to per-session user data allocated by library * @in: Pointer used for some callback reasons * @len: Length set for some callback reasons * * Each extension that is active on a particular connection receives * callbacks during the connection lifetime to allow the extension to * operate on websocket data and manage itself. * * Libwebsockets takes care of allocating and freeing "user" memory for * each active extension on each connection. That is what is pointed to * by the @user parameter. * * LWS_EXT_CB_CONSTRUCT: called when the server has decided to * select this extension from the list provided by the client, * just before the server will send back the handshake accepting * the connection with this extension active. This gives the * extension a chance to initialize its connection context found * in @user. * * LWS_EXT_CB_CLIENT_CONSTRUCT: same as LWS_EXT_CB_CONSTRUCT * but called when client is instantiating this extension. Some * extensions will work the same on client and server side and then * you can just merge handlers for both CONSTRUCTS. * * LWS_EXT_CB_DESTROY: called when the connection the extension was * being used on is about to be closed and deallocated. It's the * last chance for the extension to deallocate anything it has * allocated in the user data (pointed to by @user) before the * user data is deleted. This same callback is used whether you * are in client or server instantiation context. * * LWS_EXT_CB_PACKET_RX_PREPARSE: when this extension was active on * a connection, and a packet of data arrived at the connection, * it is passed to this callback to give the extension a chance to * change the data, eg, decompress it. @user is pointing to the * extension's private connection context data, @in is pointing * to an lws_tokens struct, it consists of a char * pointer called * token, and an int called token_len. At entry, these are * set to point to the received buffer and set to the content * length. If the extension will grow the content, it should use * a new buffer allocated in its private user context data and * set the pointed-to lws_tokens members to point to its buffer. * * LWS_EXT_CB_PACKET_TX_PRESEND: this works the same way as * LWS_EXT_CB_PACKET_RX_PREPARSE above, except it gives the * extension a chance to change websocket data just before it will * be sent out. Using the same lws_token pointer scheme in @in, * the extension can change the buffer and the length to be * transmitted how it likes. Again if it wants to grow the * buffer safely, it should copy the data into its own buffer and * set the lws_tokens token pointer to it. * * LWS_EXT_CB_ARGS_VALIDATE: */ typedef int lws_extension_callback_function(struct lws_context *context, const struct lws_extension *ext, struct lws *wsi, enum lws_extension_callback_reasons reason, void *user, void *in, size_t len); /** * struct lws_protocols - List of protocols and handlers server * supports. * @name: Protocol name that must match the one given in the client * Javascript new WebSocket(url, 'protocol') name. * @callback: The service callback used for this protocol. It allows the * service action for an entire protocol to be encapsulated in * the protocol-specific callback * @per_session_data_size: Each new connection using this protocol gets * this much memory allocated on connection establishment and * freed on connection takedown. A pointer to this per-connection * allocation is passed into the callback in the 'user' parameter * @rx_buffer_size: if you want atomic frames delivered to the callback, you * should set this to the size of the biggest legal frame that * you support. If the frame size is exceeded, there is no * error, but the buffer will spill to the user callback when * full, which you can detect by using * lws_remaining_packet_payload(). Notice that you * just talk about frame size here, the LWS_PRE * and post-padding are automatically also allocated on top. * @id: ignored by lws, but useful to contain user information bound * to the selected protocol. For example if this protocol was * called "myprotocol-v2", you might set id to 2, and the user * code that acts differently according to the version can do so by * switch (wsi->protocol->id), user code might use some bits as * capability flags based on selected protocol version, etc. * @user: User provided context data at the protocol level. * Accessible via lws_get_protocol(wsi)->user * This should not be confused with wsi->user, it is not the same. * The library completely ignores any value in here. * * This structure represents one protocol supported by the server. An * array of these structures is passed to lws_create_server() * allows as many protocols as you like to be handled by one server. * * The first protocol given has its callback used for user callbacks when * there is no agreed protocol name, that's true during HTTP part of the * connection and true if the client did not send a Protocol: header. */ struct lws_protocols { const char *name; lws_callback_function *callback; size_t per_session_data_size; size_t rx_buffer_size; unsigned int id; void *user; /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility */ }; enum lws_ext_options_types { EXTARG_NONE, EXTARG_DEC, EXTARG_OPT_DEC /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility */ }; /** * struct lws_ext_options - Option arguments to the extension. These are * used in the negotiation at ws upgrade time. * The helper function lws_ext_parse_options() * uses these to generate callbacks * * @name: Option name, eg, "server_no_context_takeover" * @type: What kind of args the option can take */ struct lws_ext_options { const char *name; enum lws_ext_options_types type; /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility */ }; struct lws_ext_option_arg { const char *option_name; /* may be NULL, option_index used then */ int option_index; const char *start; int len; }; /** * struct lws_extension - An extension we know how to cope with * * @name: Formal extension name, eg, "permessage-deflate" * @callback: Service callback * @client_offer: String containing exts and options client offers */ struct lws_extension { const char *name; lws_extension_callback_function *callback; const char *client_offer; /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility */ }; #ifdef LWS_WITH_PLUGINS /* PLUGINS implies LIBUV */ #define LWS_PLUGIN_API_MAGIC 180 struct lws_plugin_capability { unsigned int api_magic; /* caller fills this in, plugin fills rest */ const struct lws_protocols *protocols; int count_protocols; const struct lws_extension *extensions; int count_extensions; }; typedef int (*lws_plugin_init_func)(struct lws_context *, struct lws_plugin_capability *); typedef int (*lws_plugin_destroy_func)(struct lws_context *); struct lws_plugin { struct lws_plugin *list; #if (UV_VERSION_MAJOR > 0) uv_lib_t lib; #else void *l; #endif char name[64]; struct lws_plugin_capability caps; }; #endif /* * The internal exts are part of the public abi * If we add more extensions, publish the callback here ------v */ LWS_EXTERN int lws_extension_callback_pm_deflate( struct lws_context *context, const struct lws_extension *ext, struct lws *wsi, enum lws_extension_callback_reasons reason, void *user, void *in, size_t len); LWS_VISIBLE LWS_EXTERN int lws_set_extension_option(struct lws *wsi, const char *ext_name, const char *opt_name, const char *opt_val); struct lws_protocol_vhost_options { const struct lws_protocol_vhost_options *next; const struct lws_protocol_vhost_options *options; const char *name; const char *value; }; struct lws_http_mount { struct lws_http_mount *mount_next; const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */ const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */ const char *def; /* default target, eg, "index.html" */ const struct lws_protocol_vhost_options *cgienv; const struct lws_protocol_vhost_options *extra_mimetypes; int cgi_timeout; int cache_max_age; unsigned int cache_reusable:1; unsigned int cache_revalidate:1; unsigned int cache_intermediaries:1; unsigned char origin_protocol; unsigned char mountpoint_len; }; /** * struct lws_context_creation_info - parameters to create context with * * This is also used to create vhosts.... if LWS_SERVER_OPTION_EXPLICIT_VHOSTS * is not given, then for backwards compatibility one vhost is created at * context-creation time using the info from this struct. * * If LWS_SERVER_OPTION_EXPLICIT_VHOSTS is given, then no vhosts are created * at the same time as the context, they are expected to be created afterwards. * * @port: VHOST: Port to listen on... you can use CONTEXT_PORT_NO_LISTEN to * suppress listening on any port, that's what you want if you are * not running a websocket server at all but just using it as a * client * @iface: VHOST: NULL to bind the listen socket to all interfaces, or the * interface name, eg, "eth2" * If options specifies LWS_SERVER_OPTION_UNIX_SOCK, this member is * the pathname of a UNIX domain socket. you can use the UNIX domain * sockets in abstract namespace, by prepending an @ symbole to the * socket name. * @protocols: VHOST: Array of structures listing supported protocols and a protocol- * specific callback for each one. The list is ended with an * entry that has a NULL callback pointer. * It's not const because we write the owning_server member * @extensions: VHOST: NULL or array of lws_extension structs listing the * extensions this context supports. If you configured with * --without-extensions, you should give NULL here. * @token_limits: CONTEXT: NULL or struct lws_token_limits pointer which is initialized * with a token length limit for each possible WSI_TOKEN_*** * @ssl_cert_filepath: VHOST: If libwebsockets was compiled to use ssl, and you want * to listen using SSL, set to the filepath to fetch the * server cert from, otherwise NULL for unencrypted * @ssl_private_key_filepath: VHOST: filepath to private key if wanting SSL mode; * if this is set to NULL but sll_cert_filepath is set, the * OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY callback is called * to allow setting of the private key directly via openSSL * library calls * @ssl_ca_filepath: VHOST: CA certificate filepath or NULL * @ssl_cipher_list: VHOST: List of valid ciphers to use (eg, * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" * or you can leave it as NULL to get "DEFAULT" * @http_proxy_address: VHOST: If non-NULL, attempts to proxy via the given address. * If proxy auth is required, use format * "username:password@server:port" * @http_proxy_port: VHOST: If http_proxy_address was non-NULL, uses this port at * the address * @gid: CONTEXT: group id to change to after setting listen socket, or -1. * @uid: CONTEXT: user id to change to after setting listen socket, or -1. * @options: VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields * @user: CONTEXT: optional user pointer that can be recovered via the context * pointer using lws_context_user * @ka_time: CONTEXT: 0 for no keepalive, otherwise apply this keepalive timeout to * all libwebsocket sockets, client or server * @ka_probes: CONTEXT: if ka_time was nonzero, after the timeout expires how many * times to try to get a response from the peer before giving up * and killing the connection * @ka_interval: CONTEXT: if ka_time was nonzero, how long to wait before each ka_probes * attempt * @provided_client_ssl_ctx: CONTEXT: If non-null, swap out libwebsockets ssl * implementation for the one provided by provided_ssl_ctx. * Libwebsockets no longer is responsible for freeing the context * if this option is selected. * @max_http_header_data: CONTEXT: The max amount of header payload that can be handled * in an http request (unrecognized header payload is dropped) * @max_http_header_pool: CONTEXT: The max number of connections with http headers that * can be processed simultaneously (the corresponding memory is * allocated for the lifetime of the context). If the pool is * busy new incoming connections must wait for accept until one * becomes free. * @count_threads: CONTEXT: how many contexts to create in an array, 0 = 1 * @fd_limit_per_thread: CONTEXT: nonzero means restrict each service thread to this * many fds, 0 means the default which is divide the process fd * limit by the number of threads. * @timeout_secs: VHOST: various processes involving network roundtrips in the * library are protected from hanging forever by timeouts. If * nonzero, this member lets you set the timeout used in seconds. * Otherwise a default timeout is used. * @ecdh_curve: VHOST: if NULL, defaults to initializing server with "prime256v1" * @vhost_name: VHOST: name of vhost, must match external DNS name used to * access the site, like "warmcat.com" as it's used to match * Host: header and / or SNI name for SSL. * @plugin_dirs: CONTEXT: NULL, or NULL-terminated array of directories to * scan for lws protocol plugins at context creation time * @pvo: VHOST: pointer to optional linked list of per-vhost * options made accessible to protocols * @keepalive_timeout: VHOST: (default = 0 = 60s) seconds to allow remote * client to hold on to an idle HTTP/1.1 connection * @log_filepath: VHOST: filepath to append logs to... this is opened before * any dropping of initial privileges * @mounts: VHOST: optional linked list of mounts for this vhost * @server_string: CONTEXT: string used in HTTP headers to identify server * software, if NULL, "libwebsockets". */ struct lws_context_creation_info { int port; /* VH */ const char *iface; /* VH */ const struct lws_protocols *protocols; /* VH */ const struct lws_extension *extensions; /* VH */ const struct lws_token_limits *token_limits; /* context */ const char *ssl_private_key_password; /* VH */ const char *ssl_cert_filepath; /* VH */ const char *ssl_private_key_filepath; /* VH */ const char *ssl_ca_filepath; /* VH */ const char *ssl_cipher_list; /* VH */ const char *http_proxy_address; /* VH */ unsigned int http_proxy_port; /* VH */ int gid; /* context */ int uid; /* context */ unsigned int options; /* VH + context */ void *user; /* context */ int ka_time; /* context */ int ka_probes; /* context */ int ka_interval; /* context */ #ifdef LWS_OPENSSL_SUPPORT SSL_CTX *provided_client_ssl_ctx; /* context */ #else /* maintain structure layout either way */ void *provided_client_ssl_ctx; #endif short max_http_header_data; /* context */ short max_http_header_pool; /* context */ unsigned int count_threads; /* context */ unsigned int fd_limit_per_thread; /* context */ unsigned int timeout_secs; /* VH */ const char *ecdh_curve; /* VH */ const char *vhost_name; /* VH */ const char * const *plugin_dirs; /* context */ const struct lws_protocol_vhost_options *pvo; /* VH */ int keepalive_timeout; /* VH */ const char *log_filepath; /* VH */ const struct lws_http_mount *mounts; /* VH */ const char *server_string; /* context */ /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility * * The below is to ensure later library versions with new * members added above will see 0 (default) even if the app * was not built against the newer headers. */ void *_unused[8]; }; /** * struct lws_client_connect_info - parameters to connect with when using * lws_client_connect_via_info() * * @context: lws context to create connection in * @address: remote address to connect to * @port: remote port to connect to * @ssl_connection: nonzero for ssl * @path: uri path * @host: content of host header * @origin: content of origin header * @protocol: list of ws protocols * @ietf_version_or_minus_one: currently leave at 0 or -1 * @userdata: if non-NULL, use this as wsi user_data instead of malloc it * @client_exts: array of extensions that may be used on connection * @method: if non-NULL, do this http method instead of ws[s] upgrade. * use "GET" to be a simple http client connection * @parent_wsi: if another wsi is responsible for this connection, give it here. * this is used to make sure if the parent closes so do any * child connections first. * @uri_replace_from: if non-NULL, when this string is found in URIs in * text/html content-encoding, it's replaced with @uri_replace_to * @uri_replace_to: see above * @vhost: vhost to bind to (used to determine related SSL_CTX) */ struct lws_client_connect_info { struct lws_context *context; const char *address; int port; int ssl_connection; const char *path; const char *host; const char *origin; const char *protocol; int ietf_version_or_minus_one; void *userdata; const struct lws_extension *client_exts; const char *method; struct lws *parent_wsi; const char *uri_replace_from; const char *uri_replace_to; struct lws_vhost *vhost; /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility * * The below is to ensure later library versions with new * members added above will see 0 (default) even if the app * was not built against the newer headers. */ void *_unused[4]; }; enum { LWSMPRO_HTTP, LWSMPRO_HTTPS, LWSMPRO_FILE, LWSMPRO_CGI, LWSMPRO_REDIR_HTTP, LWSMPRO_REDIR_HTTPS, }; LWS_VISIBLE LWS_EXTERN int lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len); LWS_VISIBLE LWS_EXTERN int lws_json_dump_context(const struct lws_context *context, char *buf, int len); LWS_VISIBLE LWS_EXTERN void lws_set_log_level(int level, void (*log_emit_function)(int level, const char *line)); LWS_VISIBLE LWS_EXTERN void lwsl_emit_syslog(int level, const char *line); LWS_VISIBLE LWS_EXTERN struct lws_context * lws_create_context(struct lws_context_creation_info *info); struct lws_vhost; LWS_EXTERN LWS_VISIBLE struct lws_vhost * lws_create_vhost(struct lws_context *context, struct lws_context_creation_info *info); LWS_VISIBLE LWS_EXTERN struct lws_vhost * lws_vhost_get(struct lws *wsi); LWS_VISIBLE LWS_EXTERN const struct lws_protocols * lws_protocol_get(struct lws *wsi); LWS_VISIBLE LWS_EXTERN void * lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot, int size); LWS_VISIBLE LWS_EXTERN void * lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot); LWS_VISIBLE LWS_EXTERN int lws_finalize_startup(struct lws_context *context); LWS_VISIBLE LWS_EXTERN int lws_set_proxy(struct lws_vhost *vhost, const char *proxy); LWS_VISIBLE LWS_EXTERN void lws_context_destroy(struct lws_context *context); LWS_VISIBLE LWS_EXTERN int lws_service(struct lws_context *context, int timeout_ms); LWS_VISIBLE LWS_EXTERN int lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi); LWS_VISIBLE LWS_EXTERN void lws_cancel_service_pt(struct lws *wsi); LWS_VISIBLE LWS_EXTERN void lws_cancel_service(struct lws_context *context); LWS_VISIBLE LWS_EXTERN int lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, size_t addrlen); LWS_VISIBLE LWS_EXTERN const unsigned char * lws_token_to_string(enum lws_token_indexes token); /* all the below must be LWS_WARN_UNUSED_RESULT as they can run short */ LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_finalize_http_header(struct lws *wsi, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_add_http_header_content_length(struct lws *wsi, unsigned long content_length, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_add_http_header_status(struct lws *wsi, unsigned int code, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len, unsigned char **p, unsigned char *end); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_http_transaction_completed(struct lws *wsi); #ifdef LWS_USE_LIBEV typedef void (lws_ev_signal_cb_t)(EV_P_ struct ev_signal *w, int revents); LWS_VISIBLE LWS_EXTERN int lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint, lws_ev_signal_cb_t *cb); LWS_VISIBLE LWS_EXTERN int lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi); LWS_VISIBLE LWS_EXTERN void lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents); #endif /* LWS_USE_LIBEV */ #ifdef LWS_USE_LIBUV LWS_VISIBLE LWS_EXTERN int lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint, uv_signal_cb cb); LWS_VISIBLE LWS_EXTERN void lws_libuv_run(const struct lws_context *context, int tsi); LWS_VISIBLE LWS_EXTERN void lws_libuv_stop(struct lws_context *context); LWS_VISIBLE LWS_EXTERN int lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi); LWS_VISIBLE LWS_EXTERN uv_loop_t * lws_uv_getloop(struct lws_context *context, int tsi); LWS_VISIBLE LWS_EXTERN void lws_uv_sigint_cb(uv_signal_t *watcher, int signum); #endif /* LWS_USE_LIBUV */ LWS_VISIBLE LWS_EXTERN int lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd); LWS_VISIBLE LWS_EXTERN int lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int tsi); LWS_VISIBLE LWS_EXTERN void * lws_context_user(struct lws_context *context); LWS_VISIBLE LWS_EXTERN void * lws_wsi_user(struct lws *wsi); /* * NOTE: These public enums are part of the abi. If you want to add one, * add it at where specified so existing users are unaffected. */ enum pending_timeout { NO_PENDING_TIMEOUT = 0, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE = 1, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE = 2, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER = 3, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE = 4, PENDING_TIMEOUT_AWAITING_PING = 5, PENDING_TIMEOUT_CLOSE_ACK = 6, PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE = 7, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE = 8, PENDING_TIMEOUT_SSL_ACCEPT = 9, PENDING_TIMEOUT_HTTP_CONTENT = 10, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND = 11, PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE = 12, PENDING_TIMEOUT_SHUTDOWN_FLUSH = 13, PENDING_TIMEOUT_CGI = 14, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE = 15, /****** add new things just above ---^ ******/ }; LWS_VISIBLE LWS_EXTERN void lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs); /* * IMPORTANT NOTICE! * * When sending with websocket protocol * * LWS_WRITE_TEXT, * LWS_WRITE_BINARY, * LWS_WRITE_CONTINUATION, * LWS_WRITE_PING, * LWS_WRITE_PONG * * the send buffer has to have LWS_PRE bytes valid BEFORE * the buffer pointer you pass to lws_write(). * * This allows us to add protocol info before and after the data, and send as * one packet on the network without payload copying, for maximum efficiency. * * So for example you need this kind of code to use lws_write with a * 128-byte payload * * char buf[LWS_PRE + 128]; * * // fill your part of the buffer... for example here it's all zeros * memset(&buf[LWS_PRE], 0, 128); * * lws_write(wsi, &buf[LWS_PRE], 128, LWS_WRITE_TEXT); * * When sending HTTP, with * * LWS_WRITE_HTTP, * LWS_WRITE_HTTP_HEADERS * LWS_WRITE_HTTP_FINAL * * there is no protocol data prepended, and don't need to take care about the * LWS_PRE bytes valid before the buffer pointer. * * LWS_PRE is at least the frame nonce + 2 header + 8 length * LWS_SEND_BUFFER_POST_PADDING is deprecated, it's now 0 and can be left off. * The example apps no longer use it. * * Pad LWS_PRE to the CPU word size, so that word references * to the address immediately after the padding won't cause an unaligned access * error. Sometimes for performance reasons the recommended padding is even * larger than sizeof(void *). */ #if !defined(LWS_SIZEOFPTR) #define LWS_SIZEOFPTR (sizeof (void *)) #endif #if !defined(u_int64_t) #define u_int64_t unsigned long long #endif #if defined(__x86_64__) #define _LWS_PAD_SIZE 16 /* Intel recommended for best performance */ #else #define _LWS_PAD_SIZE LWS_SIZEOFPTR /* Size of a pointer on the target arch */ #endif #define _LWS_PAD(n) (((n) % _LWS_PAD_SIZE) ? \ ((n) + (_LWS_PAD_SIZE - ((n) % _LWS_PAD_SIZE))) : (n)) #define LWS_PRE _LWS_PAD(4 + 10) /* used prior to 1.7 and retained for backward compatibility */ #define LWS_SEND_BUFFER_PRE_PADDING LWS_PRE #define LWS_SEND_BUFFER_POST_PADDING 0 LWS_VISIBLE LWS_EXTERN int lws_write(struct lws *wsi, unsigned char *buf, size_t len, enum lws_write_protocol protocol); /** * lws_close_reason - Set reason and aux data to send with Close packet * If you are going to return nonzero from the callback * requesting the connection to close, you can optionally * call this to set the reason the peer will be told if * possible. * * @wsi: The websocket connection to set the close reason on * @status: A valid close status from websocket standard * @buf: NULL or buffer containing up to 124 bytes of auxiliary data * @len: Length of data in @buf to send */ LWS_VISIBLE LWS_EXTERN void lws_close_reason(struct lws *wsi, enum lws_close_status status, unsigned char *buf, size_t len); /* helper for case where buffer may be const */ #define lws_write_http(wsi, buf, len) \ lws_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP) LWS_VISIBLE LWS_EXTERN int lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, const char *other_headers, int other_headers_len); LWS_VISIBLE LWS_EXTERN int lws_serve_http_file_fragment(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body); LWS_VISIBLE LWS_EXTERN const struct lws_protocols * lws_get_protocol(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_callback_on_writable(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_callback_on_writable_all_protocol(const struct lws_context *context, const struct lws_protocols *protocol); LWS_VISIBLE LWS_EXTERN int lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost, const struct lws_protocols *protocol); LWS_VISIBLE LWS_EXTERN int lws_callback_all_protocol(struct lws_context *context, const struct lws_protocols *protocol, int reason); LWS_VISIBLE LWS_EXTERN int lws_callback_all_protocol_vhost(struct lws_vhost *vh, const struct lws_protocols *protocol, int reason); LWS_VISIBLE LWS_EXTERN int lws_get_socket_fd(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_is_final_fragment(struct lws *wsi); LWS_VISIBLE LWS_EXTERN unsigned char lws_get_reserved_bits(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_rx_flow_control(struct lws *wsi, int enable); LWS_VISIBLE LWS_EXTERN void lws_rx_flow_allow_all_protocol(const struct lws_context *context, const struct lws_protocols *protocol); LWS_VISIBLE LWS_EXTERN size_t lws_remaining_packet_payload(struct lws *wsi); /* * if the protocol does not have any guidance, returns -1. Currently only * http2 connections get send window information from this API. But your code * should use it so it can work properly with any protocol. * * If nonzero return is the amount of payload data the peer or intermediary has * reported it has buffer space for. That has NO relationship with the amount * of buffer space your OS can accept on this connection for a write action. * * This number represents the maximum you could send to the peer or intermediary * on this connection right now without it complaining. * * lws manages accounting for send window updates and payload writes * automatically, so this number reflects the situation at the peer or * intermediary dynamically. */ LWS_VISIBLE LWS_EXTERN size_t lws_get_peer_write_allowance(struct lws *wsi); /* deprecated, use lws_client_connect_via_info() */ LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_client_connect(struct lws_context *clients, const char *address, int port, int ssl_connection, const char *path, const char *host, const char *origin, const char *protocol, int ietf_version_or_minus_one) LWS_WARN_DEPRECATED; /* deprecated, use lws_client_connect_via_info() */ LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_client_connect_extended(struct lws_context *clients, const char *address, int port, int ssl_connection, const char *path, const char *host, const char *origin, const char *protocol, int ietf_version_or_minus_one, void *userdata) LWS_WARN_DEPRECATED; LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_client_connect_via_info(struct lws_client_connect_info * ccinfo); LWS_VISIBLE LWS_EXTERN struct lws * lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd); LWS_VISIBLE LWS_EXTERN struct lws * lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd, const char *readbuf, size_t len); LWS_VISIBLE LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT lws_canonical_hostname(struct lws_context *context); LWS_VISIBLE LWS_EXTERN void lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name, int name_len, char *rip, int rip_len); LWS_VISIBLE LWS_EXTERN int lws_get_random(struct lws_context *context, void *buf, int len); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_daemonize(const char *_lock_path); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_send_pipe_choked(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_partial_buffered(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_frame_is_binary(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_is_ssl(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_is_cgi(struct lws *wsi); #ifdef LWS_SHA1_USE_OPENSSL_NAME #define lws_SHA1 SHA1 #else LWS_VISIBLE LWS_EXTERN unsigned char * lws_SHA1(const unsigned char *d, size_t n, unsigned char *md); #endif LWS_VISIBLE LWS_EXTERN int lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); LWS_VISIBLE LWS_EXTERN int lws_b64_decode_string(const char *in, char *out, int out_size); LWS_VISIBLE LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT lws_get_library_version(void); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_parse_uri(char *p, const char **prot, const char **ads, int *port, const char **path); /* * Access to http headers * * In lws the client http headers are temporarily malloc'd only for the * duration of the http part of the handshake. It's because in most cases, * the header content is ignored for the whole rest of the connection lifetime * and would then just be taking up space needlessly. * * During LWS_CALLBACK_HTTP when the URI path is delivered is the last time * the http headers are still allocated, you can use these apis then to * look at and copy out interesting header content (cookies, etc) * * Notice that the header total length reported does not include a terminating * '\0', however you must allocate for it when using the _copy apis. So the * length reported for a header containing "123" is 3, but you must provide * a buffer of length 4 so that "123\0" may be copied into it, or the copy * will fail with a nonzero return code. */ LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx); /* * copies the whole, aggregated header, even if it was delivered in * several actual headers piece by piece */ LWS_VISIBLE LWS_EXTERN int lws_hdr_copy(struct lws *wsi, char *dest, int len, enum lws_token_indexes h); /* * copies only fragment frag_idx of a header. Normally this is only useful * to parse URI arguments like ?x=1&y=2, token index WSI_TOKEN_HTTP_URI_ARGS * fragment 0 will contain "x=1" and fragment 1 "y=2" */ LWS_VISIBLE LWS_EXTERN int lws_hdr_copy_fragment(struct lws *wsi, char *dest, int len, enum lws_token_indexes h, int frag_idx); /* get the active file operations struct */ LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * LWS_WARN_UNUSED_RESULT lws_get_fops(struct lws_context *context); LWS_VISIBLE LWS_EXTERN struct lws_context * LWS_WARN_UNUSED_RESULT lws_get_context(const struct lws *wsi); LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_get_count_threads(struct lws_context *context); LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_get_parent(const struct lws *wsi); LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_get_child(const struct lws *wsi); #ifdef LWS_WITH_CGI enum lws_enum_stdinouterr { LWS_STDIN = 0, LWS_STDOUT = 1, LWS_STDERR = 2, }; enum lws_cgi_hdr_state { LCHS_HEADER, LCHS_CR1, LCHS_LF1, LCHS_CR2, LCHS_LF2, LHCS_PAYLOAD, LCHS_SINGLE_0A, }; struct lws_cgi_args { struct lws **stdwsi; /* get fd with lws_get_socket_fd() */ enum lws_enum_stdinouterr ch; unsigned char *data; /* for messages with payload */ enum lws_cgi_hdr_state hdr_state; int len; }; LWS_VISIBLE LWS_EXTERN int lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len, int timeout_secs, const struct lws_protocol_vhost_options *mp_cgienv); LWS_VISIBLE LWS_EXTERN int lws_cgi_write_split_stdout_headers(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_cgi_kill(struct lws *wsi); #endif LWS_VISIBLE LWS_EXTERN int lws_http_client_read(struct lws *wsi, char **buf, int *len); /* * Wsi-associated File Operations access helpers * * Use these helper functions if you want to access a file from the perspective * of a specific wsi, which is usually the case. If you just want contextless * file access, use the fops callbacks directly with NULL wsi instead of these * helpers. * * If so, then it calls the platform handler or user overrides where present * (as defined in info->fops) * * The advantage from all this is user code can be portable for file operations * without having to deal with differences between platforms. */ static LWS_INLINE lws_filefd_type LWS_WARN_UNUSED_RESULT lws_plat_file_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) { return lws_get_fops(lws_get_context(wsi))->open(wsi, filename, filelen, flags); } static LWS_INLINE int lws_plat_file_close(struct lws *wsi, lws_filefd_type fd) { return lws_get_fops(lws_get_context(wsi))->close(wsi, fd); } static LWS_INLINE unsigned long lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset) { return lws_get_fops(lws_get_context(wsi))->seek_cur(wsi, fd, offset); } static LWS_INLINE int LWS_WARN_UNUSED_RESULT lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) { return lws_get_fops(lws_get_context(wsi))->read(wsi, fd, amount, buf, len); } static LWS_INLINE int LWS_WARN_UNUSED_RESULT lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) { return lws_get_fops(lws_get_context(wsi))->write(wsi, fd, amount, buf, len); } /* * Note: this is not normally needed as a user api. It's provided in case it is * useful when integrating with other app poll loop service code. */ LWS_VISIBLE LWS_EXTERN int lws_read(struct lws *wsi, unsigned char *buf, size_t len); #ifndef LWS_NO_EXTENSIONS /* Deprecated * * There is no longer a set internal extensions table. The table is provided * by user code along with application-specific settings. See the test * client and server for how to do. */ static LWS_INLINE LWS_WARN_DEPRECATED const struct lws_extension * lws_get_internal_extensions() { return NULL; } LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi, void *ext_user, const struct lws_ext_options *opts, const char *o, int len); #endif /* * custom allocator support */ LWS_VISIBLE LWS_EXTERN void lws_set_allocator(void *(*realloc)(void *ptr, size_t size)); /** * lws_snprintf(): lws_snprintf that truncates the returned length too * * \param str: destination buffer * \param size: bytes left in destination buffer * \param format: format string * \param ...: args for format * * This lets you correctly truncate buffers by concatenating lengths, if you * reach the limit the reported length doesn't exceed the limit. */ LWS_VISIBLE LWS_EXTERN int lws_snprintf(char *str, size_t size, const char *format, ...); #ifdef __cplusplus } #endif #endif |
Added undroid/libwebsockets/lib/lws-plat-mbed3.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" /* * included from libwebsockets.c for MBED3 builds * MBED3 is an "OS" for very small embedded systems. * He doesn't have Posix semantics or apis. * But he has things like TCP sockets. */ unsigned long long time_in_microseconds(void) { return 0; } LWS_VISIBLE int lws_get_random(struct lws_context *context, void *buf, int len) { int n = len; unsigned char *b = (unsigned char *)buf; (void)context; while (n--) b[n]= rand(); return len; } /* * MBED3 does not have a 'kernel' which takes copies of what userland wants * to send. The user application must hold the tx buffer until it is informed * that send of the user buffer was complete. * * So as soon as you send something the pipe is globally choked. * * There is no concept of additional sent things being maybe acceptable. * You can send one thing up to 64KB at a time and may not try to send * anything else until that is completed. * * You can send things on other sockets, but they cannot complete until they * get their turn at the network device. */ LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi) { #if 0 struct lws_pollfd fds; /* treat the fact we got a truncated send pending as if we're choked */ if (wsi->trunc_len) return 1; fds.fd = wsi->sock; fds.events = POLLOUT; fds.revents = 0; if (poll(&fds, 1, 0) != 1) return 1; if ((fds.revents & POLLOUT) == 0) return 1; /* okay to send another packet without blocking */ #endif (void)wsi; return 0; } LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd) { (void)fd; return -1; } /** * lws_cancel_service() - Cancel servicing of pending websocket activity * @context: Websocket context * * This function let a call to lws_service() waiting for a timeout * immediately return. * * There is no poll() in MBED3, he will fire callbacks when he feels like * it. */ LWS_VISIBLE void lws_cancel_service(struct lws_context *context) { (void)context; } LWS_VISIBLE void lws_cancel_service_pt(struct lws *wsi) { (void)wsi; } LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) { printf("%d: %s", level, line); } LWS_VISIBLE int lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd) { (void)context; (void)fd; return 0; } LWS_VISIBLE void lws_plat_drop_app_privileges(struct lws_context_creation_info *info) { (void)info; } LWS_VISIBLE int lws_plat_context_early_init(void) { return 0; } LWS_VISIBLE void lws_plat_context_early_destroy(struct lws_context *context) { (void)context; } LWS_VISIBLE void lws_plat_context_late_destroy(struct lws_context *context) { (void)context; } LWS_VISIBLE void lws_plat_service_periodic(struct lws_context *context) { (void)context; } LWS_VISIBLE const char * lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) { (void)af; (void)src; (void)dst; (void)cnt; return "unsupported"; } LWS_VISIBLE int insert_wsi(struct lws_context *context, struct lws *wsi) { (void)context; (void)wsi; return 0; } LWS_VISIBLE int delete_from_fd(struct lws_context *context, lws_sockfd_type fd) { (void)context; (void)fd; return 1; } static lws_filefd_type _lws_plat_file_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) { (void)wsi; (void)filename; (void)filelen; (void)flags; return NULL; } static int _lws_plat_file_close(struct lws *wsi, lws_filefd_type fd) { (void)wsi; (void)fd; return -1; } unsigned long _lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset) { (void)wsi; (void)fd; (void)offset; return -1; } static int _lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) { (void)wsi; (void)amount; (void)fd; (void)buf; (void)len; return -1; } static int _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) { (void)wsi; (void)amount; (void)fd; (void)buf; (void)len; return -1; } LWS_VISIBLE int lws_plat_init(struct lws_context *context, struct lws_context_creation_info *info) { (void)info; context->fops.open = _lws_plat_file_open; context->fops.close = _lws_plat_file_close; context->fops.seek_cur = _lws_plat_file_seek_cur; context->fops.read = _lws_plat_file_read; context->fops.write = _lws_plat_file_write; return 0; } |
Added undroid/libwebsockets/lib/lws-plat-mbed3.cpp.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" #include "core-util/CriticalSectionLock.h" extern "C" void *mbed3_create_tcp_stream_socket(void) { lws_conn_listener *srv = new lws_conn_listener; //lwsl_notice("%s: %p\r\n", __func__, (void *)srv); return (void *)srv; } /* this is called by compatible_close() */ extern "C" void mbed3_delete_tcp_stream_socket(void *sock) { lws_conn *conn = (lws_conn *)sock; conn->ts->close(); lwsl_notice("%s: wsi %p: conn %p\r\n", __func__, (void *)conn->wsi, sock); delete conn; } void lws_conn::serialized_writeable(struct lws *_wsi) { struct lws *wsi = (struct lws *)_wsi; struct lws_pollfd pollfd; lws_conn *conn = (lws_conn *)wsi->sock; conn->awaiting_on_writeable = 0; pollfd.fd = wsi->sock; pollfd.events = POLLOUT; pollfd.revents = POLLOUT; lwsl_debug("%s: wsi %p\r\n", __func__, (void *)wsi); lws_service_fd(lws_get_context(wsi), &pollfd); } extern "C" void mbed3_tcp_stream_bind(void *sock, int port, struct lws *wsi) { lws_conn_listener *srv = (lws_conn_listener *)sock; lwsl_debug("%s\r\n", __func__); /* associate us with the listening wsi */ ((lws_conn *)srv)->set_wsi(wsi); mbed::util::FunctionPointer1<void, uint16_t> fp(srv, &lws_conn_listener::start); minar::Scheduler::postCallback(fp.bind(port)); } extern "C" void mbed3_tcp_stream_accept(void *sock, struct lws *wsi) { lws_conn *conn = (lws_conn *)sock; lwsl_debug("%s\r\n", __func__); conn->set_wsi(wsi); } extern "C" LWS_VISIBLE int lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pfd) { lws_conn *conn = (lws_conn *)wsi->sock; (void)context; if (pfd->events & POLLOUT) { conn->awaiting_on_writeable = 1; if (conn->writeable) { mbed::util::FunctionPointer1<void, struct lws *> book(conn, &lws_conn::serialized_writeable); minar::Scheduler::postCallback(book.bind(wsi)); lwsl_debug("%s: wsi %p (booked callback)\r\n", __func__, (void *)wsi); } else { lwsl_debug("%s: wsi %p (set awaiting_on_writeable)\r\n", __func__, (void *)wsi); } } else conn->awaiting_on_writeable = 0; return 0; } extern "C" LWS_VISIBLE int lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len) { socket_error_t err; size_t _len = len; lwsl_debug("%s\r\n", __func__); err = ((lws_conn *)wsi->sock)->ts->recv((char *)buf, &_len); if (err == SOCKET_ERROR_NONE) { lwsl_info("%s: got %d bytes\n", __func__, _len); return _len; } #if LWS_POSIX if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK || LWS_ERRNO == LWS_EINTR) #else if (err == SOCKET_ERROR_WOULD_BLOCK) #endif return LWS_SSL_CAPABLE_MORE_SERVICE; lwsl_warn("error on reading from skt: %d\n", err); return LWS_SSL_CAPABLE_ERROR; } extern "C" LWS_VISIBLE int lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len) { socket_error_t err; lws_conn *conn = (lws_conn *)wsi->sock; lwsl_debug("%s: wsi %p: write %d (from %p)\n", __func__, (void *)wsi, len, (void *)buf); lwsl_debug("%s: wsi %p: clear writeable\n", __func__, (void *)wsi); conn->writeable = 0; err = conn->ts->send((char *)buf, len); if (err == SOCKET_ERROR_NONE) return len; #if LWS_POSIX if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK || LWS_ERRNO == LWS_EINTR) { if (LWS_ERRNO == LWS_EWOULDBLOCK) lws_set_blocking_send(wsi); #else if (err == SOCKET_ERROR_WOULD_BLOCK) return LWS_SSL_CAPABLE_MORE_SERVICE; #endif lwsl_warn("%s: wsi %p: ERROR %d writing len %d to skt\n", __func__, (void *)wsi, err, len); return LWS_SSL_CAPABLE_ERROR; } /* * Set the listening socket to listen. */ void lws_conn_listener::start(const uint16_t port) { socket_error_t err = srv.open(SOCKET_AF_INET4); if (srv.error_check(err)) return; err = srv.bind("0.0.0.0", port); if (srv.error_check(err)) return; err = srv.start_listening(TCPListener::IncomingHandler_t(this, &lws_conn_listener::onIncoming)); srv.error_check(err); } void lws_conn::onRX(Socket *s) { struct lws_pollfd pollfd; (void)s; pollfd.fd = this; pollfd.events = POLLIN; pollfd.revents = POLLIN; lwsl_debug("%s: lws %p\n", __func__, wsi); lws_service_fd(lws_get_context(wsi), &pollfd); } /* * this gets called from the OS when the TCPListener gets a connection that * needs accept()-ing. LWS needs to run the associated flow. */ void lws_conn_listener::onIncoming(TCPListener *tl, void *impl) { mbed::util::CriticalSectionLock lock; lws_conn *conn; if (!impl) { onError(tl, SOCKET_ERROR_NULL_PTR); return; } conn = new(lws_conn); if (!conn) { lwsl_err("OOM\n"); return; } conn->ts = srv.accept(impl); if (!conn->ts) return; conn->ts->setNagle(0); /* * we use the listen socket wsi to get started, but a new wsi is * created. mbed3_tcp_stream_accept() is also called from * here to bind the conn and new wsi together */ lws_server_socket_service(lws_get_context(wsi), wsi, (struct pollfd *)conn); conn->ts->setOnError(TCPStream::ErrorHandler_t(conn, &lws_conn::onError)); conn->ts->setOnDisconnect(TCPStream::DisconnectHandler_t(conn, &lws_conn::onDisconnect)); conn->ts->setOnSent(Socket::SentHandler_t(conn, &lws_conn::onSent)); conn->ts->setOnReadable(TCPStream::ReadableHandler_t(conn, &lws_conn::onRX)); conn->onRX((Socket *)conn->ts); lwsl_debug("%s: exit\n", __func__); } extern "C" LWS_VISIBLE struct lws * wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd) { lws_conn *conn = (lws_conn *)fd; (void)context; return conn->wsi; } extern "C" LWS_VISIBLE void lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi) { (void)wsi; lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ); context->pt[0].fds[context->pt[0].fds_count++].revents = 0; } extern "C" LWS_VISIBLE void lws_plat_delete_socket_from_fds(struct lws_context *context, struct lws *wsi, int m) { (void)context; (void)wsi; (void)m; } void lws_conn_listener::onDisconnect(TCPStream *s) { lwsl_info("%s\r\n", __func__); (void)s; //if (s) //delete this; } extern "C" LWS_VISIBLE int lws_plat_service(struct lws_context *context, int timeout_ms) { (void)context; (void)timeout_ms; return 0; } void lws_conn::onSent(Socket *s, uint16_t len) { struct lws_pollfd pollfd; (void)s; (void)len; if (!awaiting_on_writeable) { lwsl_debug("%s: wsi %p (setting writable=1)\r\n", __func__, (void *)wsi); writeable = 1; return; } writeable = 1; pollfd.fd = wsi->sock; pollfd.events = POLLOUT; pollfd.revents = POLLOUT; lwsl_debug("%s: wsi %p (servicing now)\r\n", __func__, (void *)wsi); lws_service_fd(lws_get_context(wsi), &pollfd); } void lws_conn_listener::onError(Socket *s, socket_error_t err) { (void) s; lwsl_notice("Socket Error: %s (%d)\r\n", socket_strerror(err), err); if (ts) ts->close(); } void lws_conn::onDisconnect(TCPStream *s) { lwsl_notice("%s:\r\n", __func__); (void)s; lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); } void lws_conn::onError(Socket *s, socket_error_t err) { (void) s; lwsl_notice("Socket Error: %s (%d)\r\n", socket_strerror(err), err); s->close(); } |
Added undroid/libwebsockets/lib/lws-plat-unix.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" #include <pwd.h> #include <grp.h> #include <dlfcn.h> #include <dirent.h> /* * included from libwebsockets.c for unix builds */ unsigned long long time_in_microseconds(void) { struct timeval tv; gettimeofday(&tv, NULL); return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec; } LWS_VISIBLE int lws_get_random(struct lws_context *context, void *buf, int len) { return read(context->fd_random, (char *)buf, len); } LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi) { struct lws_pollfd fds; /* treat the fact we got a truncated send pending as if we're choked */ if (wsi->trunc_len) return 1; fds.fd = wsi->sock; fds.events = POLLOUT; fds.revents = 0; if (poll(&fds, 1, 0) != 1) return 1; if ((fds.revents & POLLOUT) == 0) return 1; /* okay to send another packet without blocking */ return 0; } LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd) { return poll(fd, 1, 0); } /** * lws_cancel_service_pt() - Cancel servicing of pending socket activity * on one thread * @wsi: Cancel service on the thread this wsi is serviced by * * This function let a call to lws_service() waiting for a timeout * immediately return. */ LWS_VISIBLE void lws_cancel_service_pt(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; char buf = 0; if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1) lwsl_err("Cannot write to dummy pipe"); } /** * lws_cancel_service() - Cancel ALL servicing of pending socket activity * @context: Websocket context * * This function let a call to lws_service() waiting for a timeout * immediately return. */ LWS_VISIBLE void lws_cancel_service(struct lws_context *context) { struct lws_context_per_thread *pt = &context->pt[0]; char buf = 0, m = context->count_threads; while (m--) { if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1) lwsl_err("Cannot write to dummy pipe"); pt++; } } LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) { int syslog_level = LOG_DEBUG; switch (level) { case LLL_ERR: syslog_level = LOG_ERR; break; case LLL_WARN: syslog_level = LOG_WARNING; break; case LLL_NOTICE: syslog_level = LOG_NOTICE; break; case LLL_INFO: syslog_level = LOG_INFO; break; } syslog(syslog_level, "%s", line); } LWS_VISIBLE int lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; int n = -1, m, c; char buf; /* stay dead once we are dead */ if (!context || !context->vhost_list) return 1; if (timeout_ms < 0) goto faked_service; lws_libev_run(context, tsi); lws_libuv_run(context, tsi); if (!context->service_tid_detected) { struct lws _lws; memset(&_lws, 0, sizeof(_lws)); _lws.context = context; context->service_tid_detected = context->vhost_list->protocols[0].callback( &_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); } context->service_tid = context->service_tid_detected; timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi); n = poll(pt->fds, pt->fds_count, timeout_ms); #ifdef LWS_OPENSSL_SUPPORT if (!pt->rx_draining_ext_list && !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) && !n) { #else if (!pt->rx_draining_ext_list && !n) /* poll timeout */ { #endif lws_service_fd_tsi(context, NULL, tsi); return 0; } faked_service: m = lws_service_flag_pending(context, tsi); if (m) c = -1; /* unknown limit */ else if (n < 0) { if (LWS_ERRNO != LWS_EINTR) return -1; return 0; } else c = n; /* any socket with events to service? */ for (n = 0; n < pt->fds_count && c; n++) { if (!pt->fds[n].revents) continue; c--; if (pt->fds[n].fd == pt->dummy_pipe_fds[0]) { if (read(pt->fds[n].fd, &buf, 1) != 1) lwsl_err("Cannot read from dummy pipe."); continue; } m = lws_service_fd_tsi(context, &pt->fds[n], tsi); if (m < 0) return -1; /* if something closed, retry this slot */ if (m) n--; } return 0; } LWS_VISIBLE int lws_plat_service(struct lws_context *context, int timeout_ms) { return lws_plat_service_tsi(context, timeout_ms, 0); } LWS_VISIBLE int lws_plat_set_socket_options(struct lws_vhost *vhost, int fd) { int optval = 1; socklen_t optlen = sizeof(optval); #if defined(__APPLE__) || \ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) struct protoent *tcp_proto; #endif if (vhost->ka_time) { /* enable keepalive on this socket */ optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&optval, optlen) < 0) return 1; #if defined(__APPLE__) || \ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__CYGWIN__) || defined(__OpenBSD__) /* * didn't find a way to set these per-socket, need to * tune kernel systemwide values */ #else /* set the keepalive conditions we want on it too */ optval = vhost->ka_time; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (const void *)&optval, optlen) < 0) return 1; optval = vhost->ka_interval; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, (const void *)&optval, optlen) < 0) return 1; optval = vhost->ka_probes; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (const void *)&optval, optlen) < 0) return 1; #endif } /* Disable Nagle */ optval = 1; #if !defined(__APPLE__) && \ !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \ !defined(__NetBSD__) && \ !defined(__OpenBSD__) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) return 1; #else tcp_proto = getprotobyname("TCP"); if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0) return 1; #endif /* We are nonblocking... */ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) return 1; return 0; } LWS_VISIBLE void lws_plat_drop_app_privileges(struct lws_context_creation_info *info) { if (info->gid != -1) if (setgid(info->gid)) lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO)); if (info->uid != -1) { struct passwd *p = getpwuid(info->uid); if (p) { initgroups(p->pw_name, info->gid); if (setuid(info->uid)) lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO)); else lwsl_notice("Set privs to user '%s'\n", p->pw_name); } else lwsl_warn("getpwuid: unable to find uid %d", info->uid); } } #ifdef LWS_WITH_PLUGINS #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0 /* libuv.c implements these in a cross-platform way */ #else static int filter(const struct dirent *ent) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) return 0; return 1; } LWS_VISIBLE int lws_plat_plugins_init(struct lws_context * context, const char * const *d) { struct lws_plugin_capability lcaps; struct lws_plugin *plugin; lws_plugin_init_func initfunc; struct dirent **namelist; int n, i, m, ret = 0; char path[256]; void *l; lwsl_notice(" Plugins:\n"); while (d && *d) { n = scandir(*d, &namelist, filter, alphasort); if (n < 0) { lwsl_err("Scandir on %s failed\n", *d); return 1; } for (i = 0; i < n; i++) { if (strlen(namelist[i]->d_name) < 7) goto inval; lwsl_notice(" %s\n", namelist[i]->d_name); lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d, namelist[i]->d_name); l = dlopen(path, RTLD_NOW); if (!l) { lwsl_err("Error loading DSO: %s\n", dlerror()); while (i++ < n) free(namelist[i]); goto bail; } /* we could open it, can we get his init function? */ m = lws_snprintf(path, sizeof(path) - 1, "init_%s", namelist[i]->d_name + 3 /* snip lib... */); path[m - 3] = '\0'; /* snip the .so */ initfunc = dlsym(l, path); if (!initfunc) { lwsl_err("Failed to get init on %s: %s", namelist[i]->d_name, dlerror()); dlclose(l); } lcaps.api_magic = LWS_PLUGIN_API_MAGIC; m = initfunc(context, &lcaps); if (m) { lwsl_err("Initializing %s failed %d\n", namelist[i]->d_name, m); dlclose(l); goto skip; } plugin = lws_malloc(sizeof(*plugin)); if (!plugin) { lwsl_err("OOM\n"); goto bail; } plugin->list = context->plugin_list; context->plugin_list = plugin; strncpy(plugin->name, namelist[i]->d_name, sizeof(plugin->name) - 1); plugin->name[sizeof(plugin->name) - 1] = '\0'; plugin->l = l; plugin->caps = lcaps; context->plugin_protocol_count += lcaps.count_protocols; context->plugin_extension_count += lcaps.count_extensions; free(namelist[i]); continue; skip: dlclose(l); inval: free(namelist[i]); } free(namelist); d++; } bail: free(namelist); return ret; } LWS_VISIBLE int lws_plat_plugins_destroy(struct lws_context * context) { struct lws_plugin *plugin = context->plugin_list, *p; lws_plugin_destroy_func func; char path[256]; int m; if (!plugin) return 0; lwsl_notice("%s\n", __func__); while (plugin) { p = plugin; m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3); path[m - 3] = '\0'; func = dlsym(plugin->l, path); if (!func) { lwsl_err("Failed to get destroy on %s: %s", plugin->name, dlerror()); goto next; } m = func(context); if (m) lwsl_err("Initializing %s failed %d\n", plugin->name, m); next: dlclose(p->l); plugin = p->list; p->list = NULL; free(p); } context->plugin_list = NULL; return 0; } #endif #endif #if 0 static void sigabrt_handler(int x) { printf("%s\n", __func__); //*(char *)0 = 0; } #endif LWS_VISIBLE int lws_plat_context_early_init(void) { signal(SIGPIPE, SIG_IGN); // signal(SIGABRT, sigabrt_handler); return 0; } LWS_VISIBLE void lws_plat_context_early_destroy(struct lws_context *context) { } LWS_VISIBLE void lws_plat_context_late_destroy(struct lws_context *context) { struct lws_context_per_thread *pt = &context->pt[0]; int m = context->count_threads; #ifdef LWS_WITH_PLUGINS if (context->plugin_list) lws_plat_plugins_destroy(context); #endif if (context->lws_lookup) lws_free(context->lws_lookup); while (m--) { close(pt->dummy_pipe_fds[0]); close(pt->dummy_pipe_fds[1]); pt++; } close(context->fd_random); } /* cast a struct sockaddr_in6 * into addr for ipv6 */ LWS_VISIBLE int lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, size_t addrlen) { int rc = -1; struct ifaddrs *ifr; struct ifaddrs *ifc; #ifdef LWS_USE_IPV6 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; #endif getifaddrs(&ifr); for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) { if (!ifc->ifa_addr) continue; lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname); if (strcmp(ifc->ifa_name, ifname)) continue; switch (ifc->ifa_addr->sa_family) { case AF_INET: #ifdef LWS_USE_IPV6 if (ipv6) { /* map IPv4 to IPv6 */ bzero((char *)&addr6->sin6_addr, sizeof(struct in6_addr)); addr6->sin6_addr.s6_addr[10] = 0xff; addr6->sin6_addr.s6_addr[11] = 0xff; memcpy(&addr6->sin6_addr.s6_addr[12], &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr, sizeof(struct in_addr)); } else #endif memcpy(addr, (struct sockaddr_in *)ifc->ifa_addr, sizeof(struct sockaddr_in)); break; #ifdef LWS_USE_IPV6 case AF_INET6: memcpy(&addr6->sin6_addr, &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); break; #endif default: continue; } rc = 0; } freeifaddrs(ifr); if (rc == -1) { /* check if bind to IP adddress */ #ifdef LWS_USE_IPV6 if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) rc = 0; else #endif if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1) rc = 0; } return rc; } LWS_VISIBLE void lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ); lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ); pt->fds[pt->fds_count++].revents = 0; } LWS_VISIBLE void lws_plat_delete_socket_from_fds(struct lws_context *context, struct lws *wsi, int m) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); pt->fds_count--; } LWS_VISIBLE void lws_plat_service_periodic(struct lws_context *context) { /* if our parent went down, don't linger around */ if (context->started_with_parent && kill(context->started_with_parent, 0) < 0) kill(getpid(), SIGTERM); } LWS_VISIBLE int lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pfd) { return 0; } LWS_VISIBLE const char * lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) { return inet_ntop(af, src, dst, cnt); } static lws_filefd_type _lws_plat_file_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) { struct stat stat_buf; int ret = open(filename, flags, 0664); if (ret < 0) return LWS_INVALID_FILE; if (fstat(ret, &stat_buf) < 0) { close(ret); return LWS_INVALID_FILE; } *filelen = stat_buf.st_size; return ret; } static int _lws_plat_file_close(struct lws *wsi, lws_filefd_type fd) { return close(fd); } unsigned long _lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset) { return lseek(fd, offset, SEEK_CUR); } static int _lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) { long n; n = read((int)fd, buf, len); if (n == -1) { *amount = 0; return -1; } *amount = n; return 0; } static int _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char *buf, unsigned long len) { long n; n = write((int)fd, buf, len); if (n == -1) { *amount = 0; return -1; } *amount = n; return 0; } LWS_VISIBLE int lws_plat_init(struct lws_context *context, struct lws_context_creation_info *info) { struct lws_context_per_thread *pt = &context->pt[0]; int n = context->count_threads, fd; /* master context has the global fd lookup array */ context->lws_lookup = lws_zalloc(sizeof(struct lws *) * context->max_fds); if (context->lws_lookup == NULL) { lwsl_err("OOM on lws_lookup array for %d connections\n", context->max_fds); return 1; } lwsl_notice(" mem: platform fd map: %5u bytes\n", sizeof(struct lws *) * context->max_fds); fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); context->fd_random = fd; if (context->fd_random < 0) { lwsl_err("Unable to open random device %s %d\n", SYSTEM_RANDOM_FILEPATH, context->fd_random); return 1; } if (!lws_libev_init_fd_table(context) && !lws_libuv_init_fd_table(context)) { /* otherwise libev handled it instead */ while (n--) { if (pipe(pt->dummy_pipe_fds)) { lwsl_err("Unable to create pipe\n"); return 1; } /* use the read end of pipe as first item */ pt->fds[0].fd = pt->dummy_pipe_fds[0]; pt->fds[0].events = LWS_POLLIN; pt->fds[0].revents = 0; pt->fds_count = 1; pt++; } } context->fops.open = _lws_plat_file_open; context->fops.close = _lws_plat_file_close; context->fops.seek_cur = _lws_plat_file_seek_cur; context->fops.read = _lws_plat_file_read; context->fops.write = _lws_plat_file_write; #ifdef LWS_WITH_PLUGINS if (info->plugin_dirs) lws_plat_plugins_init(context, info->plugin_dirs); #endif return 0; } |
Added undroid/libwebsockets/lib/lws-plat-win.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #ifndef _WINSOCK_DEPRECATED_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #endif #include "private-libwebsockets.h" unsigned long long time_in_microseconds() { #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL FILETIME filetime; ULARGE_INTEGER datetime; #ifdef _WIN32_WCE GetCurrentFT(&filetime); #else GetSystemTimeAsFileTime(&filetime); #endif /* * As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a * ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can * prevent alignment faults on 64-bit Windows). */ memcpy(&datetime, &filetime, sizeof(datetime)); /* Windows file times are in 100s of nanoseconds. */ return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10; } #ifdef _WIN32_WCE time_t time(time_t *t) { time_t ret = time_in_microseconds() / 1000000; if(t != NULL) *t = ret; return ret; } #endif /* file descriptor hash management */ struct lws * wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd) { int h = LWS_FD_HASH(fd); int n = 0; for (n = 0; n < context->fd_hashtable[h].length; n++) if (context->fd_hashtable[h].wsi[n]->sock == fd) return context->fd_hashtable[h].wsi[n]; return NULL; } int insert_wsi(struct lws_context *context, struct lws *wsi) { int h = LWS_FD_HASH(wsi->sock); if (context->fd_hashtable[h].length == (getdtablesize() - 1)) { lwsl_err("hash table overflow\n"); return 1; } context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi; return 0; } int delete_from_fd(struct lws_context *context, lws_sockfd_type fd) { int h = LWS_FD_HASH(fd); int n = 0; for (n = 0; n < context->fd_hashtable[h].length; n++) if (context->fd_hashtable[h].wsi[n]->sock == fd) { while (n < context->fd_hashtable[h].length) { context->fd_hashtable[h].wsi[n] = context->fd_hashtable[h].wsi[n + 1]; n++; } context->fd_hashtable[h].length--; return 0; } lwsl_err("Failed to find fd %d requested for " "delete in hashtable\n", fd); return 1; } LWS_VISIBLE int lws_get_random(struct lws_context *context, void *buf, int len) { int n; char *p = (char *)buf; for (n = 0; n < len; n++) p[n] = (unsigned char)rand(); return n; } LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi) { return (int)wsi->sock_send_blocking; } LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd) { fd_set readfds; struct timeval tv = { 0, 0 }; assert((fd->events & LWS_POLLIN) == LWS_POLLIN); FD_ZERO(&readfds); FD_SET(fd->fd, &readfds); return select(fd->fd + 1, &readfds, NULL, NULL, &tv); } /** * lws_cancel_service() - Cancel servicing of pending websocket activity * @context: Websocket context * * This function let a call to lws_service() waiting for a timeout * immediately return. */ LWS_VISIBLE void lws_cancel_service(struct lws_context *context) { struct lws_context_per_thread *pt = &context->pt[0]; int n = context->count_threads; while (n--) { WSASetEvent(pt->events[0]); pt++; } } LWS_VISIBLE void lws_cancel_service_pt(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; WSASetEvent(pt->events[0]); } LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) { lwsl_emit_stderr(level, line); } LWS_VISIBLE int lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; WSANETWORKEVENTS networkevents; struct lws_pollfd *pfd; struct lws *wsi; unsigned int i; DWORD ev; int n, m; /* stay dead once we are dead */ if (context == NULL) return 1; if (!context->service_tid_detected) { struct lws _lws; memset(&_lws, 0, sizeof(_lws)); _lws.context = context; context->service_tid_detected = context->vhost_list-> protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); } context->service_tid = context->service_tid_detected; if (timeout_ms < 0) goto faked_service; for (i = 0; i < pt->fds_count; ++i) { pfd = &pt->fds[i]; if (!(pfd->events & LWS_POLLOUT)) continue; wsi = wsi_from_fd(context, pfd->fd); if (wsi->listener) continue; if (!wsi || wsi->sock_send_blocking) continue; pfd->revents = LWS_POLLOUT; n = lws_service_fd(context, pfd); if (n < 0) return -1; /* if something closed, retry this slot */ if (n) i--; } /* if we know something needs service already, don't wait in poll */ timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi); ev = WSAWaitForMultipleEvents(pt->fds_count + 1, pt->events, FALSE, timeout_ms, FALSE); context->service_tid = 0; if (ev == WSA_WAIT_TIMEOUT) { lws_service_fd(context, NULL); return 0; } if (ev == WSA_WAIT_EVENT_0) { WSAResetEvent(pt->events[0]); return 0; } if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + pt->fds_count) return -1; pfd = &pt->fds[ev - WSA_WAIT_EVENT_0 - 1]; /* eh... is one event at a time the best windows can do? */ if (WSAEnumNetworkEvents(pfd->fd, pt->events[ev - WSA_WAIT_EVENT_0], &networkevents) == SOCKET_ERROR) { lwsl_err("WSAEnumNetworkEvents() failed with error %d\n", LWS_ERRNO); return -1; } pfd->revents = (short)networkevents.lNetworkEvents; if (pfd->revents & LWS_POLLOUT) { wsi = wsi_from_fd(context, pfd->fd); if (wsi) wsi->sock_send_blocking = 0; } faked_service: /* if someone faked their LWS_POLLIN, then go through all active fds */ if (lws_service_flag_pending(context, tsi)) { /* any socket with events to service? */ for (n = 0; n < (int)pt->fds_count; n++) { if (!pt->fds[n].revents) continue; m = lws_service_fd_tsi(context, &pt->fds[n], tsi); if (m < 0) return -1; /* if something closed, retry this slot */ if (m) n--; } return 0; } if (timeout_ms < 0) return 0; /* otherwise just do the one... must be a way to improve that... */ return lws_service_fd_tsi(context, pfd, tsi); } LWS_VISIBLE int lws_plat_service(struct lws_context *context, int timeout_ms) { return lws_plat_service_tsi(context, timeout_ms, 0); } LWS_VISIBLE int lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd) { int optval = 1; int optlen = sizeof(optval); u_long optl = 1; DWORD dwBytesRet; struct tcp_keepalive alive; int protonbr; #ifndef _WIN32_WCE struct protoent *tcp_proto; #endif if (vhost->ka_time) { /* enable keepalive on this socket */ optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&optval, optlen) < 0) return 1; alive.onoff = TRUE; alive.keepalivetime = vhost->ka_time; alive.keepaliveinterval = vhost->ka_interval; if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive), NULL, 0, &dwBytesRet, NULL, NULL)) return 1; } /* Disable Nagle */ optval = 1; #ifndef _WIN32_WCE tcp_proto = getprotobyname("TCP"); if (!tcp_proto) { lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO); return 1; } protonbr = tcp_proto->p_proto; #else protonbr = 6; #endif setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen); /* We are nonblocking... */ ioctlsocket(fd, FIONBIO, &optl); return 0; } LWS_VISIBLE void lws_plat_drop_app_privileges(struct lws_context_creation_info *info) { } LWS_VISIBLE int lws_plat_context_early_init(void) { WORD wVersionRequested; WSADATA wsaData; int err; /* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */ wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (!err) return 0; /* * Tell the user that we could not find a usable * Winsock DLL */ lwsl_err("WSAStartup failed with error: %d\n", err); return 1; } LWS_VISIBLE void lws_plat_context_early_destroy(struct lws_context *context) { struct lws_context_per_thread *pt = &context->pt[0]; int n = context->count_threads; while (n--) { if (pt->events) { WSACloseEvent(pt->events[0]); lws_free(pt->events); } pt++; } } LWS_VISIBLE void lws_plat_context_late_destroy(struct lws_context *context) { int n; for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { if (context->fd_hashtable[n].wsi) lws_free(context->fd_hashtable[n].wsi); } WSACleanup(); } LWS_VISIBLE LWS_EXTERN int lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, size_t addrlen) { long long address = inet_addr(ifname); if (address == INADDR_NONE) { struct hostent *entry = gethostbyname(ifname); if (entry) address = ((struct in_addr *)entry->h_addr_list[0])->s_addr; } if (address == INADDR_NONE) return -1; addr->sin_addr.s_addr = (unsigned long)address; return 0; } LWS_VISIBLE void lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; pt->fds[pt->fds_count++].revents = 0; pt->events[pt->fds_count] = WSACreateEvent(); WSAEventSelect(wsi->sock, pt->events[pt->fds_count], LWS_POLLIN | LWS_POLLHUP); } LWS_VISIBLE void lws_plat_delete_socket_from_fds(struct lws_context *context, struct lws *wsi, int m) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; WSACloseEvent(pt->events[m + 1]); pt->events[m + 1] = pt->events[pt->fds_count--]; } LWS_VISIBLE void lws_plat_service_periodic(struct lws_context *context) { } LWS_VISIBLE int lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pfd) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; long networkevents = LWS_POLLHUP; if ((pfd->events & LWS_POLLIN)) networkevents |= LWS_POLLIN; if ((pfd->events & LWS_POLLOUT)) networkevents |= LWS_POLLOUT; if (WSAEventSelect(wsi->sock, pt->events[wsi->position_in_fds_table + 1], networkevents) != SOCKET_ERROR) return 0; lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO); return 1; } LWS_VISIBLE const char * lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) { WCHAR *buffer; DWORD bufferlen = cnt; BOOL ok = FALSE; buffer = lws_malloc(bufferlen); if (!buffer) { lwsl_err("Out of memory\n"); return NULL; } if (af == AF_INET) { struct sockaddr_in srcaddr; bzero(&srcaddr, sizeof(srcaddr)); srcaddr.sin_family = AF_INET; memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr)); if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen)) ok = TRUE; #ifdef LWS_USE_IPV6 } else if (af == AF_INET6) { struct sockaddr_in6 srcaddr; bzero(&srcaddr, sizeof(srcaddr)); srcaddr.sin6_family = AF_INET6; memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr)); if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen)) ok = TRUE; #endif } else lwsl_err("Unsupported type\n"); if (!ok) { int rv = WSAGetLastError(); lwsl_err("WSAAddressToString() : %d\n", rv); } else { if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0) ok = FALSE; } lws_free(buffer); return ok ? dst : NULL; } static lws_filefd_type _lws_plat_file_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) { HANDLE ret; WCHAR buf[MAX_PATH]; (void)wsi; MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf)); if ((flags & 7) == _O_RDONLY) { ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { lwsl_err("%s: open for write not implemented\n", __func__); *filelen = 0; return LWS_INVALID_FILE; } if (ret != LWS_INVALID_FILE) *filelen = GetFileSize(ret, NULL); return ret; } static int _lws_plat_file_close(struct lws *wsi, lws_filefd_type fd) { (void)wsi; CloseHandle((HANDLE)fd); return 0; } static unsigned long _lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset) { (void)wsi; return SetFilePointer((HANDLE)fd, offset, NULL, FILE_CURRENT); } static int _lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char* buf, unsigned long len) { DWORD _amount; if (!ReadFile((HANDLE)fd, buf, (DWORD)len, &_amount, NULL)) { *amount = 0; return 1; } *amount = (unsigned long)_amount; return 0; } static int _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount, unsigned char* buf, unsigned long len) { (void)wsi; (void)fd; (void)amount; (void)buf; (void)len; lwsl_err("%s: not implemented yet on this platform\n", __func__); return -1; } LWS_VISIBLE int lws_plat_init(struct lws_context *context, struct lws_context_creation_info *info) { struct lws_context_per_thread *pt = &context->pt[0]; int i, n = context->count_threads; for (i = 0; i < FD_HASHTABLE_MODULUS; i++) { context->fd_hashtable[i].wsi = lws_zalloc(sizeof(struct lws*) * context->max_fds); if (!context->fd_hashtable[i].wsi) return -1; } while (n--) { pt->events = lws_malloc(sizeof(WSAEVENT) * (context->fd_limit_per_thread + 1)); if (pt->events == NULL) { lwsl_err("Unable to allocate events array for %d connections\n", context->fd_limit_per_thread + 1); return 1; } pt->fds_count = 0; pt->events[0] = WSACreateEvent(); pt++; } context->fd_random = 0; context->fops.open = _lws_plat_file_open; context->fops.close = _lws_plat_file_close; context->fops.seek_cur = _lws_plat_file_seek_cur; context->fops.read = _lws_plat_file_read; context->fops.write = _lws_plat_file_write; return 0; } |
Added undroid/libwebsockets/lib/minihuf.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * minilex.c * * High efficiency lexical state parser * * Copyright (C)2011-2014 Andy Green <andy@warmcat.com> * * Licensed under LGPL2 * * Usage: gcc minihuf.c -o minihuf && ./minihuf > huftable.h * * Run it twice to test parsing on the generated table on stderr */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define ARRAY_SIZE(n) (sizeof(n) / sizeof(n[0])) struct huf { unsigned int code; unsigned char len; }; static struct huf huf_literal[] = { /* 0x00 */ { 0x1ff8, 13 }, /* 0x01 */ { 0x7fffd8, 23 }, /* 0x02 */ { 0xfffffe2, 28 }, /* 0x03 */ { 0xfffffe3, 28 }, /* 0x04 */ { 0xfffffe4, 28 }, /* 0x05 */ { 0xfffffe5, 28 }, /* 0x06 */ { 0xfffffe6, 28 }, /* 0x07 */ { 0xfffffe7, 28 }, /* 0x08 */ { 0xfffffe8, 28 }, /* 0x09 */ { 0xffffea, 24 }, /* 0x0a */ { 0x3ffffffc, 30 }, /* 0x0b */ { 0xfffffe9, 28 }, /* 0x0c */ { 0xfffffea, 28 }, /* 0x0d */ { 0x3ffffffd, 30 }, /* 0x0e */ { 0xfffffeb, 28 }, /* 0x0f */ { 0xfffffec, 28 }, /* 0x10 */ { 0xfffffed, 28 }, /* 0x11 */ { 0xfffffee, 28 }, /* 0x12 */ { 0xfffffef, 28 }, /* 0x13 */ { 0xffffff0, 28 }, /* 0x14 */ { 0xffffff1, 28 }, /* 0x15 */ { 0xffffff2, 28 }, /* 0x16 */ { 0x3ffffffe, 30 }, /* 0x17 */ { 0xffffff3, 28 }, /* 0x18 */ { 0xffffff4, 28 }, /* 0x19 */ { 0xffffff5, 28 }, /* 0x1a */ { 0xffffff6, 28 }, /* 0x1b */ { 0xffffff7, 28 }, /* 0x1c */ { 0xffffff8, 28 }, /* 0x1d */ { 0xffffff9, 28 }, /* 0x1e */ { 0xffffffa, 28 }, /* 0x1f */ { 0xffffffb, 28 }, /* 0x20 */ { 0x14, 6 }, /* 0x21 */ { 0x3f8, 10 }, /* 0x22 */ { 0x3f9, 10 }, /* 0x23 */ { 0xffa, 12 }, /* 0x24 */ { 0x1ff9, 13 }, /* 0x25 */ { 0x15, 6 }, /* 0x26 */ { 0xf8, 8 }, /* 0x27 */ { 0x7fa, 11 }, /* 0x28 */ { 0x3fa, 10 }, /* 0x29 */ { 0x3fb, 10 }, /* 0x2a */ { 0xf9, 8 }, /* 0x2b */ { 0x7fb, 11 }, /* 0x2c */ { 0xfa, 8 }, /* 0x2d */ { 0x16, 6 }, /* 0x2e */ { 0x17, 6 }, /* 0x2f */ { 0x18, 6 }, /* 0x30 */ { 0x0, 5 }, /* 0x31 */ { 0x1, 5 }, /* 0x32 */ { 0x2, 5 }, /* 0x33 */ { 0x19, 6 }, /* 0x34 */ { 0x1a, 6 }, /* 0x35 */ { 0x1b, 6 }, /* 0x36 */ { 0x1c, 6 }, /* 0x37 */ { 0x1d, 6 }, /* 0x38 */ { 0x1e, 6 }, /* 0x39 */ { 0x1f, 6 }, /* 0x3a */ { 0x5c, 7 }, /* 0x3b */ { 0xfb, 8 }, /* 0x3c */ { 0x7ffc, 15 }, /* 0x3d */ { 0x20, 6 }, /* 0x3e */ { 0xffb, 12 }, /* 0x3f */ { 0x3fc, 10 }, /* 0x40 */ { 0x1ffa, 13 }, /* 0x41 */ { 0x21, 6 }, /* 0x42 */ { 0x5d, 7 }, /* 0x43 */ { 0x5e, 7 }, /* 0x44 */ { 0x5f, 7 }, /* 0x45 */ { 0x60, 7 }, /* 0x46 */ { 0x61, 7 }, /* 0x47 */ { 0x62, 7 }, /* 0x48 */ { 0x63, 7 }, /* 0x49 */ { 0x64, 7 }, /* 0x4a */ { 0x65, 7 }, /* 0x4b */ { 0x66, 7 }, /* 0x4c */ { 0x67, 7 }, /* 0x4d */ { 0x68, 7 }, /* 0x4e */ { 0x69, 7 }, /* 0x4f */ { 0x6a, 7 }, /* 0x50 */ { 0x6b, 7 }, /* 0x51 */ { 0x6c, 7 }, /* 0x52 */ { 0x6d, 7 }, /* 0x53 */ { 0x6e, 7 }, /* 0x54 */ { 0x6f, 7 }, /* 0x55 */ { 0x70, 7 }, /* 0x56 */ { 0x71, 7 }, /* 0x57 */ { 0x72, 7 }, /* 0x58 */ { 0xfc, 8 }, /* 0x59 */ { 0x73, 7 }, /* 0x5a */ { 0xfd, 8 }, /* 0x5b */ { 0x1ffb, 13 }, /* 0x5c */ { 0x7fff0, 19 }, /* 0x5d */ { 0x1ffc, 13 }, /* 0x5e */ { 0x3ffc, 14 }, /* 0x5f */ { 0x22, 6 }, /* 0x60 */ { 0x7ffd, 15 }, /* 0x61 */ { 0x3, 5 }, /* 0x62 */ { 0x23, 6 }, /* 0x63 */ { 0x4, 5 }, /* 0x64 */ { 0x24, 6 }, /* 0x65 */ { 0x5, 5 }, /* 0x66 */ { 0x25, 6 }, /* 0x67 */ { 0x26, 6 }, /* 0x68 */ { 0x27, 6 }, /* 0x69 */ { 0x6, 5 }, /* 0x6a */ { 0x74, 7 }, /* 0x6b */ { 0x75, 7 }, /* 0x6c */ { 0x28, 6 }, /* 0x6d */ { 0x29, 6 }, /* 0x6e */ { 0x2a, 6 }, /* 0x6f */ { 0x7, 5 }, /* 0x70 */ { 0x2b, 6 }, /* 0x71 */ { 0x76, 7 }, /* 0x72 */ { 0x2c, 6 }, /* 0x73 */ { 0x8, 5 }, /* 0x74 */ { 0x9, 5 }, /* 0x75 */ { 0x2d, 6 }, /* 0x76 */ { 0x77, 7 }, /* 0x77 */ { 0x78, 7 }, /* 0x78 */ { 0x79, 7 }, /* 0x79 */ { 0x7a, 7 }, /* 0x7a */ { 0x7b, 7 }, /* 0x7b */ { 0x7ffe, 15 }, /* 0x7c */ { 0x7fc, 11 }, /* 0x7d */ { 0x3ffd, 14 }, /* 0x7e */ { 0x1ffd, 13 }, /* 0x7f */ { 0xffffffc, 28 }, /* 0x80 */ { 0xfffe6, 20 }, /* 0x81 */ { 0x3fffd2, 22 }, /* 0x82 */ { 0xfffe7, 20 }, /* 0x83 */ { 0xfffe8, 20 }, /* 0x84 */ { 0x3fffd3, 22 }, /* 0x85 */ { 0x3fffd4, 22 }, /* 0x86 */ { 0x3fffd5, 22 }, /* 0x87 */ { 0x7fffd9, 23 }, /* 0x88 */ { 0x3fffd6, 22 }, /* 0x89 */ { 0x7fffda, 23 }, /* 0x8a */ { 0x7fffdb, 23 }, /* 0x8b */ { 0x7fffdc, 23 }, /* 0x8c */ { 0x7fffdd, 23 }, /* 0x8d */ { 0x7fffde, 23 }, /* 0x8e */ { 0xffffeb, 24 }, /* 0x8f */ { 0x7fffdf, 23 }, /* 0x90 */ { 0xffffec, 24 }, /* 0x91 */ { 0xffffed, 24 }, /* 0x92 */ { 0x3fffd7, 22 }, /* 0x93 */ { 0x7fffe0, 23 }, /* 0x94 */ { 0xffffee, 24 }, /* 0x95 */ { 0x7fffe1, 23 }, /* 0x96 */ { 0x7fffe2, 23 }, /* 0x97 */ { 0x7fffe3, 23 }, /* 0x98 */ { 0x7fffe4, 23 }, /* 0x99 */ { 0x1fffdc, 21 }, /* 0x9a */ { 0x3fffd8, 22 }, /* 0x9b */ { 0x7fffe5, 23 }, /* 0x9c */ { 0x3fffd9, 22 }, /* 0x9d */ { 0x7fffe6, 23 }, /* 0x9e */ { 0x7fffe7, 23 }, /* 0x9f */ { 0xffffef, 24 }, /* 0xa0 */ { 0x3fffda, 22 }, /* 0xa1 */ { 0x1fffdd, 21 }, /* 0xa2 */ { 0xfffe9, 20 }, /* 0xa3 */ { 0x3fffdb, 22 }, /* 0xa4 */ { 0x3fffdc, 22 }, /* 0xa5 */ { 0x7fffe8, 23 }, /* 0xa6 */ { 0x7fffe9, 23 }, /* 0xa7 */ { 0x1fffde, 21 }, /* 0xa8 */ { 0x7fffea, 23 }, /* 0xa9 */ { 0x3fffdd, 22 }, /* 0xaa */ { 0x3fffde, 22 }, /* 0xab */ { 0xfffff0, 24 }, /* 0xac */ { 0x1fffdf, 21 }, /* 0xad */ { 0x3fffdf, 22 }, /* 0xae */ { 0x7fffeb, 23 }, /* 0xaf */ { 0x7fffec, 23 }, /* 0xb0 */ { 0x1fffe0, 21 }, /* 0xb1 */ { 0x1fffe1, 21 }, /* 0xb2 */ { 0x3fffe0, 22 }, /* 0xb3 */ { 0x1fffe2, 21 }, /* 0xb4 */ { 0x7fffed, 23 }, /* 0xb5 */ { 0x3fffe1, 22 }, /* 0xb6 */ { 0x7fffee, 23 }, /* 0xb7 */ { 0x7fffef, 23 }, /* 0xb8 */ { 0xfffea, 20 }, /* 0xb9 */ { 0x3fffe2, 22 }, /* 0xba */ { 0x3fffe3, 22 }, /* 0xbb */ { 0x3fffe4, 22 }, /* 0xbc */ { 0x7ffff0, 23 }, /* 0xbd */ { 0x3fffe5, 22 }, /* 0xbe */ { 0x3fffe6, 22 }, /* 0xbf */ { 0x7ffff1, 23 }, /* 0xc0 */ { 0x3ffffe0, 26 }, /* 0xc1 */ { 0x3ffffe1, 26 }, /* 0xc2 */ { 0xfffeb, 20 }, /* 0xc3 */ { 0x7fff1, 19 }, /* 0xc4 */ { 0x3fffe7, 22 }, /* 0xc5 */ { 0x7ffff2, 23 }, /* 0xc6 */ { 0x3fffe8, 22 }, /* 0xc7 */ { 0x1ffffec, 25 }, /* 0xc8 */ { 0x3ffffe2, 26 }, /* 0xc9 */ { 0x3ffffe3, 26 }, /* 0xca */ { 0x3ffffe4, 26 }, /* 0xcb */ { 0x7ffffde, 27 }, /* 0xcc */ { 0x7ffffdf, 27 }, /* 0xcd */ { 0x3ffffe5, 26 }, /* 0xce */ { 0xfffff1, 24 }, /* 0xcf */ { 0x1ffffed, 25 }, /* 0xd0 */ { 0x7fff2, 19 }, /* 0xd1 */ { 0x1fffe3, 21 }, /* 0xd2 */ { 0x3ffffe6, 26 }, /* 0xd3 */ { 0x7ffffe0, 27 }, /* 0xd4 */ { 0x7ffffe1, 27 }, /* 0xd5 */ { 0x3ffffe7, 26 }, /* 0xd6 */ { 0x7ffffe2, 27 }, /* 0xd7 */ { 0xfffff2, 24 }, /* 0xd8 */ { 0x1fffe4, 21 }, /* 0xd9 */ { 0x1fffe5, 21 }, /* 0xda */ { 0x3ffffe8, 26 }, /* 0xdb */ { 0x3ffffe9, 26 }, /* 0xdc */ { 0xffffffd, 28 }, /* 0xdd */ { 0x7ffffe3, 27 }, /* 0xde */ { 0x7ffffe4, 27 }, /* 0xdf */ { 0x7ffffe5, 27 }, /* 0xe0 */ { 0xfffec, 20 }, /* 0xe1 */ { 0xfffff3, 24 }, /* 0xe2 */ { 0xfffed, 20 }, /* 0xe3 */ { 0x1fffe6, 21 }, /* 0xe4 */ { 0x3fffe9, 22 }, /* 0xe5 */ { 0x1fffe7, 21 }, /* 0xe6 */ { 0x1fffe8, 21 }, /* 0xe7 */ { 0x7ffff3, 23 }, /* 0xe8 */ { 0x3fffea, 22 }, /* 0xe9 */ { 0x3fffeb, 22 }, /* 0xea */ { 0x1ffffee, 25 }, /* 0xeb */ { 0x1ffffef, 25 }, /* 0xec */ { 0xfffff4, 24 }, /* 0xed */ { 0xfffff5, 24 }, /* 0xee */ { 0x3ffffea, 26 }, /* 0xef */ { 0x7ffff4, 23 }, /* 0xf0 */ { 0x3ffffeb, 26 }, /* 0xf1 */ { 0x7ffffe6, 27 }, /* 0xf2 */ { 0x3ffffec, 26 }, /* 0xf3 */ { 0x3ffffed, 26 }, /* 0xf4 */ { 0x7ffffe7, 27 }, /* 0xf5 */ { 0x7ffffe8, 27 }, /* 0xf6 */ { 0x7ffffe9, 27 }, /* 0xf7 */ { 0x7ffffea, 27 }, /* 0xf8 */ { 0x7ffffeb, 27 }, /* 0xf9 */ { 0xffffffe, 28 }, /* 0xfa */ { 0x7ffffec, 27 }, /* 0xfb */ { 0x7ffffed, 27 }, /* 0xfc */ { 0x7ffffee, 27 }, /* 0xfd */ { 0x7ffffef, 27 }, /* 0xfe */ { 0x7fffff0, 27 }, /* 0xff */ { 0x3ffffee, 26 }, /* 0x100 */ { 0x3fffffff, 30 }, }; int code_bit(int idx, int bit) { if (bit < huf_literal[idx].len) return !!(huf_literal[idx].code & (1 << (huf_literal[idx].len - 1 - bit))); return -1; } #include "huftable.h" #define PARALLEL 2 struct state { int terminal; int state[PARALLEL]; int bytepos; int real_pos; }; struct state state[2000]; unsigned char terms[2000]; int next = 1; int lextable_decode(int pos, char c) { int q = pos + !!c; if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */ return lextable[q] | 0x8000; return pos + (lextable[q] << 1); } int main(void) { int n = 0; int m = 0; int prev; char c; int walk; int saw; int y; int j; int q; int pos = 0; int biggest = 0; int fails = 0; m = 0; while (m < ARRAY_SIZE(state)) { for (j = 0; j < PARALLEL; j++) { state[m].state[j] = 0xffff; state[m].terminal = 0; } m++; } while (n < ARRAY_SIZE(huf_literal)) { m = 0; walk = 0; prev = 0; while (m < huf_literal[n].len) { saw = 0; if (state[walk].state[code_bit(n, m)] != 0xffff) { /* exists -- go forward */ walk = state[walk].state[code_bit(n, m)]; goto again; } /* something we didn't see before */ state[walk].state[code_bit(n, m)] = next; walk = next++; again: m++; } state[walk].terminal = n++; state[walk].state[0] = 0; /* terminal marker */ } walk = 0; for (n = 0; n < next; n++) { state[n].bytepos = walk; walk += (2 * 2); } /* compute everyone's position first */ pos = 0; walk = 0; for (n = 0; n < next; n++) { state[n].real_pos = pos; if (state[n].state[0]) /* nonterminal */ pos += 2; walk ++; } fprintf(stdout, "static unsigned char lextable[] = {\n"); #define TERMINAL_MASK 0x8000 walk = 0; pos = 0; q = 0; for (n = 0; n < next; n++) { q = pos; for (m = 0; m < 2; m++) { saw = state[n].state[m]; if (saw == 0) { // c is a terminal then m = 2; continue; } if (!m) fprintf(stdout, "/* pos %04x: %3d */ ", state[n].real_pos, n); else fprintf(stdout, " "); if (saw == 0xffff) { fprintf(stdout, " 0xff, 0xff, /* 0 = fail */\n "); pos ++; /* fail */ fails++; continue; } if (state[saw].state[0] == 0) { /* points to terminal */ fprintf(stdout, " /* terminal %d */ 0x%02X,\n", state[saw].terminal, state[saw].terminal & 0xff); terms[(state[n].real_pos + m) >> 3] |= 1 << ((state[n].real_pos + m) & 7); pos++; walk++; continue; } j = (state[saw].real_pos - q) >> 1; if (j > biggest) biggest = j; if (j > 0xffff) { fprintf(stderr, "Jump > 64K bytes ahead (%d to %d)\n", state[n].real_pos, state[saw].real_pos); return 1; } fprintf(stdout, " /* %d */ 0x%02X " "/* (to 0x%04X state %3d) */,\n", m, j & 0xff, state[saw].real_pos, saw); pos++; walk++; } } fprintf(stdout, "/* total size %d bytes, biggest jump %d/256, fails=%d */\n};\n" "\n static unsigned char lextable_terms[] = {\n", pos, biggest, fails); for (n = 0; n < (walk + 7) / 8; n++) { if (!(n & 7)) fprintf(stdout, "\n\t"); fprintf(stdout, "0x%02x, ", terms[n]); } fprintf(stdout, "\n};\n"); /* * Try to parse every legal input string */ for (n = 0; n < ARRAY_SIZE(huf_literal); n++) { walk = 0; m = 0; y = -1; fprintf(stderr, " trying %d\n", n); while (m < huf_literal[n].len) { prev = walk; walk = lextable_decode(walk, code_bit(n, m)); if (walk == 0xffff) { fprintf(stderr, "failed\n"); return 3; } if (walk & 0x8000) { y = walk & 0x7fff; if (y == 0 && m == 29) { y |= 0x100; fprintf(stdout, "\n/* state that points to " "0x100 for disambiguation with " "0x0 */\n" "#define HUFTABLE_0x100_PREV " "%d\n", prev); } break; } m++; } if (y != n) { fprintf(stderr, "decode failed %d got %d (0x%x)\n", n, y, y); return 4; } } fprintf(stderr, "All decode OK\n"); return 0; } |
Added undroid/libwebsockets/lib/minilex.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * minilex.c * * High efficiency lexical state parser * * Copyright (C)2011-2014 Andy Green <andy@warmcat.com> * * Licensed under LGPL2 * * Usage: gcc minilex.c -o minilex && ./minilex > lextable.h * * Run it twice to test parsing on the generated table on stderr */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lextable-strings.h" /* * b7 = 0 = 1-byte seq * 0x08 = fail * 2-byte seq * 0x00 - 0x07, then terminal as given in 2nd byte 3-byte seq * no match: go fwd 3 byte, match: jump fwd by amt in +1/+2 bytes * = 1 = 1-byte seq * no match: die, match go fwd 1 byte */ unsigned char lextable[] = { #include "lextable.h" }; #define PARALLEL 30 struct state { char c[PARALLEL]; int state[PARALLEL]; int count; int bytepos; int real_pos; }; struct state state[1000]; int next = 1; #define FAIL_CHAR 0x08 int lextable_decode(int pos, char c) { while (1) { if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */ if ((lextable[pos] & 0x7f) != c) return -1; /* fall thru */ pos++; if (lextable[pos] == FAIL_CHAR) return -1; return pos; } else { /* b7 = 0, end or 3-byte */ if (lextable[pos] < FAIL_CHAR) /* terminal marker */ return pos; if (lextable[pos] == c) /* goto */ return pos + (lextable[pos + 1]) + (lextable[pos + 2] << 8); /* fall thru goto */ pos += 3; /* continue */ } } } int main(void) { int n = 0; int m = 0; int prev; char c; int walk; int saw; int y; int j; int pos = 0; while (n < sizeof(set) / sizeof(set[0])) { m = 0; walk = 0; prev = 0; if (set[n][0] == '\0') { n++; continue; } while (set[n][m]) { saw = 0; for (y = 0; y < state[walk].count; y++) if (state[walk].c[y] == set[n][m]) { /* exists -- go forward */ walk = state[walk].state[y]; saw = 1; break; } if (saw) goto again; /* something we didn't see before */ state[walk].c[state[walk].count] = set[n][m]; state[walk].state[state[walk].count] = next; state[walk].count++; walk = next++; again: m++; } state[walk].c[0] = n++; state[walk].state[0] = 0; /* terminal marker */ state[walk].count = 1; } walk = 0; for (n = 0; n < next; n++) { state[n].bytepos = walk; walk += (2 * state[n].count); } /* compute everyone's position first */ pos = 0; walk = 0; for (n = 0; n < next; n++) { state[n].real_pos = pos; for (m = 0; m < state[n].count; m++) { if (state[n].state[m] == 0) pos += 2; /* terminal marker */ else { /* c is a character */ if ((state[state[n].state[m]].bytepos - walk) == 2) pos++; else { pos += 3; if (m == state[n].count - 1) pos++; /* fail */ } } walk += 2; } } walk = 0; pos = 0; for (n = 0; n < next; n++) { for (m = 0; m < state[n].count; m++) { if (!m) fprintf(stdout, "/* pos %04x: %3d */ ", state[n].real_pos, n); else fprintf(stdout, " "); y = state[n].c[m]; saw = state[n].state[m]; if (saw == 0) { // c is a terminal then if (y > 0x7ff) { fprintf(stderr, "terminal too big\n"); return 2; } fprintf(stdout, " 0x%02X, 0x%02X " " " "/* - terminal marker %2d - */,\n", y >> 8, y & 0xff, y & 0x7f); pos += 2; walk += 2; continue; } /* c is a character */ prev = y &0x7f; if (prev < 32 || prev > 126) prev = '.'; if ((state[saw].bytepos - walk) == 2) { fprintf(stdout, " 0x%02X /* '%c' -> */,\n", y | 0x80, prev); pos++; walk += 2; continue; } j = state[saw].real_pos - pos; if (j > 0xffff) { fprintf(stderr, "Jump > 64K bytes ahead (%d to %d)\n", state[n].real_pos, state[saw].real_pos); return 1; } fprintf(stdout, " 0x%02X /* '%c' */, 0x%02X, 0x%02X " "/* (to 0x%04X state %3d) */,\n", y, prev, j & 0xff, j >> 8, state[saw].real_pos, saw); pos += 3; if (m == state[n].count - 1) { fprintf(stdout, " 0x%02X, /* fail */\n", FAIL_CHAR); pos++; /* fail */ } walk += 2; } } fprintf(stdout, "/* total size %d bytes */\n", pos); /* * Try to parse every legal input string */ for (n = 0; n < sizeof(set) / sizeof(set[0]); n++) { walk = 0; m = 0; y = -1; if (set[n][0] == '\0') continue; fprintf(stderr, " trying '%s'\n", set[n]); while (set[n][m]) { walk = lextable_decode(walk, set[n][m]); if (walk < 0) { fprintf(stderr, "failed\n"); return 3; } if (lextable[walk] < FAIL_CHAR) { y = (lextable[walk] << 8) + lextable[walk + 1]; break; } m++; } if (y != n) { fprintf(stderr, "decode failed %d\n", y); return 4; } } fprintf(stderr, "All decode OK\n"); return 0; } |
Added undroid/libwebsockets/lib/output.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" static int lws_0405_frame_mask_generate(struct lws *wsi) { #if 0 wsi->u.ws.mask[0] = 0; wsi->u.ws.mask[1] = 0; wsi->u.ws.mask[2] = 0; wsi->u.ws.mask[3] = 0; #else int n; /* fetch the per-frame nonce */ n = lws_get_random(lws_get_context(wsi), wsi->u.ws.mask, 4); if (n != 4) { lwsl_parser("Unable to read from random device %s %d\n", SYSTEM_RANDOM_FILEPATH, n); return 1; } #endif /* start masking from first byte of masking key buffer */ wsi->u.ws.mask_idx = 0; return 0; } #ifdef _DEBUG LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len) { unsigned char *buf = (unsigned char *)vbuf; unsigned int n, m, start; char line[80]; char *p; lwsl_parser("\n"); for (n = 0; n < len;) { start = n; p = line; p += sprintf(p, "%04X: ", start); for (m = 0; m < 16 && n < len; m++) p += sprintf(p, "%02X ", buf[n++]); while (m++ < 16) p += sprintf(p, " "); p += sprintf(p, " "); for (m = 0; m < 16 && (start + m) < len; m++) { if (buf[start + m] >= ' ' && buf[start + m] < 127) *p++ = buf[start + m]; else *p++ = '.'; } while (m++ < 16) *p++ = ' '; *p++ = '\n'; *p = '\0'; lwsl_debug("%s", line); } lwsl_debug("\n"); } #endif /* * notice this returns number of bytes consumed, or -1 */ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len) { struct lws_context *context = lws_get_context(wsi); size_t real_len = len; unsigned int n; int m; if (!len) return 0; /* just ignore sends after we cleared the truncation buffer */ if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE && !wsi->trunc_len) return len; if (wsi->trunc_len && (buf < wsi->trunc_alloc || buf > (wsi->trunc_alloc + wsi->trunc_len + wsi->trunc_offset))) { lwsl_err("****** %x Sending new, pending truncated ...\n", wsi); assert(0); return -1; } m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_DO_SEND, &buf, len); if (m < 0) return -1; if (m) /* handled */ { n = m; goto handle_truncated_send; } if (!lws_socket_is_valid(wsi->sock)) lwsl_warn("** error invalid sock but expected to send\n"); /* limit sending */ n = wsi->protocol->rx_buffer_size; if (!n) n = LWS_MAX_SOCKET_IO_BUF; n += LWS_PRE + 4; if (n > len) n = len; /* nope, send it on the socket directly */ lws_latency_pre(context, wsi); n = lws_ssl_capable_write(wsi, buf, n); lws_latency(context, wsi, "send lws_issue_raw", n, n == len); switch (n) { case LWS_SSL_CAPABLE_ERROR: /* we're going to close, let close know sends aren't possible */ wsi->socket_is_permanently_unusable = 1; return -1; case LWS_SSL_CAPABLE_MORE_SERVICE: /* nothing got sent, not fatal, retry the whole thing later */ n = 0; break; } handle_truncated_send: /* * we were already handling a truncated send? */ if (wsi->trunc_len) { lwsl_info("%p partial adv %d (vs %d)\n", wsi, n, real_len); wsi->trunc_offset += n; wsi->trunc_len -= n; if (!wsi->trunc_len) { lwsl_info("***** %x partial send completed\n", wsi); /* done with it, but don't free it */ n = real_len; if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) { lwsl_info("***** %x signalling to close now\n", wsi); return -1; /* retry closing now */ } } /* always callback on writeable */ lws_callback_on_writable(wsi); return n; } if ((unsigned int)n == real_len) /* what we just sent went out cleanly */ return n; /* * Newly truncated send. Buffer the remainder (it will get * first priority next time the socket is writable) */ lwsl_info("%p new partial sent %d from %d total\n", wsi, n, real_len); /* * - if we still have a suitable malloc lying around, use it * - or, if too small, reallocate it * - or, if no buffer, create it */ if (!wsi->trunc_alloc || real_len - n > wsi->trunc_alloc_len) { lws_free(wsi->trunc_alloc); wsi->trunc_alloc_len = real_len - n; wsi->trunc_alloc = lws_malloc(real_len - n); if (!wsi->trunc_alloc) { lwsl_err("truncated send: unable to malloc %d\n", real_len - n); return -1; } } wsi->trunc_offset = 0; wsi->trunc_len = real_len - n; memcpy(wsi->trunc_alloc, buf + n, real_len - n); /* since something buffered, force it to get another chance to send */ lws_callback_on_writable(wsi); return real_len; } /** * lws_write() - Apply protocol then write data to client * @wsi: Websocket instance (available from user callback) * @buf: The data to send. For data being sent on a websocket * connection (ie, not default http), this buffer MUST have * LWS_PRE bytes valid BEFORE the pointer. * This is so the protocol header data can be added in-situ. * @len: Count of the data bytes in the payload starting from buf * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate * data on a websockets connection. Remember to allow the extra * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT * are used. * * This function provides the way to issue data back to the client * for both http and websocket protocols. * * In the case of sending using websocket protocol, be sure to allocate * valid storage before and after buf as explained above. This scheme * allows maximum efficiency of sending data and protocol in a single * packet while not burdening the user code with any protocol knowledge. * * Return may be -1 for a fatal error needing connection close, or a * positive number reflecting the amount of bytes actually sent. This * can be less than the requested number of bytes due to OS memory * pressure at any given time. */ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len, enum lws_write_protocol wp) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; int masked7 = (wsi->mode == LWSCM_WS_CLIENT); unsigned char is_masked_bit = 0; unsigned char *dropmask = NULL; struct lws_tokens eff_buf; int pre = 0, n; size_t orig_len = len; #ifdef LWS_WITH_ACCESS_LOG wsi->access_log.sent += len; #endif if (wsi->vhost) wsi->vhost->tx += len; if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) { /* remove us from the list */ struct lws **w = &pt->tx_draining_ext_list; lwsl_debug("%s: TX EXT DRAINING: Remove from list\n", __func__); wsi->u.ws.tx_draining_ext = 0; /* remove us from context draining ext list */ while (*w) { if (*w == wsi) { *w = wsi->u.ws.tx_draining_ext_list; break; } w = &((*w)->u.ws.tx_draining_ext_list); } wsi->u.ws.tx_draining_ext_list = NULL; wp = (wsi->u.ws.tx_draining_stashed_wp & 0xc0) | LWS_WRITE_CONTINUATION; lwsl_ext("FORCED draining wp to 0x%02X\n", wp); } if (wp == LWS_WRITE_HTTP || wp == LWS_WRITE_HTTP_FINAL || wp == LWS_WRITE_HTTP_HEADERS) goto send_raw; /* if not in a state to send stuff, then just send nothing */ if (wsi->state != LWSS_ESTABLISHED && ((wsi->state != LWSS_RETURNED_CLOSE_ALREADY && wsi->state != LWSS_AWAITING_CLOSE_ACK) || wp != LWS_WRITE_CLOSE)) return 0; /* if we are continuing a frame that already had its header done */ if (wsi->u.ws.inside_frame) { lwsl_debug("INSIDE FRAME\n"); goto do_more_inside_frame; } wsi->u.ws.clean_buffer = 1; /* * give a chance to the extensions to modify payload * the extension may decide to produce unlimited payload erratically * (eg, compression extension), so we require only that if he produces * something, it will be a complete fragment of the length known at * the time (just the fragment length known), and if he has * more we will come back next time he is writeable and allow him to * produce more fragments until he's drained. * * This allows what is sent each time it is writeable to be limited to * a size that can be sent without partial sends or blocking, allows * interleaving of control frames and other connection service. */ eff_buf.token = (char *)buf; eff_buf.token_len = len; switch ((int)wp) { case LWS_WRITE_PING: case LWS_WRITE_PONG: case LWS_WRITE_CLOSE: break; default: n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_TX, &eff_buf, wp); if (n < 0) return -1; if (n && eff_buf.token_len) { /* extension requires further draining */ wsi->u.ws.tx_draining_ext = 1; wsi->u.ws.tx_draining_ext_list = pt->tx_draining_ext_list; pt->tx_draining_ext_list = wsi; /* we must come back to do more */ lws_callback_on_writable(wsi); /* * keep a copy of the write type for the overall * action that has provoked generation of these * fragments, so the last guy can use its FIN state. */ wsi->u.ws.tx_draining_stashed_wp = wp; /* this is definitely not actually the last fragment * because the extension asserted he has more coming * So make sure this intermediate one doesn't go out * with a FIN. */ wp |= LWS_WRITE_NO_FIN; } if (eff_buf.token_len && wsi->u.ws.stashed_write_pending) { wsi->u.ws.stashed_write_pending = 0; wp = (wp &0xc0) | (int)wsi->u.ws.stashed_write_type; } } /* * an extension did something we need to keep... for example, if * compression extension, it has already updated its state according * to this being issued */ if ((char *)buf != eff_buf.token) { /* * ext might eat it, but no have anything to issue yet * in that case we have to follow his lead, but stash and * replace the write type that was lost here the first time. */ if (len && !eff_buf.token_len) { if (!wsi->u.ws.stashed_write_pending) wsi->u.ws.stashed_write_type = (char)wp & 0x3f; wsi->u.ws.stashed_write_pending = 1; return len; } /* * extension recreated it: * need to buffer this if not all sent */ wsi->u.ws.clean_buffer = 0; } buf = (unsigned char *)eff_buf.token; len = eff_buf.token_len; switch (wsi->ietf_spec_revision) { case 13: if (masked7) { pre += 4; dropmask = &buf[0 - pre]; is_masked_bit = 0x80; } switch (wp & 0xf) { case LWS_WRITE_TEXT: n = LWSWSOPC_TEXT_FRAME; break; case LWS_WRITE_BINARY: n = LWSWSOPC_BINARY_FRAME; break; case LWS_WRITE_CONTINUATION: n = LWSWSOPC_CONTINUATION; break; case LWS_WRITE_CLOSE: n = LWSWSOPC_CLOSE; break; case LWS_WRITE_PING: n = LWSWSOPC_PING; break; case LWS_WRITE_PONG: n = LWSWSOPC_PONG; break; default: lwsl_warn("lws_write: unknown write opc / wp\n"); return -1; } if (!(wp & LWS_WRITE_NO_FIN)) n |= 1 << 7; if (len < 126) { pre += 2; buf[-pre] = n; buf[-pre + 1] = (unsigned char)(len | is_masked_bit); } else { if (len < 65536) { pre += 4; buf[-pre] = n; buf[-pre + 1] = 126 | is_masked_bit; buf[-pre + 2] = (unsigned char)(len >> 8); buf[-pre + 3] = (unsigned char)len; } else { pre += 10; buf[-pre] = n; buf[-pre + 1] = 127 | is_masked_bit; #if defined __LP64__ buf[-pre + 2] = (len >> 56) & 0x7f; buf[-pre + 3] = len >> 48; buf[-pre + 4] = len >> 40; buf[-pre + 5] = len >> 32; #else buf[-pre + 2] = 0; buf[-pre + 3] = 0; buf[-pre + 4] = 0; buf[-pre + 5] = 0; #endif buf[-pre + 6] = (unsigned char)(len >> 24); buf[-pre + 7] = (unsigned char)(len >> 16); buf[-pre + 8] = (unsigned char)(len >> 8); buf[-pre + 9] = (unsigned char)len; } } break; } do_more_inside_frame: /* * Deal with masking if we are in client -> server direction and * the wp demands it */ if (masked7) { if (!wsi->u.ws.inside_frame) if (lws_0405_frame_mask_generate(wsi)) { lwsl_err("frame mask generation failed\n"); return -1; } /* * in v7, just mask the payload */ if (dropmask) { /* never set if already inside frame */ for (n = 4; n < (int)len + 4; n++) dropmask[n] = dropmask[n] ^ wsi->u.ws.mask[ (wsi->u.ws.mask_idx++) & 3]; /* copy the frame nonce into place */ memcpy(dropmask, wsi->u.ws.mask, 4); } } send_raw: switch ((int)wp) { case LWS_WRITE_CLOSE: /* lwsl_hexdump(&buf[-pre], len); */ case LWS_WRITE_HTTP: case LWS_WRITE_HTTP_FINAL: case LWS_WRITE_HTTP_HEADERS: case LWS_WRITE_PONG: case LWS_WRITE_PING: #ifdef LWS_USE_HTTP2 if (wsi->mode == LWSCM_HTTP2_SERVING) { unsigned char flags = 0; n = LWS_HTTP2_FRAME_TYPE_DATA; if (wp == LWS_WRITE_HTTP_HEADERS) { n = LWS_HTTP2_FRAME_TYPE_HEADERS; flags = LWS_HTTP2_FLAG_END_HEADERS; if (wsi->u.http2.send_END_STREAM) flags |= LWS_HTTP2_FLAG_END_STREAM; } if ((wp == LWS_WRITE_HTTP || wp == LWS_WRITE_HTTP_FINAL) && wsi->u.http.content_length) { wsi->u.http.content_remain -= len; lwsl_info("%s: content_remain = %lu\n", __func__, wsi->u.http.content_remain); if (!wsi->u.http.content_remain) { lwsl_info("%s: selecting final write mode\n", __func__); wp = LWS_WRITE_HTTP_FINAL; } } if (wp == LWS_WRITE_HTTP_FINAL && wsi->u.http2.END_STREAM) { lwsl_info("%s: setting END_STREAM\n", __func__); flags |= LWS_HTTP2_FLAG_END_STREAM; } return lws_http2_frame_write(wsi, n, flags, wsi->u.http2.my_stream_id, len, buf); } #endif return lws_issue_raw(wsi, (unsigned char *)buf - pre, len + pre); default: break; } /* * give any active extensions a chance to munge the buffer * before send. We pass in a pointer to an lws_tokens struct * prepared with the default buffer and content length that's in * there. Rather than rewrite the default buffer, extensions * that expect to grow the buffer can adapt .token to * point to their own per-connection buffer in the extension * user allocation. By default with no extensions or no * extension callback handling, just the normal input buffer is * used then so it is efficient. * * callback returns 1 in case it wants to spill more buffers * * This takes care of holding the buffer if send is incomplete, ie, * if wsi->u.ws.clean_buffer is 0 (meaning an extension meddled with * the buffer). If wsi->u.ws.clean_buffer is 1, it will instead * return to the user code how much OF THE USER BUFFER was consumed. */ n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre); wsi->u.ws.inside_frame = 1; if (n <= 0) return n; if (n == (int)len + pre) { /* everything in the buffer was handled (or rebuffered...) */ wsi->u.ws.inside_frame = 0; return orig_len; } /* * it is how many bytes of user buffer got sent... may be < orig_len * in which case callback when writable has already been arranged * and user code can call lws_write() again with the rest * later. */ return n - pre; } LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; unsigned long amount; int n, m; while (wsi->http2_substream || !lws_send_pipe_choked(wsi)) { if (wsi->trunc_len) { if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset, wsi->trunc_len) < 0) { lwsl_info("%s: closing\n", __func__); return -1; } continue; } if (wsi->u.http.filepos == wsi->u.http.filelen) goto all_sent; if (lws_plat_file_read(wsi, wsi->u.http.fd, &amount, pt->serv_buf, LWS_MAX_SOCKET_IO_BUF) < 0) return -1; /* caller will close */ n = (int)amount; if (n) { lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, context->timeout_secs); wsi->u.http.filepos += n; m = lws_write(wsi, pt->serv_buf, n, wsi->u.http.filepos == wsi->u.http.filelen ? LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP); if (m < 0) return -1; if (m != n) /* adjust for what was not sent */ if (lws_plat_file_seek_cur(wsi, wsi->u.http.fd, m - n) == (unsigned long)-1) return -1; } all_sent: if (!wsi->trunc_len && wsi->u.http.filepos == wsi->u.http.filelen) { wsi->state = LWSS_HTTP; /* we might be in keepalive, so close it off here */ lws_plat_file_close(wsi, wsi->u.http.fd); wsi->u.http.fd = LWS_INVALID_FILE; if (wsi->protocol->callback) /* ignore callback returned value */ if (user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_HTTP_FILE_COMPLETION, wsi->user_space, NULL, 0) < 0) return -1; return 1; /* >0 indicates completed */ } } lwsl_info("choked before able to send whole file (post)\n"); lws_callback_on_writable(wsi); return 0; /* indicates further processing must be done */ } #if LWS_POSIX LWS_VISIBLE int lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len) { int n; n = recv(wsi->sock, (char *)buf, len, 0); if (n >= 0) { if (wsi->vhost) wsi->vhost->rx += n; return n; } #if LWS_POSIX if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK || LWS_ERRNO == LWS_EINTR) return LWS_SSL_CAPABLE_MORE_SERVICE; #endif lwsl_notice("error on reading from skt : %d\n", LWS_ERRNO); return LWS_SSL_CAPABLE_ERROR; } LWS_VISIBLE int lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len) { int n = 0; #if LWS_POSIX n = send(wsi->sock, (char *)buf, len, MSG_NOSIGNAL); // lwsl_info("%s: sent len %d result %d", __func__, len, n); if (n >= 0) return n; if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK || LWS_ERRNO == LWS_EINTR) { if (LWS_ERRNO == LWS_EWOULDBLOCK) lws_set_blocking_send(wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } #else (void)n; (void)wsi; (void)buf; (void)len; // !!! #endif lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n", len, wsi->sock, n, LWS_ERRNO); return LWS_SSL_CAPABLE_ERROR; } #endif LWS_VISIBLE int lws_ssl_pending_no_ssl(struct lws *wsi) { (void)wsi; return 0; } |
Added undroid/libwebsockets/lib/parsers.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" unsigned char lextable[] = { #include "lextable.h" }; #define FAIL_CHAR 0x08 int LWS_WARN_UNUSED_RESULT lextable_decode(int pos, char c) { if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; while (1) { if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */ if ((lextable[pos] & 0x7f) != c) return -1; /* fall thru */ pos++; if (lextable[pos] == FAIL_CHAR) return -1; return pos; } if (lextable[pos] == FAIL_CHAR) return -1; /* b7 = 0, end or 3-byte */ if (lextable[pos] < FAIL_CHAR) /* terminal marker */ return pos; if (lextable[pos] == c) /* goto */ return pos + (lextable[pos + 1]) + (lextable[pos + 2] << 8); /* fall thru goto */ pos += 3; /* continue */ } } void lws_header_table_reset(struct lws *wsi, int autoservice) { struct allocated_headers *ah = wsi->u.hdr.ah; struct lws_context_per_thread *pt; struct lws_pollfd *pfd; /* if we have the idea we're resetting 'our' ah, must be bound to one */ assert(ah); /* ah also concurs with ownership */ assert(ah->wsi == wsi); /* init the ah to reflect no headers or data have appeared yet */ memset(ah->frag_index, 0, sizeof(ah->frag_index)); ah->nfrag = 0; ah->pos = 0; /* and reset the rx state */ ah->rxpos = 0; ah->rxlen = 0; /* since we will restart the ah, our new headers are not completed */ wsi->hdr_parsing_completed = 0; /* * if we inherited pending rx (from socket adoption deferred * processing), apply and free it. */ if (wsi->u.hdr.preamble_rx) { memcpy(ah->rx, wsi->u.hdr.preamble_rx, wsi->u.hdr.preamble_rx_len); ah->rxlen = wsi->u.hdr.preamble_rx_len; lws_free_set_NULL(wsi->u.hdr.preamble_rx); if (autoservice) { lwsl_notice("%s: calling service on readbuf ah\n", __func__); pt = &wsi->context->pt[(int)wsi->tsi]; /* unlike a normal connect, we have the headers already * (or the first part of them anyway) */ pfd = &pt->fds[wsi->position_in_fds_table]; pfd->revents |= LWS_POLLIN; lwsl_err("%s: calling service\n", __func__); lws_service_fd_tsi(wsi->context, pfd, wsi->tsi); } } } int LWS_WARN_UNUSED_RESULT lws_header_table_attach(struct lws *wsi, int autoservice) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; struct lws_pollargs pa; struct lws **pwsi; int n; lwsl_info("%s: wsi %p: ah %p (tsi %d)\n", __func__, (void *)wsi, (void *)wsi->u.hdr.ah, wsi->tsi); /* if we are already bound to one, just clear it down */ if (wsi->u.hdr.ah) { lwsl_info("cleardown\n"); goto reset; } lws_pt_lock(pt); pwsi = &pt->ah_wait_list; while (*pwsi) { if (*pwsi == wsi) { /* if already waiting on list, if no new ah just ret */ if (pt->ah_count_in_use == context->max_http_header_pool) { lwsl_err("ah wl denied\n"); goto bail; } /* new ah.... remove ourselves from waiting list */ *pwsi = wsi->u.hdr.ah_wait_list; /* set our prev to our next */ wsi->u.hdr.ah_wait_list = NULL; /* no next any more */ pt->ah_wait_list_length--; break; } pwsi = &(*pwsi)->u.hdr.ah_wait_list; } /* * pool is all busy... add us to waiting list and return that we * weren't able to deliver it right now */ if (pt->ah_count_in_use == context->max_http_header_pool) { lwsl_info("%s: adding %p to ah waiting list\n", __func__, wsi); wsi->u.hdr.ah_wait_list = pt->ah_wait_list; pt->ah_wait_list = wsi; pt->ah_wait_list_length++; /* we cannot accept input then */ _lws_change_pollfd(wsi, LWS_POLLIN, 0, &pa); goto bail; } for (n = 0; n < context->max_http_header_pool; n++) if (!pt->ah_pool[n].in_use) break; /* if the count of in use said something free... */ assert(n != context->max_http_header_pool); wsi->u.hdr.ah = &pt->ah_pool[n]; wsi->u.hdr.ah->in_use = 1; pt->ah_pool[n].wsi = wsi; /* mark our owner */ pt->ah_count_in_use++; _lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa); lwsl_info("%s: wsi %p: ah %p: count %d (on exit)\n", __func__, (void *)wsi, (void *)wsi->u.hdr.ah, pt->ah_count_in_use); lws_pt_unlock(pt); reset: lws_header_table_reset(wsi, autoservice); time(&wsi->u.hdr.ah->assigned); #ifndef LWS_NO_CLIENT if (wsi->state == LWSS_CLIENT_UNCONNECTED) if (!lws_client_connect_via_info2(wsi)) /* our client connect has failed, the wsi * has been closed */ return -1; #endif return 0; bail: lws_pt_unlock(pt); return 1; } int lws_header_table_detach(struct lws *wsi, int autoservice) { struct lws_context *context = wsi->context; struct allocated_headers *ah = wsi->u.hdr.ah; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; struct lws_pollargs pa; struct lws **pwsi; time_t now; lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__, (void *)wsi, (void *)wsi->u.hdr.ah, wsi->tsi, pt->ah_count_in_use); if (wsi->u.hdr.preamble_rx) lws_free_set_NULL(wsi->u.hdr.preamble_rx); /* may not be detached while he still has unprocessed rx */ if (ah && ah->rxpos != ah->rxlen) { lwsl_err("%s: %p: rxpos:%d, rxlen:%d\n", __func__, wsi, ah->rxpos, ah->rxlen); assert(ah->rxpos == ah->rxlen); } lws_pt_lock(pt); pwsi = &pt->ah_wait_list; if (!ah) { /* remove from wait list if none attached */ while (*pwsi) { if (*pwsi == wsi) { lwsl_info("%s: wsi %p, remv wait\n", __func__, wsi); *pwsi = wsi->u.hdr.ah_wait_list; wsi->u.hdr.ah_wait_list = NULL; pt->ah_wait_list_length--; goto bail; } pwsi = &(*pwsi)->u.hdr.ah_wait_list; } /* no ah, not on list... no more business here */ goto bail; } /* we did have an ah attached */ time(&now); if (now - wsi->u.hdr.ah->assigned > 3) { /* * we're detaching the ah, but it was held an * unreasonably long time */ lwsl_notice("%s: wsi %p: ah held %ds, " "ah.rxpos %d, ah.rxlen %d, mode/state %d %d," "wsi->more_rx_waiting %d\n", __func__, wsi, (int)(now - wsi->u.hdr.ah->assigned), ah->rxpos, ah->rxlen, wsi->mode, wsi->state, wsi->more_rx_waiting); } /* if we think we're detaching one, there should be one in use */ assert(pt->ah_count_in_use > 0); /* and this specific one should have been in use */ assert(wsi->u.hdr.ah->in_use); wsi->u.hdr.ah = NULL; ah->wsi = NULL; /* no owner */ /* oh there is nobody on the waiting list... leave it at that then */ if (!*pwsi) { ah->in_use = 0; pt->ah_count_in_use--; goto bail; } /* somebody else on same tsi is waiting, give it to oldest guy */ lwsl_info("pt wait list %p\n", *pwsi); while ((*pwsi)->u.hdr.ah_wait_list) pwsi = &(*pwsi)->u.hdr.ah_wait_list; wsi = *pwsi; lwsl_info("last wsi in wait list %p\n", wsi); wsi->u.hdr.ah = ah; ah->wsi = wsi; /* new owner */ lws_header_table_reset(wsi, autoservice); time(&wsi->u.hdr.ah->assigned); assert(wsi->position_in_fds_table != -1); lwsl_info("%s: Enabling %p POLLIN\n", __func__, wsi); /* he has been stuck waiting for an ah, but now his wait is over, * let him progress */ _lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa); /* point prev guy to next guy in list instead */ *pwsi = wsi->u.hdr.ah_wait_list; /* the guy who got one is out of the list */ wsi->u.hdr.ah_wait_list = NULL; pt->ah_wait_list_length--; #ifndef LWS_NO_CLIENT if (wsi->state == LWSS_CLIENT_UNCONNECTED) if (!lws_client_connect_via_info2(wsi)) { /* our client connect has failed, the wsi * has been closed */ lws_pt_unlock(pt); return -1; } #endif assert(!!pt->ah_wait_list_length == !!(int)(long)pt->ah_wait_list); bail: lws_pt_unlock(pt); return 0; } /** * lws_hdr_fragment_length: report length of a single fragment of a header * The returned length does not include the space for a * terminating '\0' * * @wsi: websocket connection * @h: which header index we are interested in * @frag_idx: which fragment of @h we want to get the length of */ LWS_VISIBLE int lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx) { int n; n = wsi->u.hdr.ah->frag_index[h]; if (!n) return 0; do { if (!frag_idx) return wsi->u.hdr.ah->frags[n].len; n = wsi->u.hdr.ah->frags[n].nfrag; } while (frag_idx-- && n); return 0; } /** * lws_hdr_total_length: report length of all fragments of a header totalled up * The returned length does not include the space for a * terminating '\0' * * @wsi: websocket connection * @h: which header index we are interested in */ LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h) { int n; int len = 0; n = wsi->u.hdr.ah->frag_index[h]; if (!n) return 0; do { len += wsi->u.hdr.ah->frags[n].len; n = wsi->u.hdr.ah->frags[n].nfrag; } while (n); return len; } /** * lws_hdr_copy_fragment: copy a single fragment of the given header to a buffer * The buffer length @len must include space for an additional * terminating '\0', or it will fail returning -1. * If the requested fragment index is not present, it fails * returning -1. * * @wsi: websocket connection * @dst: destination buffer * @len: length of destination buffer * @h: which header index we are interested in * @frag_index: which fragment of @h we want to copy */ LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len, enum lws_token_indexes h, int frag_idx) { int n = 0; int f = wsi->u.hdr.ah->frag_index[h]; if (!f) return -1; while (n < frag_idx) { f = wsi->u.hdr.ah->frags[f].nfrag; if (!f) return -1; n++; } if (wsi->u.hdr.ah->frags[f].len >= len) return -1; memcpy(dst, wsi->u.hdr.ah->data + wsi->u.hdr.ah->frags[f].offset, wsi->u.hdr.ah->frags[f].len); dst[wsi->u.hdr.ah->frags[f].len] = '\0'; return wsi->u.hdr.ah->frags[f].len; } /** * lws_hdr_copy: copy a single fragment of the given header to a buffer * The buffer length @len must include space for an additional * terminating '\0', or it will fail returning -1. * * @wsi: websocket connection * @dst: destination buffer * @len: length of destination buffer * @h: which header index we are interested in */ LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len, enum lws_token_indexes h) { int toklen = lws_hdr_total_length(wsi, h); int n; if (toklen >= len) return -1; n = wsi->u.hdr.ah->frag_index[h]; if (!n) return 0; do { strcpy(dst, &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]); dst += wsi->u.hdr.ah->frags[n].len; n = wsi->u.hdr.ah->frags[n].nfrag; } while (n); return toklen; } char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h) { int n; n = wsi->u.hdr.ah->frag_index[h]; if (!n) return NULL; return wsi->u.hdr.ah->data + wsi->u.hdr.ah->frags[n].offset; } int LWS_WARN_UNUSED_RESULT lws_pos_in_bounds(struct lws *wsi) { if (wsi->u.hdr.ah->pos < wsi->context->max_http_header_data) return 0; if (wsi->u.hdr.ah->pos == wsi->context->max_http_header_data) { lwsl_err("Ran out of header data space\n"); return 1; } /* * with these tests everywhere, it should never be able to exceed * the limit, only meet the limit */ lwsl_err("%s: pos %d, limit %d\n", __func__, wsi->u.hdr.ah->pos, wsi->context->max_http_header_data); assert(0); return 1; } int LWS_WARN_UNUSED_RESULT lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s) { wsi->u.hdr.ah->nfrag++; if (wsi->u.hdr.ah->nfrag == ARRAY_SIZE(wsi->u.hdr.ah->frags)) { lwsl_warn("More hdr frags than we can deal with, dropping\n"); return -1; } wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->nfrag; wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].offset = wsi->u.hdr.ah->pos; wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len = 0; wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].nfrag = 0; do { if (lws_pos_in_bounds(wsi)) return -1; wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s; if (*s) wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len++; } while (*s++); return 0; } signed char char_to_hex(const char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int LWS_WARN_UNUSED_RESULT issue_char(struct lws *wsi, unsigned char c) { unsigned short frag_len; if (lws_pos_in_bounds(wsi)) return -1; frag_len = wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len; /* * If we haven't hit the token limit, just copy the character into * the header */ if (frag_len < wsi->u.hdr.current_token_limit) { wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c; if (c) wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len++; return 0; } /* Insert a null character when we *hit* the limit: */ if (frag_len == wsi->u.hdr.current_token_limit) { if (lws_pos_in_bounds(wsi)) return -1; wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0'; lwsl_warn("header %i exceeds limit %d\n", wsi->u.hdr.parser_state, wsi->u.hdr.current_token_limit); } return 1; } int LWS_WARN_UNUSED_RESULT lws_parse(struct lws *wsi, unsigned char c) { static const unsigned char methods[] = { WSI_TOKEN_GET_URI, WSI_TOKEN_POST_URI, WSI_TOKEN_OPTIONS_URI, WSI_TOKEN_PUT_URI, WSI_TOKEN_PATCH_URI, WSI_TOKEN_DELETE_URI, }; struct allocated_headers *ah = wsi->u.hdr.ah; struct lws_context *context = wsi->context; unsigned int n, m, enc = 0; assert(wsi->u.hdr.ah); switch (wsi->u.hdr.parser_state) { default: lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c); /* collect into malloc'd buffers */ /* optional initial space swallow */ if (!ah->frags[ah->frag_index[wsi->u.hdr.parser_state]].len && c == ' ') break; for (m = 0; m < ARRAY_SIZE(methods); m++) if (wsi->u.hdr.parser_state == methods[m]) break; if (m == ARRAY_SIZE(methods)) /* it was not any of the methods */ goto check_eol; /* special URI processing... end at space */ if (c == ' ') { /* enforce starting with / */ if (!ah->frags[ah->nfrag].len) if (issue_char(wsi, '/') < 0) return -1; if (wsi->u.hdr.ups == URIPS_SEEN_SLASH_DOT_DOT) { /* * back up one dir level if possible * safe against header fragmentation because * the method URI can only be in 1 fragment */ if (ah->frags[ah->nfrag].len > 2) { ah->pos--; ah->frags[ah->nfrag].len--; do { ah->pos--; ah->frags[ah->nfrag].len--; } while (ah->frags[ah->nfrag].len > 1 && ah->data[ah->pos] != '/'); } } /* begin parsing HTTP version: */ if (issue_char(wsi, '\0') < 0) return -1; wsi->u.hdr.parser_state = WSI_TOKEN_HTTP; goto start_fragment; } /* * PRIORITY 1 * special URI processing... convert %xx */ switch (wsi->u.hdr.ues) { case URIES_IDLE: if (c == '%') { wsi->u.hdr.ues = URIES_SEEN_PERCENT; goto swallow; } break; case URIES_SEEN_PERCENT: if (char_to_hex(c) < 0) /* illegal post-% char */ goto forbid; wsi->u.hdr.esc_stash = c; wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1; goto swallow; case URIES_SEEN_PERCENT_H1: if (char_to_hex(c) < 0) /* illegal post-% char */ goto forbid; c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) | char_to_hex(c); enc = 1; wsi->u.hdr.ues = URIES_IDLE; break; } /* * PRIORITY 2 * special URI processing... * convert /.. or /... or /../ etc to / * convert /./ to / * convert // or /// etc to / * leave /.dir or whatever alone */ switch (wsi->u.hdr.ups) { case URIPS_IDLE: if (!c) return -1; /* genuine delimiter */ if ((c == '&' || c == ';') && !enc) { if (issue_char(wsi, c) < 0) return -1; /* swallow the terminator */ ah->frags[ah->nfrag].len--; /* link to next fragment */ ah->frags[ah->nfrag].nfrag = ah->nfrag + 1; ah->nfrag++; if (ah->nfrag >= ARRAY_SIZE(ah->frags)) goto excessive; /* start next fragment after the & */ wsi->u.hdr.post_literal_equal = 0; ah->frags[ah->nfrag].offset = ah->pos; ah->frags[ah->nfrag].len = 0; ah->frags[ah->nfrag].nfrag = 0; goto swallow; } /* uriencoded = in the name part, disallow */ if (c == '=' && enc && ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] && !wsi->u.hdr.post_literal_equal) c = '_'; /* after the real =, we don't care how many = */ if (c == '=' && !enc) wsi->u.hdr.post_literal_equal = 1; /* + to space */ if (c == '+' && !enc) c = ' '; /* issue the first / always */ if (c == '/' && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) wsi->u.hdr.ups = URIPS_SEEN_SLASH; break; case URIPS_SEEN_SLASH: /* swallow subsequent slashes */ if (c == '/') goto swallow; /* track and swallow the first . after / */ if (c == '.') { wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT; goto swallow; } wsi->u.hdr.ups = URIPS_IDLE; break; case URIPS_SEEN_SLASH_DOT: /* swallow second . */ if (c == '.') { wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT; goto swallow; } /* change /./ to / */ if (c == '/') { wsi->u.hdr.ups = URIPS_SEEN_SLASH; goto swallow; } /* it was like /.dir ... regurgitate the . */ wsi->u.hdr.ups = URIPS_IDLE; if (issue_char(wsi, '.') < 0) return -1; break; case URIPS_SEEN_SLASH_DOT_DOT: /* /../ or /..[End of URI] --> backup to last / */ if (c == '/' || c == '?') { /* * back up one dir level if possible * safe against header fragmentation because * the method URI can only be in 1 fragment */ if (ah->frags[ah->nfrag].len > 2) { ah->pos--; ah->frags[ah->nfrag].len--; do { ah->pos--; ah->frags[ah->nfrag].len--; } while (ah->frags[ah->nfrag].len > 1 && ah->data[ah->pos] != '/'); } wsi->u.hdr.ups = URIPS_SEEN_SLASH; if (ah->frags[ah->nfrag].len > 1) break; goto swallow; } /* /..[^/] ... regurgitate and allow */ if (issue_char(wsi, '.') < 0) return -1; if (issue_char(wsi, '.') < 0) return -1; wsi->u.hdr.ups = URIPS_IDLE; break; } if (c == '?' && !enc && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */ if (wsi->u.hdr.ues != URIES_IDLE) goto forbid; /* seal off uri header */ if (issue_char(wsi, '\0') < 0) return -1; /* move to using WSI_TOKEN_HTTP_URI_ARGS */ ah->nfrag++; if (ah->nfrag >= ARRAY_SIZE(ah->frags)) goto excessive; ah->frags[ah->nfrag].offset = ah->pos; ah->frags[ah->nfrag].len = 0; ah->frags[ah->nfrag].nfrag = 0; wsi->u.hdr.post_literal_equal = 0; ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag; wsi->u.hdr.ups = URIPS_IDLE; goto swallow; } check_eol: /* bail at EOL */ if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') { if (wsi->u.hdr.ues != URIES_IDLE) goto forbid; c = '\0'; wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR; lwsl_parser("*\n"); } n = issue_char(wsi, c); if ((int)n < 0) return -1; if (n > 0) wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; swallow: /* per-protocol end of headers management */ if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE) goto set_parsing_complete; break; /* collecting and checking a name part */ case WSI_TOKEN_NAME_PART: lwsl_parser("WSI_TOKEN_NAME_PART '%c' (mode=%d)\n", c, wsi->mode); wsi->u.hdr.lextable_pos = lextable_decode(wsi->u.hdr.lextable_pos, c); /* * Server needs to look out for unknown methods... */ if (wsi->u.hdr.lextable_pos < 0 && wsi->mode == LWSCM_HTTP_SERVING) { /* this is not a header we know about */ for (m = 0; m < ARRAY_SIZE(methods); m++) if (ah->frag_index[methods[m]]) { /* * already had the method, no idea what * this crap from the client is, ignore */ wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; break; } /* * hm it's an unknown http method from a client in fact, * treat as dangerous */ if (m == ARRAY_SIZE(methods)) { lwsl_info("Unknown method - dropping\n"); goto forbid; } break; } /* * ...otherwise for a client, let him ignore unknown headers * coming from the server */ if (wsi->u.hdr.lextable_pos < 0) { wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; break; } if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) { /* terminal state */ n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) | lextable[wsi->u.hdr.lextable_pos + 1]; lwsl_parser("known hdr %d\n", n); for (m = 0; m < ARRAY_SIZE(methods); m++) if (n == methods[m] && ah->frag_index[methods[m]]) { lwsl_warn("Duplicated method\n"); return -1; } /* * WSORIGIN is protocol equiv to ORIGIN, * JWebSocket likes to send it, map to ORIGIN */ if (n == WSI_TOKEN_SWORIGIN) n = WSI_TOKEN_ORIGIN; wsi->u.hdr.parser_state = (enum lws_token_indexes) (WSI_TOKEN_GET_URI + n); if (context->token_limits) wsi->u.hdr.current_token_limit = context->token_limits->token_limit[ wsi->u.hdr.parser_state]; else wsi->u.hdr.current_token_limit = wsi->context->max_http_header_data; if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE) goto set_parsing_complete; goto start_fragment; } break; start_fragment: ah->nfrag++; excessive: if (ah->nfrag == ARRAY_SIZE(ah->frags)) { lwsl_warn("More hdr frags than we can deal with\n"); return -1; } ah->frags[ah->nfrag].offset = ah->pos; ah->frags[ah->nfrag].len = 0; ah->frags[ah->nfrag].nfrag = 0; n = ah->frag_index[wsi->u.hdr.parser_state]; if (!n) { /* first fragment */ ah->frag_index[wsi->u.hdr.parser_state] = ah->nfrag; break; } /* continuation */ while (ah->frags[n].nfrag) n = ah->frags[n].nfrag; ah->frags[n].nfrag = ah->nfrag; if (issue_char(wsi, ' ') < 0) return -1; break; /* skipping arg part of a name we didn't recognize */ case WSI_TOKEN_SKIPPING: lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c); if (c == '\x0d') wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR; break; case WSI_TOKEN_SKIPPING_SAW_CR: lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c); if (wsi->u.hdr.ues != URIES_IDLE) goto forbid; if (c == '\x0a') { wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; wsi->u.hdr.lextable_pos = 0; } else wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; break; /* we're done, ignore anything else */ case WSI_PARSING_COMPLETE: lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c); break; } return 0; set_parsing_complete: if (wsi->u.hdr.ues != URIES_IDLE) goto forbid; if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) { if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION)) wsi->ietf_spec_revision = atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION)); lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision); } wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE; wsi->hdr_parsing_completed = 1; return 0; forbid: lwsl_notice(" forbidding on uri sanitation\n"); lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); return -1; } /** * lws_frame_is_binary: true if the current frame was sent in binary mode * * @wsi: the connection we are inquiring about * * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if * it's interested to see if the frame it's dealing with was sent in binary * mode. */ LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi) { return wsi->u.ws.frame_is_binary; } int lws_rx_sm(struct lws *wsi, unsigned char c) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; int callback_action = LWS_CALLBACK_RECEIVE; int ret = 0, n, rx_draining_ext = 0; struct lws_tokens eff_buf; if (wsi->socket_is_permanently_unusable) return -1; switch (wsi->lws_rx_parse_state) { case LWS_RXPS_NEW: if (wsi->u.ws.rx_draining_ext) { struct lws **w = &pt->rx_draining_ext_list; eff_buf.token = NULL; eff_buf.token_len = 0; wsi->u.ws.rx_draining_ext = 0; /* remove us from context draining ext list */ while (*w) { if (*w == wsi) { *w = wsi->u.ws.rx_draining_ext_list; break; } w = &((*w)->u.ws.rx_draining_ext_list); } wsi->u.ws.rx_draining_ext_list = NULL; rx_draining_ext = 1; lwsl_err("%s: doing draining flow\n", __func__); goto drain_extension; } switch (wsi->ietf_spec_revision) { case 13: /* * no prepended frame key any more */ wsi->u.ws.all_zero_nonce = 1; goto handle_first; default: lwsl_warn("lws_rx_sm: unknown spec version %d\n", wsi->ietf_spec_revision); break; } break; case LWS_RXPS_04_mask_1: wsi->u.ws.mask[1] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_04_mask_2; break; case LWS_RXPS_04_mask_2: wsi->u.ws.mask[2] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_04_mask_3; break; case LWS_RXPS_04_mask_3: wsi->u.ws.mask[3] = c; if (c) wsi->u.ws.all_zero_nonce = 0; /* * start from the zero'th byte in the XOR key buffer since * this is the start of a frame with a new key */ wsi->u.ws.mask_idx = 0; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1; break; /* * 04 logical framing from the spec (all this is masked when incoming * and has to be unmasked) * * We ignore the possibility of extension data because we don't * negotiate any extensions at the moment. * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-------+-+-------------+-------------------------------+ * |F|R|R|R| opcode|R| Payload len | Extended payload length | * |I|S|S|S| (4) |S| (7) | (16/63) | * |N|V|V|V| |V| | (if payload len==126/127) | * | |1|2|3| |4| | | * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + * | Extended payload length continued, if payload len == 127 | * + - - - - - - - - - - - - - - - +-------------------------------+ * | | Extension data | * +-------------------------------+ - - - - - - - - - - - - - - - + * : : * +---------------------------------------------------------------+ * : Application data : * +---------------------------------------------------------------+ * * We pass payload through to userland as soon as we get it, ignoring * FIN. It's up to userland to buffer it up if it wants to see a * whole unfragmented block of the original size (which may be up to * 2^63 long!) */ case LWS_RXPS_04_FRAME_HDR_1: handle_first: wsi->u.ws.opcode = c & 0xf; wsi->u.ws.rsv = c & 0x70; wsi->u.ws.final = !!((c >> 7) & 1); switch (wsi->u.ws.opcode) { case LWSWSOPC_TEXT_FRAME: case LWSWSOPC_BINARY_FRAME: wsi->u.ws.rsv_first_msg = (c & 0x70); wsi->u.ws.frame_is_binary = wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME; break; case 3: case 4: case 5: case 6: case 7: case 0xb: case 0xc: case 0xd: case 0xe: case 0xf: lwsl_info("illegal opcode\n"); return -1; } wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; break; case LWS_RXPS_04_FRAME_HDR_LEN: wsi->u.ws.this_frame_masked = !!(c & 0x80); switch (c & 0x7f) { case 126: /* control frames are not allowed to have big lengths */ if (wsi->u.ws.opcode & 8) goto illegal_ctl_length; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2; break; case 127: /* control frames are not allowed to have big lengths */ if (wsi->u.ws.opcode & 8) goto illegal_ctl_length; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8; break; default: wsi->u.ws.rx_packet_length = c & 0x7f; if (wsi->u.ws.this_frame_masked) wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; else if (wsi->u.ws.rx_packet_length) wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; else { wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } break; } break; case LWS_RXPS_04_FRAME_HDR_LEN16_2: wsi->u.ws.rx_packet_length = c << 8; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; break; case LWS_RXPS_04_FRAME_HDR_LEN16_1: wsi->u.ws.rx_packet_length |= c; if (wsi->u.ws.this_frame_masked) wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; else wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; case LWS_RXPS_04_FRAME_HDR_LEN64_8: if (c & 0x80) { lwsl_warn("b63 of length must be zero\n"); /* kill the connection */ return -1; } #if defined __LP64__ wsi->u.ws.rx_packet_length = ((size_t)c) << 56; #else wsi->u.ws.rx_packet_length = 0; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7; break; case LWS_RXPS_04_FRAME_HDR_LEN64_7: #if defined __LP64__ wsi->u.ws.rx_packet_length |= ((size_t)c) << 48; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6; break; case LWS_RXPS_04_FRAME_HDR_LEN64_6: #if defined __LP64__ wsi->u.ws.rx_packet_length |= ((size_t)c) << 40; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5; break; case LWS_RXPS_04_FRAME_HDR_LEN64_5: #if defined __LP64__ wsi->u.ws.rx_packet_length |= ((size_t)c) << 32; #endif wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4; break; case LWS_RXPS_04_FRAME_HDR_LEN64_4: wsi->u.ws.rx_packet_length |= ((size_t)c) << 24; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; break; case LWS_RXPS_04_FRAME_HDR_LEN64_3: wsi->u.ws.rx_packet_length |= ((size_t)c) << 16; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; break; case LWS_RXPS_04_FRAME_HDR_LEN64_2: wsi->u.ws.rx_packet_length |= ((size_t)c) << 8; wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; break; case LWS_RXPS_04_FRAME_HDR_LEN64_1: wsi->u.ws.rx_packet_length |= ((size_t)c); if (wsi->u.ws.this_frame_masked) wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; else wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_1: wsi->u.ws.mask[0] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_2: wsi->u.ws.mask[1] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_3: wsi->u.ws.mask[2] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4; break; case LWS_RXPS_07_COLLECT_FRAME_KEY_4: wsi->u.ws.mask[3] = c; if (c) wsi->u.ws.all_zero_nonce = 0; wsi->lws_rx_parse_state = LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED; wsi->u.ws.mask_idx = 0; if (wsi->u.ws.rx_packet_length == 0) { wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } break; case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: assert(wsi->u.ws.rx_ubuf); if (wsi->u.ws.rx_ubuf_head + LWS_PRE >= wsi->u.ws.rx_ubuf_alloc) { lwsl_err("Attempted overflow \n"); return -1; } if (wsi->u.ws.all_zero_nonce) wsi->u.ws.rx_ubuf[LWS_PRE + (wsi->u.ws.rx_ubuf_head++)] = c; else wsi->u.ws.rx_ubuf[LWS_PRE + (wsi->u.ws.rx_ubuf_head++)] = c ^ wsi->u.ws.mask[ (wsi->u.ws.mask_idx++) & 3]; if (--wsi->u.ws.rx_packet_length == 0) { /* spill because we have the whole frame */ wsi->lws_rx_parse_state = LWS_RXPS_NEW; goto spill; } /* * if there's no protocol max frame size given, we are * supposed to default to LWS_MAX_SOCKET_IO_BUF */ if (!wsi->protocol->rx_buffer_size && wsi->u.ws.rx_ubuf_head != LWS_MAX_SOCKET_IO_BUF) break; else if (wsi->protocol->rx_buffer_size && wsi->u.ws.rx_ubuf_head != wsi->protocol->rx_buffer_size) break; /* spill because we filled our rx buffer */ spill: /* * is this frame a control packet we should take care of at this * layer? If so service it and hide it from the user callback */ lwsl_parser("spill on %s\n", wsi->protocol->name); switch (wsi->u.ws.opcode) { case LWSWSOPC_CLOSE: /* is this an acknowledgement of our close? */ if (wsi->state == LWSS_AWAITING_CLOSE_ACK) { /* * fine he has told us he is closing too, let's * finish our close */ lwsl_parser("seen client close ack\n"); return -1; } if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY) /* if he sends us 2 CLOSE, kill him */ return -1; if (user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, wsi->user_space, &wsi->u.ws.rx_ubuf[LWS_PRE], wsi->u.ws.rx_ubuf_head)) return -1; lwsl_parser("server sees client close packet\n"); wsi->state = LWSS_RETURNED_CLOSE_ALREADY; /* deal with the close packet contents as a PONG */ wsi->u.ws.payload_is_close = 1; goto process_as_ping; case LWSWSOPC_PING: lwsl_info("received %d byte ping, sending pong\n", wsi->u.ws.rx_ubuf_head); if (wsi->u.ws.ping_pending_flag) { /* * there is already a pending ping payload * we should just log and drop */ lwsl_parser("DROP PING since one pending\n"); goto ping_drop; } process_as_ping: /* control packets can only be < 128 bytes long */ if (wsi->u.ws.rx_ubuf_head > 128 - 3) { lwsl_parser("DROP PING payload too large\n"); goto ping_drop; } /* stash the pong payload */ memcpy(wsi->u.ws.ping_payload_buf + LWS_PRE, &wsi->u.ws.rx_ubuf[LWS_PRE], wsi->u.ws.rx_ubuf_head); wsi->u.ws.ping_payload_len = wsi->u.ws.rx_ubuf_head; wsi->u.ws.ping_pending_flag = 1; /* get it sent as soon as possible */ lws_callback_on_writable(wsi); ping_drop: wsi->u.ws.rx_ubuf_head = 0; return 0; case LWSWSOPC_PONG: lwsl_info("received pong\n"); lwsl_hexdump(&wsi->u.ws.rx_ubuf[LWS_PRE], wsi->u.ws.rx_ubuf_head); /* issue it */ callback_action = LWS_CALLBACK_RECEIVE_PONG; break; case LWSWSOPC_TEXT_FRAME: case LWSWSOPC_BINARY_FRAME: case LWSWSOPC_CONTINUATION: break; default: lwsl_parser("passing opc %x up to exts\n", wsi->u.ws.opcode); /* * It's something special we can't understand here. * Pass the payload up to the extension's parsing * state machine. */ eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE]; eff_buf.token_len = wsi->u.ws.rx_ubuf_head; if (lws_ext_cb_active(wsi, LWS_EXT_CB_EXTENDED_PAYLOAD_RX, &eff_buf, 0) <= 0) /* not handle or fail */ lwsl_ext("ext opc opcode 0x%x unknown\n", wsi->u.ws.opcode); wsi->u.ws.rx_ubuf_head = 0; return 0; } /* * No it's real payload, pass it up to the user callback. * It's nicely buffered with the pre-padding taken care of * so it can be sent straight out again using lws_write */ eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE]; eff_buf.token_len = wsi->u.ws.rx_ubuf_head; drain_extension: lwsl_ext("%s: passing %d to ext\n", __func__, eff_buf.token_len); if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY || wsi->state == LWSS_AWAITING_CLOSE_ACK) goto already_done; n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0); if (n < 0) { /* * we may rely on this to get RX, just drop connection */ wsi->socket_is_permanently_unusable = 1; return -1; } if (rx_draining_ext && eff_buf.token_len == 0) goto already_done; if (n && eff_buf.token_len) { /* extension had more... main loop will come back */ wsi->u.ws.rx_draining_ext = 1; wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list; pt->rx_draining_ext_list = wsi; } if (eff_buf.token_len > 0 || callback_action == LWS_CALLBACK_RECEIVE_PONG) { eff_buf.token[eff_buf.token_len] = '\0'; if (wsi->protocol->callback) { if (callback_action == LWS_CALLBACK_RECEIVE_PONG) lwsl_info("Doing pong callback\n"); ret = user_callback_handle_rxflow( wsi->protocol->callback, wsi, (enum lws_callback_reasons)callback_action, wsi->user_space, eff_buf.token, eff_buf.token_len); } else lwsl_err("No callback on payload spill!\n"); } already_done: wsi->u.ws.rx_ubuf_head = 0; break; } return ret; illegal_ctl_length: lwsl_warn("Control frame with xtended length is illegal\n"); /* kill the connection */ return -1; } /** * lws_remaining_packet_payload() - Bytes to come before "overall" * rx packet is complete * @wsi: Websocket instance (available from user callback) * * This function is intended to be called from the callback if the * user code is interested in "complete packets" from the client. * libwebsockets just passes through payload as it comes and issues a buffer * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE * callback handler can use this API to find out if the buffer it has just * been given is the last piece of a "complete packet" from the client -- * when that is the case lws_remaining_packet_payload() will return * 0. * * Many protocols won't care becuse their packets are always small. */ LWS_VISIBLE size_t lws_remaining_packet_payload(struct lws *wsi) { return wsi->u.ws.rx_packet_length; } /* Once we reach LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED, we know how much * to expect in that state and can deal with it in bulk more efficiently. */ int lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf, size_t *len) { unsigned char *buffer = *buf, mask[4]; int buffer_size, n; unsigned int avail; char *rx_ubuf; if (wsi->protocol->rx_buffer_size) buffer_size = wsi->protocol->rx_buffer_size; else buffer_size = LWS_MAX_SOCKET_IO_BUF; avail = buffer_size - wsi->u.ws.rx_ubuf_head; /* do not consume more than we should */ if (avail > wsi->u.ws.rx_packet_length) avail = wsi->u.ws.rx_packet_length; /* do not consume more than what is in the buffer */ if (avail > *len) avail = *len; /* we want to leave 1 byte for the parser to handle properly */ if (avail <= 1) return 0; avail--; rx_ubuf = wsi->u.ws.rx_ubuf + LWS_PRE + wsi->u.ws.rx_ubuf_head; if (wsi->u.ws.all_zero_nonce) memcpy(rx_ubuf, buffer, avail); else { for (n = 0; n < 4; n++) mask[n] = wsi->u.ws.mask[(wsi->u.ws.mask_idx + n) & 3]; /* deal with 4-byte chunks using unwrapped loop */ n = avail >> 2; while (n--) { *(rx_ubuf++) = *(buffer++) ^ mask[0]; *(rx_ubuf++) = *(buffer++) ^ mask[1]; *(rx_ubuf++) = *(buffer++) ^ mask[2]; *(rx_ubuf++) = *(buffer++) ^ mask[3]; } /* and the remaining bytes bytewise */ for (n = 0; n < (int)(avail & 3); n++) *(rx_ubuf++) = *(buffer++) ^ mask[n]; wsi->u.ws.mask_idx = (wsi->u.ws.mask_idx + avail) & 3; } (*buf) += avail; wsi->u.ws.rx_ubuf_head += avail; wsi->u.ws.rx_packet_length -= avail; *len -= avail; return avail; } |
Added undroid/libwebsockets/lib/pollfd.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" int _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa) { struct lws_context_per_thread *pt; struct lws_context *context; int ret = 0, pa_events = 1; struct lws_pollfd *pfd; int sampled_tid, tid; if (!wsi || wsi->position_in_fds_table < 0) return 0; context = wsi->context; pt = &context->pt[(int)wsi->tsi]; assert(wsi->position_in_fds_table >= 0 && wsi->position_in_fds_table < pt->fds_count); pfd = &pt->fds[wsi->position_in_fds_table]; pa->fd = wsi->sock; pa->prev_events = pfd->events; pa->events = pfd->events = (pfd->events & ~_and) | _or; if (wsi->http2_substream) return 0; if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CHANGE_MODE_POLL_FD, wsi->user_space, (void *)pa, 0)) { ret = -1; goto bail; } if (_and & LWS_POLLIN) { lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ); lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ); } if (_or & LWS_POLLIN) { lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ); lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ); } if (_and & LWS_POLLOUT) { lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE); lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_WRITE); } if (_or & LWS_POLLOUT) { lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE); lws_libuv_io(wsi, LWS_EV_START | LWS_EV_WRITE); } /* * if we changed something in this pollfd... * ... and we're running in a different thread context * than the service thread... * ... and the service thread is waiting ... * then cancel it to force a restart with our changed events */ #if LWS_POSIX pa_events = pa->prev_events != pa->events; #endif if (pa_events) { if (lws_plat_change_pollfd(context, wsi, pfd)) { lwsl_info("%s failed\n", __func__); ret = -1; goto bail; } sampled_tid = context->service_tid; if (sampled_tid) { tid = wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); if (tid == -1) { ret = -1; goto bail; } if (tid != sampled_tid) lws_cancel_service_pt(wsi); } } bail: return ret; } int insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi) { struct lws_pollargs pa = { wsi->sock, LWS_POLLIN, 0 }; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int ret = 0; #ifndef LWS_NO_SERVER struct lws_pollargs pa1; #endif lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n", __func__, wsi, wsi->tsi, wsi->sock, pt->fds_count); if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) { lwsl_err("Too many fds (%d vs %d)\n", context->max_fds, context->fd_limit_per_thread ); return 1; } #if !defined(_WIN32) && !defined(MBED_OPERATORS) if (wsi->sock >= context->max_fds) { lwsl_err("Socket fd %d is too high (%d)\n", wsi->sock, context->max_fds); return 1; } #endif assert(wsi); assert(wsi->vhost); assert(lws_socket_is_valid(wsi->sock)); if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 1)) return -1; lws_pt_lock(pt); pt->count_conns++; insert_wsi(context, wsi); wsi->position_in_fds_table = pt->fds_count; pt->fds[pt->fds_count].fd = wsi->sock; pt->fds[pt->fds_count].events = LWS_POLLIN; pa.events = pt->fds[pt->fds_count].events; lws_plat_insert_socket_into_fds(context, wsi); /* external POLL support via protocol 0 */ if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD, wsi->user_space, (void *) &pa, 0)) ret = -1; #ifndef LWS_NO_SERVER /* if no more room, defeat accepts on this thread */ if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1) _lws_change_pollfd(pt->wsi_listening, LWS_POLLIN, 0, &pa1); #endif lws_pt_unlock(pt); if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *)&pa, 1)) ret = -1; return ret; } int remove_wsi_socket_from_fds(struct lws *wsi) { struct lws_pollargs pa = { wsi->sock, 0, 0 }; #ifndef LWS_NO_SERVER struct lws_pollargs pa1; #endif struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; struct lws *end_wsi; int m, ret = 0; #if !defined(_WIN32) && !defined(MBED_OPERATORS) if (wsi->sock > context->max_fds) { lwsl_err("fd %d too high (%d)\n", wsi->sock, context->max_fds); return 1; } #endif if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *)&pa, 1)) return -1; /* * detach ourselves from vh protocol list if we're on one * A -> B -> C * A -> C , or, B -> C, or A -> B */ lwsl_info("%s: removing same prot wsi %p\n", __func__, wsi); if (wsi->same_vh_protocol_prev) { assert (*(wsi->same_vh_protocol_prev) == wsi); lwsl_info("have prev %p, setting him to our next %p\n", wsi->same_vh_protocol_prev, wsi->same_vh_protocol_next); /* guy who pointed to us should point to our next */ *(wsi->same_vh_protocol_prev) = wsi->same_vh_protocol_next; } //else //lwsl_err("null wsi->prev\n"); /* our next should point back to our prev */ if (wsi->same_vh_protocol_next) { lwsl_info("have next %p\n"); wsi->same_vh_protocol_next->same_vh_protocol_prev = wsi->same_vh_protocol_prev; } //else //lwsl_err("null wsi->next\n"); lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE | LWS_EV_PREPARE_DELETION); lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE | LWS_EV_PREPARE_DELETION); lws_pt_lock(pt); lwsl_info("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n", __func__, wsi, wsi->sock, wsi->position_in_fds_table, pt->fds_count, pt->fds[pt->fds_count].fd); /* the guy who is to be deleted's slot index in pt->fds */ m = wsi->position_in_fds_table; /* have the last guy take up the now vacant slot */ pt->fds[m] = pt->fds[pt->fds_count - 1]; lws_plat_delete_socket_from_fds(context, wsi, m); /* end guy's "position in fds table" is now the deletion guy's old one */ end_wsi = wsi_from_fd(context, pt->fds[pt->fds_count].fd); assert(end_wsi); end_wsi->position_in_fds_table = m; /* deletion guy's lws_lookup entry needs nuking */ delete_from_fd(context, wsi->sock); /* removed wsi has no position any more */ wsi->position_in_fds_table = -1; /* remove also from external POLL support via protocol 0 */ if (lws_socket_is_valid(wsi->sock)) if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD, wsi->user_space, (void *) &pa, 0)) ret = -1; #ifndef LWS_NO_SERVER if (!context->being_destroyed) /* if this made some room, accept connects on this thread */ if ((unsigned int)pt->fds_count < context->fd_limit_per_thread - 1) _lws_change_pollfd(pt->wsi_listening, 0, LWS_POLLIN, &pa1); #endif lws_pt_unlock(pt); if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *) &pa, 1)) ret = -1; return ret; } int lws_change_pollfd(struct lws *wsi, int _and, int _or) { struct lws_context_per_thread *pt; struct lws_context *context; struct lws_pollargs pa; int ret = 0; if (!wsi || !wsi->protocol || wsi->position_in_fds_table < 0) return 1; context = lws_get_context(wsi); if (!context) return 1; if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 0)) return -1; pt = &context->pt[(int)wsi->tsi]; lws_pt_lock(pt); ret = _lws_change_pollfd(wsi, _and, _or, &pa); lws_pt_unlock(pt); if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *) &pa, 0)) ret = -1; return ret; } /** * lws_callback_on_writable() - Request a callback when this socket * becomes able to be written to without * blocking * * @wsi: Websocket connection instance to get callback for */ LWS_VISIBLE int lws_callback_on_writable(struct lws *wsi) { #ifdef LWS_USE_HTTP2 struct lws *network_wsi, *wsi2; int already; #endif if (wsi->state == LWSS_SHUTDOWN) return 0; if (wsi->socket_is_permanently_unusable) return 0; #ifdef LWS_USE_HTTP2 lwsl_info("%s: %p\n", __func__, wsi); if (wsi->mode != LWSCM_HTTP2_SERVING) goto network_sock; if (wsi->u.http2.requested_POLLOUT) { lwsl_info("already pending writable\n"); return 1; } if (wsi->u.http2.tx_credit <= 0) { /* * other side is not able to cope with us sending * anything so no matter if we have POLLOUT on our side. * * Delay waiting for our POLLOUT until peer indicates he has * space for more using tx window command in http2 layer */ lwsl_info("%s: %p: waiting_tx_credit (%d)\n", __func__, wsi, wsi->u.http2.tx_credit); wsi->u.http2.waiting_tx_credit = 1; return 0; } network_wsi = lws_http2_get_network_wsi(wsi); already = network_wsi->u.http2.requested_POLLOUT; /* mark everybody above him as requesting pollout */ wsi2 = wsi; while (wsi2) { wsi2->u.http2.requested_POLLOUT = 1; lwsl_info("mark %p pending writable\n", wsi2); wsi2 = wsi2->u.http2.parent_wsi; } /* for network action, act only on the network wsi */ wsi = network_wsi; if (already) return 1; network_sock: #endif if (lws_ext_cb_active(wsi, LWS_EXT_CB_REQUEST_ON_WRITEABLE, NULL, 0)) return 1; if (wsi->position_in_fds_table < 0) { lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock); return -1; } if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) return -1; return 1; } /** * lws_callback_on_writable_all_protocol_vhost() - Request a callback for * all connections using the given protocol when it * becomes possible to write to each socket without * blocking in turn. * * This calls back connections with the same protocol ON THE SAME * VHOST ONLY. * * @vhost: Only consider connections on this lws_vhost * @protocol: Protocol whose connections will get callbacks */ LWS_VISIBLE int lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost, const struct lws_protocols *protocol) { struct lws *wsi; if (protocol < vhost->protocols || protocol >= (vhost->protocols + vhost->count_protocols)) { lwsl_err("%s: protocol is not from vhost\n", __func__); return -1; } wsi = vhost->same_vh_protocol_list[protocol - vhost->protocols]; //lwsl_notice("%s: protocol %p, start wsi %p\n", __func__, protocol, wsi); while (wsi) { //lwsl_notice("%s: protocol %p, this wsi %p (wsi->protocol=%p)\n", // __func__, protocol, wsi, wsi->protocol); assert(wsi->protocol == protocol); assert(*wsi->same_vh_protocol_prev == wsi); if (wsi->same_vh_protocol_next) { // lwsl_err("my next says %p\n", wsi->same_vh_protocol_next); // lwsl_err("my next's prev says %p\n", // wsi->same_vh_protocol_next->same_vh_protocol_prev); assert(wsi->same_vh_protocol_next->same_vh_protocol_prev == &wsi->same_vh_protocol_next); } lws_callback_on_writable(wsi); wsi = wsi->same_vh_protocol_next; } return 0; } /** * lws_callback_on_writable_all_protocol() - Request a callback for * all connections using the given protocol when it * becomes possible to write to each socket without * blocking in turn. * * This calls back any connection using the same protocol on ANY * VHOST. * * @context: lws_context * @protocol: Protocol whose connections will get callbacks */ LWS_VISIBLE int lws_callback_on_writable_all_protocol(const struct lws_context *context, const struct lws_protocols *protocol) { struct lws_vhost *vhost = context->vhost_list; int n; while (vhost) { for (n = 0; n < vhost->count_protocols; n++) if (protocol->callback == vhost->protocols[n].callback && !strcmp(protocol->name, vhost->protocols[n].name)) break; if (n != vhost->count_protocols) lws_callback_on_writable_all_protocol_vhost( vhost, &vhost->protocols[n]); vhost = vhost->vhost_next; } return 0; } |
Added undroid/libwebsockets/lib/private-libwebsockets.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 - 2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "lws_config.h" #include "lws_config_private.h" #if defined(LWS_WITH_CGI) && defined(LWS_HAVE_VFORK) #define _GNU_SOURCE #endif #ifdef LWS_HAVE_SYS_TYPES_H #include <sys/types.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <ctype.h> #include <limits.h> #include <stdarg.h> #include <assert.h> #if LWS_MAX_SMP > 1 #include <pthread.h> #endif #ifdef LWS_HAVE_SYS_STAT_H #include <sys/stat.h> #endif #if defined(WIN32) || defined(_WIN32) #if (WINVER < 0x0501) #undef WINVER #undef _WIN32_WINNT #define WINVER 0x0501 #define _WIN32_WINNT WINVER #endif #define LWS_NO_DAEMONIZE #define LWS_ERRNO WSAGetLastError() #define LWS_EAGAIN WSAEWOULDBLOCK #define LWS_EALREADY WSAEALREADY #define LWS_EINPROGRESS WSAEINPROGRESS #define LWS_EINTR WSAEINTR #define LWS_EISCONN WSAEISCONN #define LWS_EWOULDBLOCK WSAEWOULDBLOCK #define LWS_POLLHUP (FD_CLOSE) #define LWS_POLLIN (FD_READ | FD_ACCEPT) #define LWS_POLLOUT (FD_WRITE) #define MSG_NOSIGNAL 0 #define SHUT_RDWR SD_BOTH #define SOL_TCP IPPROTO_TCP #define SHUT_WR SD_SEND #define compatible_close(fd) closesocket(fd) #define lws_set_blocking_send(wsi) wsi->sock_send_blocking = 1 #define lws_socket_is_valid(x) (!!x) #define LWS_SOCK_INVALID 0 #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h> #include <tchar.h> #ifdef LWS_HAVE_IN6ADDR_H #include <in6addr.h> #endif #include <mstcpip.h> #include <io.h> #ifndef __func__ #define __func__ __FUNCTION__ #endif #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE) #define vsnprintf _vsnprintf #else #ifdef LWS_HAVE__VSNPRINTF #define vsnprintf _vsnprintf #endif #endif #ifdef LWS_HAVE__SNPRINTF #define lws_snprintf _snprintf #endif #else /* not windows --> */ #include <fcntl.h> #include <strings.h> #include <unistd.h> #include <sys/types.h> #ifndef MBED_OPERATORS #ifndef __cplusplus #include <errno.h> #endif #include <netdb.h> #include <signal.h> #include <sys/socket.h> #ifdef LWS_WITH_HTTP_PROXY #include <hubbub/hubbub.h> #include <hubbub/parser.h> #endif #ifdef LWS_BUILTIN_GETIFADDRS #include <getifaddrs.h> #else #include <ifaddrs.h> #endif #if defined (__ANDROID__) #include <syslog.h> #include <sys/resource.h> #else #include <sys/syslog.h> #endif #include <sys/un.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <poll.h> #ifdef LWS_USE_LIBEV #include <ev.h> #endif #ifdef LWS_USE_LIBUV #include <uv.h> #endif #include <sys/mman.h> #endif /* MBED */ #ifndef LWS_NO_FORK #ifdef LWS_HAVE_SYS_PRCTL_H #include <sys/prctl.h> #endif #endif #include <sys/time.h> #define LWS_ERRNO errno #define LWS_EAGAIN EAGAIN #define LWS_EALREADY EALREADY #define LWS_EINPROGRESS EINPROGRESS #define LWS_EINTR EINTR #define LWS_EISCONN EISCONN #define LWS_EWOULDBLOCK EWOULDBLOCK #define LWS_POLLHUP (POLLHUP|POLLERR) #define LWS_POLLIN (POLLIN) #define LWS_POLLOUT (POLLOUT) static inline int compatible_close(int fd) { return close(fd); } #define lws_set_blocking_send(wsi) #ifdef MBED_OPERATORS #define lws_socket_is_valid(x) ((x) != NULL) #define LWS_SOCK_INVALID (NULL) #else #define lws_socket_is_valid(x) (x >= 0) #define LWS_SOCK_INVALID (-1) #endif #endif #ifndef LWS_HAVE_BZERO #ifndef bzero #define bzero(b, len) (memset((b), '\0', (len)), (void) 0) #endif #endif #ifndef LWS_HAVE_STRERROR #define strerror(x) "" #endif #ifdef LWS_OPENSSL_SUPPORT #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL #include <cyassl/openssl/ssl.h> #include <cyassl/error-ssl.h> #else #include <wolfssl/openssl/ssl.h> #include <wolfssl/error-ssl.h> #endif /* not USE_OLD_CYASSL */ #else #if defined(LWS_USE_POLARSSL) #include <polarssl/ssl.h> #include <polarssl/error.h> #include <polarssl/md5.h> #include <polarssl/sha1.h> #include <polarssl/ecdh.h> #define SSL_ERROR_WANT_READ POLARSSL_ERR_NET_WANT_READ #define SSL_ERROR_WANT_WRITE POLARSSL_ERR_NET_WANT_WRITE #define OPENSSL_VERSION_NUMBER 0x10002000L #else #if defined(LWS_USE_MBEDTLS) #include <mbedtls/ssl.h> #include <mbedtls/error.h> #include <mbedtls/md5.h> #include <mbedtls/sha1.h> #include <mbedtls/ecdh.h> #else #include <openssl/ssl.h> #include <openssl/evp.h> #include <openssl/err.h> #include <openssl/md5.h> #include <openssl/sha.h> #ifdef LWS_HAVE_OPENSSL_ECDH_H #include <openssl/ecdh.h> #endif #include <openssl/x509v3.h> #endif /* not USE_MBEDTLS */ #endif /* not USE_POLARSSL */ #endif /* not USE_WOLFSSL */ #endif #include "libwebsockets.h" #if defined(MBED_OPERATORS) #undef compatible_close #define compatible_close(fd) mbed3_delete_tcp_stream_socket(fd) #ifndef BIG_ENDIAN #define BIG_ENDIAN 4321 /* to show byte order (taken from gcc) */ #endif #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN 1234 #endif #ifndef BYTE_ORDER #define BYTE_ORDER LITTLE_ENDIAN #endif #endif #if defined(WIN32) || defined(_WIN32) #ifndef BIG_ENDIAN #define BIG_ENDIAN 4321 /* to show byte order (taken from gcc) */ #endif #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN 1234 #endif #ifndef BYTE_ORDER #define BYTE_ORDER LITTLE_ENDIAN #endif #ifndef u_int64_t typedef unsigned __int64 u_int64_t; #endif #undef __P #ifndef __P #if __STDC__ #define __P(protos) protos #else #define __P(protos) () #endif #endif #else #include <sys/stat.h> #include <sys/time.h> #if defined(__APPLE__) #include <machine/endian.h> #elif defined(__FreeBSD__) #include <sys/endian.h> #elif defined(__linux__) #include <endian.h> #endif #ifdef __cplusplus extern "C" { #endif #if defined(__QNX__) #include <gulliver.h> #if defined(__LITTLEENDIAN__) #define BYTE_ORDER __LITTLEENDIAN__ #define LITTLE_ENDIAN __LITTLEENDIAN__ #define BIG_ENDIAN 4321 /* to show byte order (taken from gcc); for suppres warning that BIG_ENDIAN is not defined. */ #endif #if defined(__BIGENDIAN__) #define BYTE_ORDER __BIGENDIAN__ #define LITTLE_ENDIAN 1234 /* to show byte order (taken from gcc); for suppres warning that LITTLE_ENDIAN is not defined. */ #define BIG_ENDIAN __BIGENDIAN__ #endif #endif #if !defined(BYTE_ORDER) # define BYTE_ORDER __BYTE_ORDER #endif #if !defined(LITTLE_ENDIAN) # define LITTLE_ENDIAN __LITTLE_ENDIAN #endif #if !defined(BIG_ENDIAN) # define BIG_ENDIAN __BIG_ENDIAN #endif #endif /* * Mac OSX as well as iOS do not define the MSG_NOSIGNAL flag, * but happily have something equivalent in the SO_NOSIGPIPE flag. */ #ifdef __APPLE__ #define MSG_NOSIGNAL SO_NOSIGPIPE #endif #ifdef _WIN32 #ifndef FD_HASHTABLE_MODULUS #define FD_HASHTABLE_MODULUS 32 #endif #endif #ifndef LWS_DEF_HEADER_LEN #define LWS_DEF_HEADER_LEN 1024 #endif #ifndef LWS_DEF_HEADER_POOL #define LWS_DEF_HEADER_POOL 16 #endif #ifndef LWS_MAX_PROTOCOLS #define LWS_MAX_PROTOCOLS 5 #endif #ifndef LWS_MAX_EXTENSIONS_ACTIVE #define LWS_MAX_EXTENSIONS_ACTIVE 2 #endif #ifndef LWS_MAX_EXT_OFFERS #define LWS_MAX_EXT_OFFERS 8 #endif #ifndef SPEC_LATEST_SUPPORTED #define SPEC_LATEST_SUPPORTED 13 #endif #ifndef AWAITING_TIMEOUT #define AWAITING_TIMEOUT 20 #endif #ifndef CIPHERS_LIST_STRING #define CIPHERS_LIST_STRING "DEFAULT" #endif #ifndef LWS_SOMAXCONN #define LWS_SOMAXCONN SOMAXCONN #endif #define MAX_WEBSOCKET_04_KEY_LEN 128 #define LWS_MAX_SOCKET_IO_BUF 4096 #ifndef SYSTEM_RANDOM_FILEPATH #define SYSTEM_RANDOM_FILEPATH "/dev/urandom" #endif enum lws_websocket_opcodes_07 { LWSWSOPC_CONTINUATION = 0, LWSWSOPC_TEXT_FRAME = 1, LWSWSOPC_BINARY_FRAME = 2, LWSWSOPC_NOSPEC__MUX = 7, /* control extensions 8+ */ LWSWSOPC_CLOSE = 8, LWSWSOPC_PING = 9, LWSWSOPC_PONG = 0xa, }; enum lws_connection_states { LWSS_HTTP, LWSS_HTTP_ISSUING_FILE, LWSS_HTTP_HEADERS, LWSS_HTTP_BODY, LWSS_DEAD_SOCKET, LWSS_ESTABLISHED, LWSS_CLIENT_HTTP_ESTABLISHED, LWSS_CLIENT_UNCONNECTED, LWSS_RETURNED_CLOSE_ALREADY, LWSS_AWAITING_CLOSE_ACK, LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE, LWSS_SHUTDOWN, LWSS_HTTP2_AWAIT_CLIENT_PREFACE, LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS, LWSS_HTTP2_ESTABLISHED, LWSS_CGI, }; enum http_version { HTTP_VERSION_1_0, HTTP_VERSION_1_1, HTTP_VERSION_2 }; enum http_connection_type { HTTP_CONNECTION_CLOSE, HTTP_CONNECTION_KEEP_ALIVE }; enum lws_pending_protocol_send { LWS_PPS_NONE, LWS_PPS_HTTP2_MY_SETTINGS, LWS_PPS_HTTP2_ACK_SETTINGS, LWS_PPS_HTTP2_PONG, }; enum lws_rx_parse_state { LWS_RXPS_NEW, LWS_RXPS_04_mask_1, LWS_RXPS_04_mask_2, LWS_RXPS_04_mask_3, LWS_RXPS_04_FRAME_HDR_1, LWS_RXPS_04_FRAME_HDR_LEN, LWS_RXPS_04_FRAME_HDR_LEN16_2, LWS_RXPS_04_FRAME_HDR_LEN16_1, LWS_RXPS_04_FRAME_HDR_LEN64_8, LWS_RXPS_04_FRAME_HDR_LEN64_7, LWS_RXPS_04_FRAME_HDR_LEN64_6, LWS_RXPS_04_FRAME_HDR_LEN64_5, LWS_RXPS_04_FRAME_HDR_LEN64_4, LWS_RXPS_04_FRAME_HDR_LEN64_3, LWS_RXPS_04_FRAME_HDR_LEN64_2, LWS_RXPS_04_FRAME_HDR_LEN64_1, LWS_RXPS_07_COLLECT_FRAME_KEY_1, LWS_RXPS_07_COLLECT_FRAME_KEY_2, LWS_RXPS_07_COLLECT_FRAME_KEY_3, LWS_RXPS_07_COLLECT_FRAME_KEY_4, LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED }; enum connection_mode { LWSCM_HTTP_SERVING, LWSCM_HTTP_CLIENT, /* we are client to someone else's server */ LWSCM_HTTP_SERVING_ACCEPTED, /* actual HTTP service going on */ LWSCM_HTTP_CLIENT_ACCEPTED, /* actual HTTP service going on */ LWSCM_PRE_WS_SERVING_ACCEPT, LWSCM_WS_SERVING, LWSCM_WS_CLIENT, LWSCM_HTTP2_SERVING, /* transient, ssl delay hiding */ LWSCM_SSL_ACK_PENDING, LWSCM_SSL_INIT, /* transient modes */ LWSCM_WSCL_WAITING_CONNECT, LWSCM_WSCL_WAITING_PROXY_REPLY, LWSCM_WSCL_ISSUE_HANDSHAKE, LWSCM_WSCL_ISSUE_HANDSHAKE2, LWSCM_WSCL_WAITING_SSL, LWSCM_WSCL_WAITING_SERVER_REPLY, LWSCM_WSCL_WAITING_EXTENSION_CONNECT, LWSCM_WSCL_PENDING_CANDIDATE_CHILD, /* special internal types */ LWSCM_SERVER_LISTENER, LWSCM_CGI, /* stdin, stdout, stderr for another cgi master wsi */ }; enum { LWS_RXFLOW_ALLOW = (1 << 0), LWS_RXFLOW_PENDING_CHANGE = (1 << 1), }; /* this is not usable directly by user code any more, lws_close_reason() */ #define LWS_WRITE_CLOSE 4 struct lws_protocols; struct lws; #if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) struct lws_io_watcher { #ifdef LWS_USE_LIBEV ev_io ev_watcher; #endif #ifdef LWS_USE_LIBUV uv_poll_t uv_watcher; #endif struct lws_context *context; }; struct lws_signal_watcher { #ifdef LWS_USE_LIBEV ev_signal ev_watcher; #endif #ifdef LWS_USE_LIBUV uv_signal_t uv_watcher; #endif struct lws_context *context; }; #endif #ifdef _WIN32 #define LWS_FD_HASH(fd) ((fd ^ (fd >> 8) ^ (fd >> 16)) % FD_HASHTABLE_MODULUS) struct lws_fd_hashtable { struct lws **wsi; int length; }; #endif /* * This is totally opaque to code using the library. It's exported as a * forward-reference pointer-only declaration; the user can use the pointer with * other APIs to get information out of it. */ struct lws_fragments { unsigned short offset; unsigned short len; unsigned char nfrag; /* which ah->frag[] continues this content, or 0 */ }; /* * these are assigned from a pool held in the context. * Both client and server mode uses them for http header analysis */ struct allocated_headers { struct lws *wsi; /* owner */ char *data; /* prepared by context init to point to dedicated storage */ /* * the randomly ordered fragments, indexed by frag_index and * lws_fragments->nfrag for continuation. */ struct lws_fragments frags[WSI_TOKEN_COUNT * 2]; time_t assigned; /* * for each recognized token, frag_index says which frag[] his data * starts in (0 means the token did not appear) * the actual header data gets dumped as it comes in, into data[] */ unsigned char frag_index[WSI_TOKEN_COUNT]; unsigned char rx[2048]; unsigned int rxpos; unsigned int rxlen; #ifndef LWS_NO_CLIENT char initial_handshake_hash_base64[30]; #endif unsigned short pos; unsigned char in_use; unsigned char nfrag; }; /* * so we can have n connections being serviced simultaneously, * these things need to be isolated per-thread. */ struct lws_context_per_thread { #if LWS_MAX_SMP > 1 pthread_mutex_t lock; #endif struct lws_pollfd *fds; struct lws *rx_draining_ext_list; struct lws *tx_draining_ext_list; struct lws *timeout_list; struct lws_context *context; #ifdef LWS_WITH_CGI struct lws_cgi *cgi_list; #endif void *http_header_data; struct allocated_headers *ah_pool; struct lws *ah_wait_list; int ah_wait_list_length; #ifdef LWS_OPENSSL_SUPPORT struct lws *pending_read_list; /* linked list */ #endif #ifndef LWS_NO_SERVER struct lws *wsi_listening; #endif #if defined(LWS_USE_LIBEV) struct ev_loop *io_loop_ev; #endif #if defined(LWS_USE_LIBUV) uv_loop_t *io_loop_uv; uv_signal_t signals[8]; uv_timer_t uv_timeout_watcher; uv_idle_t uv_idle; #endif #if defined(LWS_USE_LIBEV) struct lws_io_watcher w_accept; #endif #if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) struct lws_signal_watcher w_sigint; unsigned char ev_loop_foreign:1; #endif unsigned long count_conns; /* * usable by anything in the service code, but only if the scope * does not last longer than the service action (since next service * of any socket can likewise use it and overwrite) */ unsigned char *serv_buf; #ifdef _WIN32 WSAEVENT *events; #else int dummy_pipe_fds[2]; #endif unsigned int fds_count; short ah_count_in_use; unsigned char tid; }; /* * virtual host -related context information * vhostwide SSL context * vhostwide proxy * * heirarchy: * * context -> vhost -> wsi * * incoming connection non-SSL vhost binding: * * listen socket -> wsi -> select vhost after first headers * * incoming connection SSL vhost binding: * * SSL SNI -> wsi -> bind after SSL negotiation */ struct lws_vhost { char http_proxy_address[128]; char proxy_basic_auth_token[128]; struct lws_context *context; struct lws_vhost *vhost_next; const struct lws_http_mount *mount_list; struct lws *lserv_wsi; const char *name; const char *iface; const struct lws_protocols *protocols; void **protocol_vh_privs; const struct lws_protocol_vhost_options *pvo; struct lws **same_vh_protocol_list; #ifdef LWS_OPENSSL_SUPPORT SSL_CTX *ssl_ctx; SSL_CTX *ssl_client_ctx; #endif #ifndef LWS_NO_EXTENSIONS const struct lws_extension *extensions; #endif unsigned long long rx, tx; unsigned long conn, trans, ws_upgrades, http2_upgrades; int listen_port; unsigned int http_proxy_port; unsigned int options; int count_protocols; int ka_time; int ka_probes; int ka_interval; int keepalive_timeout; #ifdef LWS_WITH_ACCESS_LOG int log_fd; #endif #ifdef LWS_OPENSSL_SUPPORT int use_ssl; int allow_non_ssl_on_ssl_port; unsigned int user_supplied_ssl_ctx:1; #endif unsigned char default_protocol_index; }; /* * the rest is managed per-context, that includes * * - processwide single fd -> wsi lookup * - contextwide headers pool */ struct lws_context { time_t last_timeout_check_s; time_t time_up; struct lws_plat_file_ops fops; struct lws_context_per_thread pt[LWS_MAX_SMP]; #ifdef _WIN32 /* different implementation between unix and windows */ struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS]; #else struct lws **lws_lookup; /* fd to wsi */ #endif struct lws_vhost *vhost_list; struct lws_plugin *plugin_list; const struct lws_token_limits *token_limits; void *user_space; const char *server_string; #if defined(LWS_USE_LIBEV) lws_ev_signal_cb_t * lws_ev_sigint_cb; #endif #if defined(LWS_USE_LIBUV) uv_signal_cb lws_uv_sigint_cb; #endif char canonical_hostname[128]; #ifdef LWS_LATENCY unsigned long worst_latency; char worst_latency_info[256]; #endif int max_fds; #if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) int use_ev_sigint; #endif int started_with_parent; int uid, gid; int fd_random; #ifdef LWS_OPENSSL_SUPPORT #define lws_ssl_anybody_has_buffered_read(w) \ (w->vhost->use_ssl && \ w->context->pt[(int)w->tsi].pending_read_list) #define lws_ssl_anybody_has_buffered_read_tsi(c, t) \ (/*c->use_ssl && */ \ c->pt[(int)t].pending_read_list) #else #define lws_ssl_anybody_has_buffered_read(ctx) (0) #define lws_ssl_anybody_has_buffered_read_tsi(ctx, t) (0) #endif int count_wsi_allocated; int count_cgi_spawned; unsigned int options; unsigned int fd_limit_per_thread; unsigned int timeout_secs; /* * set to the Thread ID that's doing the service loop just before entry * to poll indicates service thread likely idling in poll() * volatile because other threads may check it as part of processing * for pollfd event change. */ volatile int service_tid; int service_tid_detected; short max_http_header_data; short max_http_header_pool; short count_threads; short plugin_protocol_count; short plugin_extension_count; short server_string_len; unsigned int being_destroyed:1; unsigned int requested_kill:1; unsigned int protocol_init_done:1; }; #define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x] #define lws_get_vh_protocol(vh, x) vh->protocols[x] LWS_EXTERN void lws_close_free_wsi_final(struct lws *wsi); LWS_EXTERN void lws_libuv_closehandle(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int lws_plat_plugins_init(struct lws_context * context, const char * const *d); LWS_VISIBLE LWS_EXTERN int lws_plat_plugins_destroy(struct lws_context * context); enum { LWS_EV_READ = (1 << 0), LWS_EV_WRITE = (1 << 1), LWS_EV_START = (1 << 2), LWS_EV_STOP = (1 << 3), LWS_EV_PREPARE_DELETION = (1 << 31), }; #if defined(LWS_USE_LIBEV) LWS_EXTERN void lws_libev_accept(struct lws *new_wsi, lws_sockfd_type accept_fd); LWS_EXTERN void lws_libev_io(struct lws *wsi, int flags); LWS_EXTERN int lws_libev_init_fd_table(struct lws_context *context); LWS_EXTERN void lws_libev_destroyloop(struct lws_context *context, int tsi); LWS_EXTERN void lws_libev_run(const struct lws_context *context, int tsi); #define LWS_LIBEV_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV) LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info); #else #define lws_libev_accept(_a, _b) ((void) 0) #define lws_libev_io(_a, _b) ((void) 0) #define lws_libev_init_fd_table(_a) (0) #define lws_libev_run(_a, _b) ((void) 0) #define lws_libev_destroyloop(_a, _b) ((void) 0) #define LWS_LIBEV_ENABLED(context) (0) #if LWS_POSIX #define lws_feature_status_libev(_a) \ lwsl_notice("libev support not compiled in\n") #else #define lws_feature_status_libev(_a) #endif #endif #if defined(LWS_USE_LIBUV) LWS_EXTERN void lws_libuv_accept(struct lws *new_wsi, lws_sockfd_type accept_fd); LWS_EXTERN void lws_libuv_io(struct lws *wsi, int flags); LWS_EXTERN int lws_libuv_init_fd_table(struct lws_context *context); LWS_EXTERN void lws_libuv_run(const struct lws_context *context, int tsi); LWS_EXTERN void lws_libuv_destroyloop(struct lws_context *context, int tsi); #define LWS_LIBUV_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV) LWS_EXTERN void lws_feature_status_libuv(struct lws_context_creation_info *info); #else #define lws_libuv_accept(_a, _b) ((void) 0) #define lws_libuv_io(_a, _b) ((void) 0) #define lws_libuv_init_fd_table(_a) (0) #define lws_libuv_run(_a, _b) ((void) 0) #define lws_libuv_destroyloop(_a, _b) ((void) 0) #define LWS_LIBUV_ENABLED(context) (0) #if LWS_POSIX #define lws_feature_status_libuv(_a) \ lwsl_notice("libuv support not compiled in\n") #else #define lws_feature_status_libuv(_a) #endif #endif #ifdef LWS_USE_IPV6 #define LWS_IPV6_ENABLED(context) \ (!lws_check_opt(context->options, LWS_SERVER_OPTION_DISABLE_IPV6)) #else #define LWS_IPV6_ENABLED(context) (0) #endif #ifdef LWS_USE_UNIX_SOCK #define LWS_UNIX_SOCK_ENABLED(vhost) \ (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK) #else #define LWS_UNIX_SOCK_ENABLED(vhost) (0) #endif enum uri_path_states { URIPS_IDLE, URIPS_SEEN_SLASH, URIPS_SEEN_SLASH_DOT, URIPS_SEEN_SLASH_DOT_DOT, }; enum uri_esc_states { URIES_IDLE, URIES_SEEN_PERCENT, URIES_SEEN_PERCENT_H1, }; /* notice that these union members: * * hdr * http * http2 * * all have a pointer to allocated_headers struct as their first member. * * It means for allocated_headers access, the three union paths can all be * used interchangeably to access the same data */ #ifndef LWS_NO_CLIENT struct client_info_stash { char address[256]; char path[1024]; char host[256]; char origin[256]; char protocol[256]; char method[16]; }; #endif struct _lws_header_related { /* MUST be first in struct */ struct allocated_headers *ah; struct lws *ah_wait_list; unsigned char *preamble_rx; #ifndef LWS_NO_CLIENT struct client_info_stash *stash; #endif unsigned int preamble_rx_len; enum uri_path_states ups; enum uri_esc_states ues; short lextable_pos; unsigned short current_token_limit; #ifndef LWS_NO_CLIENT unsigned short c_port; #endif char esc_stash; char post_literal_equal; unsigned char parser_state; /* enum lws_token_indexes */ char redirects; }; struct _lws_http_mode_related { /* MUST be first in struct */ struct allocated_headers *ah; /* mirroring _lws_header_related */ struct lws *ah_wait_list; unsigned char *preamble_rx; #ifndef LWS_NO_CLIENT struct client_info_stash *stash; #endif unsigned int preamble_rx_len; struct lws *new_wsi_list; unsigned long filepos; unsigned long filelen; lws_filefd_type fd; enum http_version request_version; enum http_connection_type connection_type; unsigned int content_length; unsigned int content_remain; }; #ifdef LWS_USE_HTTP2 enum lws_http2_settings { LWS_HTTP2_SETTINGS__HEADER_TABLE_SIZE = 1, LWS_HTTP2_SETTINGS__ENABLE_PUSH, LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS, LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE, LWS_HTTP2_SETTINGS__MAX_FRAME_SIZE, LWS_HTTP2_SETTINGS__MAX_HEADER_LIST_SIZE, LWS_HTTP2_SETTINGS__COUNT /* always last */ }; enum lws_http2_wellknown_frame_types { LWS_HTTP2_FRAME_TYPE_DATA, LWS_HTTP2_FRAME_TYPE_HEADERS, LWS_HTTP2_FRAME_TYPE_PRIORITY, LWS_HTTP2_FRAME_TYPE_RST_STREAM, LWS_HTTP2_FRAME_TYPE_SETTINGS, LWS_HTTP2_FRAME_TYPE_PUSH_PROMISE, LWS_HTTP2_FRAME_TYPE_PING, LWS_HTTP2_FRAME_TYPE_GOAWAY, LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE, LWS_HTTP2_FRAME_TYPE_CONTINUATION, LWS_HTTP2_FRAME_TYPE_COUNT /* always last */ }; enum lws_http2_flags { LWS_HTTP2_FLAG_END_STREAM = 1, LWS_HTTP2_FLAG_END_HEADERS = 4, LWS_HTTP2_FLAG_PADDED = 8, LWS_HTTP2_FLAG_PRIORITY = 0x20, LWS_HTTP2_FLAG_SETTINGS_ACK = 1, }; #define LWS_HTTP2_STREAM_ID_MASTER 0 #define LWS_HTTP2_FRAME_HEADER_LENGTH 9 #define LWS_HTTP2_SETTINGS_LENGTH 6 struct http2_settings { unsigned int setting[LWS_HTTP2_SETTINGS__COUNT]; }; enum http2_hpack_state { /* optional before first header block */ HPKS_OPT_PADDING, HKPS_OPT_E_DEPENDENCY, HKPS_OPT_WEIGHT, /* header block */ HPKS_TYPE, HPKS_IDX_EXT, HPKS_HLEN, HPKS_HLEN_EXT, HPKS_DATA, /* optional after last header block */ HKPS_OPT_DISCARD_PADDING, }; enum http2_hpack_type { HPKT_INDEXED_HDR_7, HPKT_INDEXED_HDR_6_VALUE_INCR, HPKT_LITERAL_HDR_VALUE_INCR, HPKT_INDEXED_HDR_4_VALUE, HPKT_LITERAL_HDR_VALUE, HPKT_SIZE_5 }; struct hpack_dt_entry { int token; /* additions that don't map to a token are ignored */ int arg_offset; int arg_len; }; struct hpack_dynamic_table { struct hpack_dt_entry *entries; char *args; int pos; int next; int num_entries; int args_length; }; struct _lws_http2_related { /* * having this first lets us also re-use all HTTP union code * and in turn, http_mode_related has allocated headers in right * place so we can use the header apis on the wsi directly still */ struct _lws_http_mode_related http; /* MUST BE FIRST IN STRUCT */ struct http2_settings my_settings; struct http2_settings peer_settings; struct lws *parent_wsi; struct lws *next_child_wsi; struct hpack_dynamic_table *hpack_dyn_table; struct lws *stream_wsi; unsigned char ping_payload[8]; unsigned char one_setting[LWS_HTTP2_SETTINGS_LENGTH]; unsigned int count; unsigned int length; unsigned int stream_id; enum http2_hpack_state hpack; enum http2_hpack_type hpack_type; unsigned int header_index; unsigned int hpack_len; unsigned int hpack_e_dep; int tx_credit; unsigned int my_stream_id; unsigned int child_count; int my_priority; unsigned int END_STREAM:1; unsigned int END_HEADERS:1; unsigned int send_END_STREAM:1; unsigned int GOING_AWAY; unsigned int requested_POLLOUT:1; unsigned int waiting_tx_credit:1; unsigned int huff:1; unsigned int value:1; unsigned short round_robin_POLLOUT; unsigned short count_POLLOUT_children; unsigned short hpack_pos; unsigned char type; unsigned char flags; unsigned char frame_state; unsigned char padding; unsigned char hpack_m; unsigned char initialized; }; #define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->u.http2.parent_wsi) #endif struct _lws_websocket_related { /* cheapest way to deal with ah overlap with ws union transition */ struct _lws_header_related hdr; char *rx_ubuf; unsigned int rx_ubuf_alloc; struct lws *rx_draining_ext_list; struct lws *tx_draining_ext_list; size_t rx_packet_length; unsigned int rx_ubuf_head; unsigned char mask[4]; /* Also used for close content... control opcode == < 128 */ unsigned char ping_payload_buf[128 - 3 + LWS_PRE]; unsigned char ping_payload_len; unsigned char mask_idx; unsigned char opcode; unsigned char rsv; unsigned char rsv_first_msg; /* zero if no info, or length including 2-byte close code */ unsigned char close_in_ping_buffer_len; unsigned char utf8; unsigned char stashed_write_type; unsigned char tx_draining_stashed_wp; unsigned int final:1; unsigned int frame_is_binary:1; unsigned int all_zero_nonce:1; unsigned int this_frame_masked:1; unsigned int inside_frame:1; /* next write will be more of frame */ unsigned int clean_buffer:1; /* buffer not rewritten by extension */ unsigned int payload_is_close:1; /* process as PONG, but it is close */ unsigned int ping_pending_flag:1; unsigned int continuation_possible:1; unsigned int owed_a_fin:1; unsigned int check_utf8:1; unsigned int defeat_check_utf8:1; unsigned int pmce_compressed_message:1; unsigned int stashed_write_pending:1; unsigned int rx_draining_ext:1; unsigned int tx_draining_ext:1; }; #ifdef LWS_WITH_CGI /* wsi who is master of the cgi points to an lws_cgi */ struct lws_cgi { struct lws_cgi *cgi_list; struct lws *stdwsi[3]; /* points to the associated stdin/out/err wsis */ struct lws *wsi; /* owner */ unsigned long content_length; unsigned long content_length_seen; int pipe_fds[3][2]; int pid; unsigned int being_closed:1; }; #endif signed char char_to_hex(const char c); #ifndef LWS_NO_CLIENT enum lws_chunk_parser { ELCP_HEX, ELCP_CR, ELCP_CONTENT, ELCP_POST_CR, ELCP_POST_LF, }; #endif struct lws_rewrite; #ifdef LWS_WITH_ACCESS_LOG struct lws_access_log { char *header_log; char *user_agent; unsigned long sent; int response; }; #endif struct lws { /* structs */ /* members with mutually exclusive lifetimes are unionized */ union u { struct _lws_http_mode_related http; #ifdef LWS_USE_HTTP2 struct _lws_http2_related http2; #endif struct _lws_header_related hdr; struct _lws_websocket_related ws; } u; /* lifetime members */ #if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) struct lws_io_watcher w_read; #endif #if defined(LWS_USE_LIBEV) struct lws_io_watcher w_write; #endif time_t pending_timeout_limit; /* pointers */ struct lws_context *context; struct lws_vhost *vhost; struct lws *parent; /* points to parent, if any */ struct lws *child_list; /* points to first child */ struct lws *sibling_list; /* subsequent children at same level */ #ifdef LWS_WITH_CGI struct lws_cgi *cgi; /* wsi being cgi master have one of these */ #endif const struct lws_protocols *protocol; struct lws **same_vh_protocol_prev, *same_vh_protocol_next; struct lws *timeout_list; struct lws **timeout_list_prev; #ifdef LWS_WITH_ACCESS_LOG struct lws_access_log access_log; #endif void *user_space; /* rxflow handling */ unsigned char *rxflow_buffer; /* truncated send handling */ unsigned char *trunc_alloc; /* non-NULL means buffering in progress */ #ifndef LWS_NO_EXTENSIONS const struct lws_extension *active_extensions[LWS_MAX_EXTENSIONS_ACTIVE]; void *act_ext_user[LWS_MAX_EXTENSIONS_ACTIVE]; #endif #ifdef LWS_OPENSSL_SUPPORT SSL *ssl; #if !defined(LWS_USE_POLARSSL) && !defined(LWS_USE_MBEDTLS) BIO *client_bio; #endif struct lws *pending_read_list_prev, *pending_read_list_next; #endif #ifdef LWS_WITH_HTTP_PROXY struct lws_rewrite *rw; #endif #ifdef LWS_LATENCY unsigned long action_start; unsigned long latency_start; #endif /* pointer / int */ lws_sockfd_type sock; /* ints */ int position_in_fds_table; int rxflow_len; int rxflow_pos; unsigned int trunc_alloc_len; /* size of malloc */ unsigned int trunc_offset; /* where we are in terms of spilling */ unsigned int trunc_len; /* how much is buffered */ #ifndef LWS_NO_CLIENT int chunk_remaining; #endif unsigned int cache_secs; unsigned int hdr_parsing_completed:1; unsigned int http2_substream:1; unsigned int listener:1; unsigned int user_space_externally_allocated:1; unsigned int socket_is_permanently_unusable:1; unsigned int rxflow_change_to:2; unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */ unsigned int conn_stat_done:1; unsigned int cache_reuse:1; unsigned int cache_revalidate:1; unsigned int cache_intermediaries:1; unsigned int favoured_pollin:1; #ifdef LWS_WITH_ACCESS_LOG unsigned int access_log_pending:1; #endif #ifndef LWS_NO_CLIENT unsigned int do_ws:1; /* whether we are doing http or ws flow */ unsigned int chunked:1; /* if the clientside connection is chunked */ unsigned int client_rx_avail:1; #endif #ifdef LWS_WITH_HTTP_PROXY unsigned int perform_rewrite:1; #endif #ifndef LWS_NO_EXTENSIONS unsigned int extension_data_pending:1; #endif #ifdef LWS_OPENSSL_SUPPORT unsigned int use_ssl:2; unsigned int upgraded:1; #endif #ifdef _WIN32 unsigned int sock_send_blocking:1; #endif #ifdef LWS_OPENSSL_SUPPORT unsigned int redirect_to_https:1; #endif /* chars */ #ifndef LWS_NO_EXTENSIONS unsigned char count_act_ext; #endif unsigned char ietf_spec_revision; char mode; /* enum connection_mode */ char state; /* enum lws_connection_states */ char state_pre_close; char lws_rx_parse_state; /* enum lws_rx_parse_state */ char rx_frame_type; /* enum lws_write_protocol */ char pending_timeout; /* enum pending_timeout */ char pps; /* enum lws_pending_protocol_send */ char tsi; /* thread service index we belong to */ #ifdef LWS_WITH_CGI char cgi_channel; /* which of stdin/out/err */ char hdr_state; #endif #ifndef LWS_NO_CLIENT char chunk_parser; /* enum lws_chunk_parser */ #endif }; LWS_EXTERN int log_level; LWS_EXTERN int lws_socket_bind(struct lws_vhost *vhost, int sockfd, int port, const char *iface); LWS_EXTERN void lws_close_free_wsi(struct lws *wsi, enum lws_close_status); LWS_EXTERN int remove_wsi_socket_from_fds(struct lws *wsi); LWS_EXTERN int lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len); #ifndef LWS_LATENCY static inline void lws_latency(struct lws_context *context, struct lws *wsi, const char *action, int ret, int completion) { do { (void)context; (void)wsi; (void)action; (void)ret; (void)completion; } while (0); } static inline void lws_latency_pre(struct lws_context *context, struct lws *wsi) { do { (void)context; (void)wsi; } while (0); } #else #define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0) extern void lws_latency(struct lws_context *context, struct lws *wsi, const char *action, int ret, int completion); #endif LWS_EXTERN void lws_set_protocol_write_pending(struct lws *wsi, enum lws_pending_protocol_send pend); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_client_rx_sm(struct lws *wsi, unsigned char c); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_parse(struct lws *wsi, unsigned char c); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_http_action(struct lws *wsi); LWS_EXTERN int lws_b64_selftest(void); LWS_EXTERN int lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi); LWS_EXTERN int lws_service_flag_pending(struct lws_context *context, int tsi); #if defined(_WIN32) || defined(MBED_OPERATORS) LWS_EXTERN struct lws * wsi_from_fd(const struct lws_context *context, lws_sockfd_type fd); LWS_EXTERN int insert_wsi(struct lws_context *context, struct lws *wsi); LWS_EXTERN int delete_from_fd(struct lws_context *context, lws_sockfd_type fd); #else #define wsi_from_fd(A,B) A->lws_lookup[B] #define insert_wsi(A,B) assert(A->lws_lookup[B->sock] == 0); A->lws_lookup[B->sock]=B #define delete_from_fd(A,B) A->lws_lookup[B]=0 #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_service_timeout_check(struct lws *wsi, unsigned int sec); LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_client_connect_2(struct lws *wsi); LWS_VISIBLE struct lws * LWS_WARN_UNUSED_RESULT lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host); LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_create_new_server_wsi(struct lws_vhost *vhost); LWS_EXTERN char * LWS_WARN_UNUSED_RESULT lws_generate_client_handshake(struct lws *wsi, char *pkt); LWS_EXTERN int lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd); LWS_EXTERN struct lws * lws_client_connect_via_info2(struct lws *wsi); /* * EXTENSIONS */ #ifndef LWS_NO_EXTENSIONS LWS_VISIBLE void lws_context_init_extensions(struct lws_context_creation_info *info, struct lws_context *context); LWS_EXTERN int lws_any_extension_handled(struct lws *wsi, enum lws_extension_callback_reasons r, void *v, size_t len); LWS_EXTERN int lws_ext_cb_active(struct lws *wsi, int reason, void *buf, int len); LWS_EXTERN int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi, int reason, void *arg, int len); #else #define lws_any_extension_handled(_a, _b, _c, _d) (0) #define lws_ext_cb_active(_a, _b, _c, _d) (0) #define lws_ext_cb_all_exts(_a, _b, _c, _d, _e) (0) #define lws_issue_raw_ext_access lws_issue_raw #define lws_context_init_extensions(_a, _b) #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_client_interpret_server_handshake(struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_rx_sm(struct lws *wsi, unsigned char c); LWS_EXTERN int lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf, size_t *len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len); LWS_EXTERN void lws_union_transition(struct lws *wsi, enum connection_mode mode); LWS_EXTERN int LWS_WARN_UNUSED_RESULT user_callback_handle_rxflow(lws_callback_function, struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); #ifdef LWS_USE_HTTP2 LWS_EXTERN struct lws *lws_http2_get_network_wsi(struct lws *wsi); struct lws * lws_http2_get_nth_child(struct lws *wsi, int n); LWS_EXTERN int lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len); LWS_EXTERN void lws_http2_init(struct http2_settings *settings); LWS_EXTERN int lws_http2_parser(struct lws *wsi, unsigned char c); LWS_EXTERN int lws_http2_do_pps_send(struct lws_context *context, struct lws *wsi); LWS_EXTERN int lws_http2_frame_write(struct lws *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf); LWS_EXTERN struct lws * lws_http2_wsi_from_id(struct lws *wsi, unsigned int sid); LWS_EXTERN int lws_hpack_interpret(struct lws *wsi, unsigned char c); LWS_EXTERN int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name, const unsigned char *value, int length, unsigned char **p, unsigned char *end); LWS_EXTERN int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token, const unsigned char *value, int length, unsigned char **p, unsigned char *end); LWS_EXTERN int lws_add_http2_header_status(struct lws *wsi, unsigned int code, unsigned char **p, unsigned char *end); LWS_EXTERN void lws_http2_configure_if_upgraded(struct lws *wsi); #else #define lws_http2_configure_if_upgraded(x) #endif LWS_EXTERN int lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_header_table_attach(struct lws *wsi, int autoservice); LWS_EXTERN int lws_header_table_detach(struct lws *wsi, int autoservice); LWS_EXTERN void lws_header_table_reset(struct lws *wsi, int autoservice); LWS_EXTERN char * LWS_WARN_UNUSED_RESULT lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ensure_user_space(struct lws *wsi); LWS_EXTERN int lws_change_pollfd(struct lws *wsi, int _and, int _or); #ifndef LWS_NO_SERVER int lws_context_init_server(struct lws_context_creation_info *info, struct lws_vhost *vhost); LWS_EXTERN struct lws_vhost * lws_select_vhost(struct lws_context *context, int port, const char *servername); LWS_EXTERN int handshake_0405(struct lws_context *context, struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len); LWS_EXTERN void lws_server_get_canonical_hostname(struct lws_context *context, struct lws_context_creation_info *info); #else #define lws_context_init_server(_a, _b) (0) #define lws_interpret_incoming_packet(_a, _b, _c) (0) #define lws_server_get_canonical_hostname(_a, _b) #endif #ifndef LWS_NO_DAEMONIZE LWS_EXTERN int get_daemonize_pid(); #else #define get_daemonize_pid() (0) #endif #if !defined(MBED_OPERATORS) LWS_EXTERN int LWS_WARN_UNUSED_RESULT interface_to_sa(struct lws_context *context, const char *ifname, struct sockaddr_in *addr, size_t addrlen); #endif LWS_EXTERN void lwsl_emit_stderr(int level, const char *line); enum lws_ssl_capable_status { LWS_SSL_CAPABLE_ERROR = -1, LWS_SSL_CAPABLE_MORE_SERVICE = -2, }; #ifndef LWS_OPENSSL_SUPPORT #define LWS_SSL_ENABLED(context) (0) #define lws_context_init_server_ssl(_a, _b) (0) #define lws_ssl_destroy(_a) #define lws_context_init_http2_ssl(_a) #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl #define lws_ssl_pending lws_ssl_pending_no_ssl #define lws_server_socket_service_ssl(_b, _c) (0) #define lws_ssl_close(_a) (0) #define lws_ssl_context_destroy(_a) #define lws_ssl_SSL_CTX_destroy(_a) #define lws_ssl_remove_wsi_from_buffered_list(_a) #define lws_context_init_ssl_library(_a) #else #define LWS_SSL_ENABLED(context) (context->use_ssl) LWS_EXTERN int openssl_websocket_private_data_index; LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_pending(struct lws *wsi); LWS_EXTERN int lws_context_init_ssl_library(struct lws_context_creation_info *info); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd); LWS_EXTERN int lws_ssl_close(struct lws *wsi); LWS_EXTERN void lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost); LWS_EXTERN void lws_ssl_context_destroy(struct lws_context *context); LWS_VISIBLE void lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi); LWS_EXTERN int lws_ssl_client_bio_create(struct lws *wsi); LWS_EXTERN int lws_ssl_client_connect1(struct lws *wsi); LWS_EXTERN int lws_ssl_client_connect2(struct lws *wsi); LWS_EXTERN void lws_ssl_elaborate_error(void); #ifndef LWS_NO_SERVER LWS_EXTERN int lws_context_init_server_ssl(struct lws_context_creation_info *info, struct lws_vhost *vhost); #else #define lws_context_init_server_ssl(_a, _b) (0) #endif LWS_EXTERN void lws_ssl_destroy(struct lws_vhost *vhost); /* HTTP2-related */ #ifdef LWS_USE_HTTP2 LWS_EXTERN void lws_context_init_http2_ssl(struct lws_vhost *vhost); #else #define lws_context_init_http2_ssl(_a) #endif #endif #if LWS_MAX_SMP > 1 static LWS_INLINE void lws_pt_mutex_init(struct lws_context_per_thread *pt) { pthread_mutex_init(&pt->lock, NULL); } static LWS_INLINE void lws_pt_mutex_destroy(struct lws_context_per_thread *pt) { pthread_mutex_destroy(&pt->lock); } static LWS_INLINE void lws_pt_lock(struct lws_context_per_thread *pt) { pthread_mutex_lock(&pt->lock); } static LWS_INLINE void lws_pt_unlock(struct lws_context_per_thread *pt) { pthread_mutex_unlock(&pt->lock); } #else #define lws_pt_mutex_init(_a) (void)(_a) #define lws_pt_mutex_destroy(_a) (void)(_a) #define lws_pt_lock(_a) (void)(_a) #define lws_pt_unlock(_a) (void)(_a) #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_pending_no_ssl(struct lws *wsi); #ifdef LWS_WITH_HTTP_PROXY struct lws_rewrite { hubbub_parser *parser; hubbub_parser_optparams params; const char *from, *to; int from_len, to_len; unsigned char *p, *end; struct lws *wsi; }; static LWS_INLINE int hstrcmp(hubbub_string *s, const char *p, int len) { if (s->len != len) return 1; return strncmp((const char *)s->ptr, p, len); } typedef hubbub_error (*hubbub_callback_t)(const hubbub_token *token, void *pw); LWS_EXTERN struct lws_rewrite * lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to); LWS_EXTERN void lws_rewrite_destroy(struct lws_rewrite *r); LWS_EXTERN int lws_rewrite_parse(struct lws_rewrite *r, const unsigned char *in, int in_len); #endif #ifndef LWS_NO_CLIENT LWS_EXTERN int lws_client_socket_service(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pollfd); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_http_transaction_completed_client(struct lws *wsi); #ifdef LWS_OPENSSL_SUPPORT LWS_EXTERN int lws_context_init_client_ssl(struct lws_context_creation_info *info, struct lws_vhost *vhost); #else #define lws_context_init_client_ssl(_a, _b) (0) #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len); LWS_EXTERN void lws_decode_ssl_error(void); #else #define lws_context_init_client_ssl(_a, _b) (0) #define lws_handshake_client(_a, _b, _c) (0) #endif LWS_EXTERN int _lws_rx_flow_control(struct lws *wsi); LWS_EXTERN int _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa); #ifndef LWS_NO_SERVER LWS_EXTERN int lws_server_socket_service(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pollfd); LWS_EXTERN int lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len); LWS_EXTERN int _lws_server_listen_accept_flow_control(struct lws *twsi, int on); #else #define lws_server_socket_service(_a, _b, _c) (0) #define lws_handshake_server(_a, _b, _c) (0) #define _lws_server_listen_accept_flow_control(a, b) (0) #endif LWS_EXTERN int lws_get_addresses(struct lws_context *context, void *ads, char *name, int name_len, char *rip, int rip_len); LWS_EXTERN const char * lws_get_peer_simple(struct lws *wsi, char *name, int namelen); #ifdef LWS_WITH_ACCESS_LOG LWS_EXTERN int lws_access_log(struct lws *wsi); #else #define lws_access_log(_a) #endif LWS_EXTERN int lws_cgi_kill_terminated(struct lws_context_per_thread *pt); int lws_protocol_init(struct lws_context *context); /* * custom allocator */ LWS_EXTERN void * lws_realloc(void *ptr, size_t size); LWS_EXTERN void * LWS_WARN_UNUSED_RESULT lws_zalloc(size_t size); #define lws_malloc(S) lws_realloc(NULL, S) #define lws_free(P) lws_realloc(P, 0) #define lws_free_set_NULL(P) do { lws_realloc(P, 0); (P) = NULL; } while(0) /* lws_plat_ */ LWS_EXTERN void lws_plat_delete_socket_from_fds(struct lws_context *context, struct lws *wsi, int m); LWS_EXTERN void lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi); LWS_EXTERN void lws_plat_service_periodic(struct lws_context *context); LWS_EXTERN int lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pfd); LWS_EXTERN int lws_plat_context_early_init(void); LWS_EXTERN void lws_plat_context_early_destroy(struct lws_context *context); LWS_EXTERN void lws_plat_context_late_destroy(struct lws_context *context); LWS_EXTERN int lws_poll_listen_fd(struct lws_pollfd *fd); LWS_EXTERN int lws_plat_service(struct lws_context *context, int timeout_ms); LWS_EXTERN LWS_VISIBLE int lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi); LWS_EXTERN int lws_plat_init(struct lws_context *context, struct lws_context_creation_info *info); LWS_EXTERN void lws_plat_drop_app_privileges(struct lws_context_creation_info *info); LWS_EXTERN unsigned long long time_in_microseconds(void); LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len); #ifdef __cplusplus }; #endif |
Added undroid/libwebsockets/lib/rewrite.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "private-libwebsockets.h" LWS_EXTERN struct lws_rewrite * lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to) { struct lws_rewrite *r = lws_malloc(sizeof(*r)); if (!r) { lwsl_err("OOM\n"); return NULL; } if (hubbub_parser_create("UTF-8", false, &r->parser) != HUBBUB_OK) { lws_free(r); return NULL; } r->from = from; r->from_len = strlen(from); r->to = to; r->to_len = strlen(to); r->params.token_handler.handler = cb; r->wsi = wsi; r->params.token_handler.pw = (void *)r; if (hubbub_parser_setopt(r->parser, HUBBUB_PARSER_TOKEN_HANDLER, &r->params) != HUBBUB_OK) { lws_free(r); return NULL; } return r; } LWS_EXTERN int lws_rewrite_parse(struct lws_rewrite *r, const unsigned char *in, int in_len) { if (hubbub_parser_parse_chunk(r->parser, in, in_len) != HUBBUB_OK) return -1; return 0; } LWS_EXTERN void lws_rewrite_destroy(struct lws_rewrite *r) { hubbub_parser_destroy(r->parser); lws_free(r); } |
Added undroid/libwebsockets/lib/server-handshake.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); } #ifndef LWS_NO_EXTENSIONS LWS_VISIBLE int lws_extension_server_handshake(struct lws *wsi, char **p) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; const struct lws_extension *ext; char ext_name[128]; int ext_count = 0; int more = 1; char ignore; int n, m; char *c; /* * Figure out which extensions the client has that we want to * enable on this connection, and give him back the list */ if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) return 0; /* * break down the list of client extensions * and go through them */ if (lws_hdr_copy(wsi, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF, WSI_TOKEN_EXTENSIONS) < 0) return 1; c = (char *)pt->serv_buf; lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c); wsi->count_act_ext = 0; n = 0; ignore = 0; while (more) { if (*c && (*c != ',' && *c != '\t')) { if (*c == ';') ignore = 1; if (ignore || *c == ' ') { c++; continue; } ext_name[n] = *c++; if (n < sizeof(ext_name) - 1) n++; continue; } ext_name[n] = '\0'; ignore = 0; if (!*c) more = 0; else { c++; if (!n) continue; } /* check a client's extension against our support */ ext = wsi->vhost->extensions; while (ext && ext->callback) { if (strcmp(ext_name, ext->name)) { ext++; continue; } #if 0 m = ext->callback(lws_get_context(wsi), ext, wsi, LWS_EXT_CB_ARGS_VALIDATE, NULL, start + n, 0); if (m) { ext++; continue; } #endif /* * oh, we do support this one he asked for... but let's * ask user code if it's OK to apply it on this * particular connection + protocol */ m = wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, wsi->user_space, ext_name, 0); /* * zero return from callback means go ahead and allow * the extension, it's what we get if the callback is * unhandled */ if (m) { ext++; continue; } /* apply it */ ext_count++; /* instantiate the extension on this conn */ wsi->active_extensions[wsi->count_act_ext] = ext; /* allow him to construct his context */ if (ext->callback(lws_get_context(wsi), ext, wsi, LWS_EXT_CB_CONSTRUCT, (void *)&wsi->act_ext_user[wsi->count_act_ext], NULL, 0)) { lwsl_notice("ext %s failed construction\n", ext_name); ext_count--; ext++; continue; } if (ext_count > 1) *(*p)++ = ','; else LWS_CPYAPP(*p, "\x0d\x0aSec-WebSocket-Extensions: "); *p += sprintf(*p, "%s", ext_name); wsi->count_act_ext++; lwsl_parser("count_act_ext <- %d\n", wsi->count_act_ext); ext++; } n = 0; } return 0; } #endif int handshake_0405(struct lws_context *context, struct lws *wsi) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; unsigned char hash[20]; int n, accept_len; char *response; char *p; if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) || !lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) { lwsl_parser("handshake_04 missing pieces\n"); /* completed header processing, but missing some bits */ goto bail; } if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >= MAX_WEBSOCKET_04_KEY_LEN) { lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN); goto bail; } /* * since key length is restricted above (currently 128), cannot * overflow */ n = sprintf((char *)pt->serv_buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY)); lws_SHA1(pt->serv_buf, n, hash); accept_len = lws_b64_encode_string((char *)hash, 20, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF); if (accept_len < 0) { lwsl_warn("Base64 encoded hash too long\n"); goto bail; } /* allocate the per-connection user memory (if any) */ if (lws_ensure_user_space(wsi)) goto bail; /* create the response packet */ /* make a buffer big enough for everything */ response = (char *)pt->serv_buf + MAX_WEBSOCKET_04_KEY_LEN + LWS_PRE; p = response; LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a" "Upgrade: WebSocket\x0d\x0a" "Connection: Upgrade\x0d\x0a" "Sec-WebSocket-Accept: "); strcpy(p, (char *)pt->serv_buf); p += accept_len; if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) { LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: "); n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL); if (n < 0) goto bail; p += n; } #ifndef LWS_NO_EXTENSIONS /* * Figure out which extensions the client has that we want to * enable on this connection, and give him back the list */ if (lws_extension_server_handshake(wsi, &p)) goto bail; #endif //LWS_CPYAPP(p, "\x0d\x0a""An-unknown-header: blah"); /* end of response packet */ LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); if (!lws_any_extension_handled(wsi, LWS_EXT_CB_HANDSHAKE_REPLY_TX, response, p - response)) { /* okay send the handshake response accepting the connection */ lwsl_parser("issuing resp pkt %d len\n", (int)(p - response)); #ifdef DEBUG fwrite(response, 1, p - response, stderr); #endif n = lws_write(wsi, (unsigned char *)response, p - response, LWS_WRITE_HTTP_HEADERS); if (n != (p - response)) { lwsl_debug("handshake_0405: ERROR writing to socket\n"); goto bail; } } /* alright clean up and set ourselves into established state */ wsi->state = LWSS_ESTABLISHED; wsi->lws_rx_parse_state = LWS_RXPS_NEW; /* notify user code that we're ready to roll */ if (wsi->protocol->callback) if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED, wsi->user_space, #ifdef LWS_OPENSSL_SUPPORT wsi->ssl, #else NULL, #endif 0)) goto bail; return 0; bail: /* caller will free up his parsing allocations */ return -1; } |
Added undroid/libwebsockets/lib/server.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" int lws_context_init_server(struct lws_context_creation_info *info, struct lws_vhost *vhost) { #ifdef LWS_POSIX int n, opt = 1, limit = 1; #endif lws_sockfd_type sockfd; struct lws_vhost *vh; struct lws *wsi; int m = 0; /* set up our external listening socket we serve on */ if (info->port == CONTEXT_PORT_NO_LISTEN) return 0; vh = vhost->context->vhost_list; while (vh) { if (vh->listen_port == info->port) { if ((!info->iface && !vh->iface) || (info->iface && vh->iface && !strcmp(info->iface, vh->iface))) { vhost->listen_port = info->port; vhost->iface = info->iface; lwsl_notice(" using listen skt from vhost %s\n", vh->name); return 0; } } vh = vh->vhost_next; } #if LWS_POSIX #if defined(__linux__) limit = vhost->context->count_threads; #endif for (m = 0; m < limit; m++) { #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(vhost)) sockfd = socket(AF_UNIX, SOCK_STREAM, 0); else #endif #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(vhost->context)) sockfd = socket(AF_INET6, SOCK_STREAM, 0); else #endif sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { #else sockfd = mbed3_create_tcp_stream_socket(); if (!lws_sockfd_valid(sockfd)) { #endif lwsl_err("ERROR opening socket\n"); return 1; } #if LWS_POSIX /* * allow us to restart even if old sockets in TIME_WAIT */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) < 0) { compatible_close(sockfd); return 1; } #if defined(__linux__) && defined(SO_REUSEPORT) && LWS_MAX_SMP > 1 if (vhost->context->count_threads > 1) if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const void *)&opt, sizeof(opt)) < 0) { compatible_close(sockfd); return 1; } #endif #endif lws_plat_set_socket_options(vhost, sockfd); #if LWS_POSIX n = lws_socket_bind(vhost, sockfd, info->port, info->iface); if (n < 0) goto bail; info->port = n; #endif vhost->listen_port = info->port; vhost->iface = info->iface; wsi = lws_zalloc(sizeof(struct lws)); if (wsi == NULL) { lwsl_err("Out of mem\n"); goto bail; } wsi->context = vhost->context; wsi->sock = sockfd; wsi->mode = LWSCM_SERVER_LISTENER; wsi->protocol = vhost->protocols; wsi->tsi = m; wsi->vhost = vhost; wsi->listener = 1; vhost->context->pt[m].wsi_listening = wsi; if (insert_wsi_socket_into_fds(vhost->context, wsi)) goto bail; vhost->context->count_wsi_allocated++; vhost->lserv_wsi = wsi; #if LWS_POSIX listen(wsi->sock, LWS_SOMAXCONN); } /* for each thread able to independently listen */ #else mbed3_tcp_stream_bind(wsi->sock, info->port, wsi); #endif if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) { #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(vhost)) lwsl_notice(" Listening on \"%s\"\n", info->iface); else #endif lwsl_notice(" Listening on port %d\n", info->port); } return 0; bail: compatible_close(sockfd); return 1; } int _lws_server_listen_accept_flow_control(struct lws *twsi, int on) { struct lws_context_per_thread *pt = &twsi->context->pt[(int)twsi->tsi]; struct lws *wsi = pt->wsi_listening; int n; if (!wsi || twsi->context->being_destroyed) return 0; lwsl_debug("%s: Thr %d: LISTEN wsi %p: state %d\n", __func__, twsi->tsi, (void *)wsi, on); if (on) n = lws_change_pollfd(wsi, 0, LWS_POLLIN); else n = lws_change_pollfd(wsi, LWS_POLLIN, 0); return n; } struct lws_vhost * lws_select_vhost(struct lws_context *context, int port, const char *servername) { struct lws_vhost *vhost = context->vhost_list; const char *p; int n, m, colon; n = strlen(servername); colon = n; p = strchr(servername, ':'); if (p) colon = p - servername; /* first try exact matches */ while (vhost) { if (port == vhost->listen_port && !strncmp(vhost->name, servername, colon)) { lwsl_info("SNI: Found: %s\n", servername); return vhost; } vhost = vhost->vhost_next; } /* * if no exact matches, try matching *.vhost-name * unintentional matches are possible but resolve to x.com for *.x.com * which is reasonable. If exact match exists we already chose it and * never reach here. SSL will still fail it if the cert doesn't allow * *.x.com. */ vhost = context->vhost_list; while (vhost) { m = strlen(vhost->name); if (port == vhost->listen_port && m <= (colon - 2) && servername[colon - m - 1] == '.' && !strncmp(vhost->name, servername + colon - m, m)) { lwsl_info("SNI: Found %s on wildcard: %s\n", servername, vhost->name); return vhost; } vhost = vhost->vhost_next; } return NULL; } static const char * get_mimetype(const char *file, const struct lws_http_mount *m) { int n = strlen(file); const struct lws_protocol_vhost_options *pvo = NULL; if (m) pvo = m->extra_mimetypes; if (n < 5) return NULL; if (!strcmp(&file[n - 4], ".ico")) return "image/x-icon"; if (!strcmp(&file[n - 4], ".gif")) return "image/gif"; if (!strcmp(&file[n - 3], ".js")) return "text/javascript"; if (!strcmp(&file[n - 4], ".png")) return "image/png"; if (!strcmp(&file[n - 4], ".jpg")) return "image/jpeg"; if (!strcmp(&file[n - 3], ".gz")) return "application/gzip"; if (!strcmp(&file[n - 4], ".JPG")) return "image/jpeg"; if (!strcmp(&file[n - 5], ".html")) return "text/html"; if (!strcmp(&file[n - 4], ".css")) return "text/css"; if (!strcmp(&file[n - 4], ".txt")) return "text/plain"; if (!strcmp(&file[n - 4], ".ttf")) return "application/x-font-ttf"; if (!strcmp(&file[n - 5], ".woff")) return "application/font-woff"; if (!strcmp(&file[n - 4], ".xml")) return "application/xml"; while (pvo) { if (!strcmp(&file[n - strlen(pvo->name)], pvo->name)) return pvo->value; pvo = pvo->next; } return NULL; } static int lws_http_serve(struct lws *wsi, char *uri, const char *origin, const struct lws_http_mount *m) { const char *mimetype; #ifndef _WIN32_WCE struct stat st; #endif char path[256], sym[256]; unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p; unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE; #if !defined(WIN32) size_t len; #endif int n, spin = 0; lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri); #ifndef _WIN32_WCE do { spin++; if (stat(path, &st)) { lwsl_info("unable to stat %s\n", path); goto bail; } lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode); #if !defined(WIN32) if ((S_IFMT & st.st_mode) == S_IFLNK) { len = readlink(path, sym, sizeof(sym) - 1); if (len) { lwsl_err("Failed to read link %s\n", path); goto bail; } sym[len] = '\0'; lwsl_debug("symlink %s -> %s\n", path, sym); lws_snprintf(path, sizeof(path) - 1, "%s", sym); } #endif if ((S_IFMT & st.st_mode) == S_IFDIR) { lwsl_debug("default filename append to dir\n"); lws_snprintf(path, sizeof(path) - 1, "%s/%s/index.html", origin, uri); } } while ((S_IFMT & st.st_mode) != S_IFREG && spin < 5); if (spin == 5) lwsl_err("symlink loop %s \n", path); n = sprintf(sym, "%08lX%08lX", (unsigned long)st.st_size, (unsigned long)st.st_mtime); if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH)) { /* * he thinks he has some version of it already, * check if the tag matches */ if (!strcmp(sym, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_IF_NONE_MATCH))) { lwsl_debug("%s: ETAG match %s %s\n", __func__, uri, origin); /* we don't need to send the payload */ if (lws_add_http_header_status(wsi, 304, &p, end)) return -1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG, (unsigned char *)sym, n, &p, end)) return -1; if (lws_finalize_http_header(wsi, &p, end)) return -1; n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n != (p - start)) { lwsl_err("_write returned %d from %d\n", n, p - start); return -1; } return lws_http_transaction_completed(wsi); } } if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG, (unsigned char *)sym, n, &p, end)) return -1; #endif mimetype = get_mimetype(path, m); if (!mimetype) { lwsl_err("unknown mimetype for %s", path); goto bail; } n = lws_serve_http_file(wsi, path, mimetype, (char *)start, p - start); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ return 0; bail: return -1; } int lws_http_action(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; enum http_connection_type connection_type; enum http_version request_version; char content_length_str[32]; const struct lws_http_mount *hm, *hit = NULL; unsigned int n, count = 0; char http_version_str[10]; char http_conn_str[20]; int http_version_len; char *uri_ptr = NULL; int uri_len = 0, best = 0; int meth = -1; static const unsigned char methods[] = { WSI_TOKEN_GET_URI, WSI_TOKEN_POST_URI, WSI_TOKEN_OPTIONS_URI, WSI_TOKEN_PUT_URI, WSI_TOKEN_PATCH_URI, WSI_TOKEN_DELETE_URI, #ifdef LWS_USE_HTTP2 WSI_TOKEN_HTTP_COLON_PATH, #endif }; #if defined(_DEBUG) || defined(LWS_WITH_ACCESS_LOG) static const char * const method_names[] = { "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", #ifdef LWS_USE_HTTP2 ":path", #endif }; #endif /* it's not websocket.... shall we accept it as http? */ for (n = 0; n < ARRAY_SIZE(methods); n++) if (lws_hdr_total_length(wsi, methods[n])) count++; if (!count) { lwsl_warn("Missing URI in HTTP request\n"); goto bail_nuke_ah; } if (count != 1) { lwsl_warn("multiple methods?\n"); goto bail_nuke_ah; } if (lws_ensure_user_space(wsi)) goto bail_nuke_ah; for (n = 0; n < ARRAY_SIZE(methods); n++) if (lws_hdr_total_length(wsi, methods[n])) { uri_ptr = lws_hdr_simple_ptr(wsi, methods[n]); uri_len = lws_hdr_total_length(wsi, methods[n]); lwsl_info("Method: %s request for '%s'\n", method_names[n], uri_ptr); meth = n; break; } (void)meth; /* we insist on absolute paths */ if (uri_ptr[0] != '/') { lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); goto bail_nuke_ah; } /* HTTP header had a content length? */ wsi->u.http.content_length = 0; if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) || lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) || lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI)) wsi->u.http.content_length = 100 * 1024 * 1024; if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { lws_hdr_copy(wsi, content_length_str, sizeof(content_length_str) - 1, WSI_TOKEN_HTTP_CONTENT_LENGTH); wsi->u.http.content_length = atoi(content_length_str); } if (wsi->http2_substream) { wsi->u.http.request_version = HTTP_VERSION_2; } else { /* http_version? Default to 1.0, override with token: */ request_version = HTTP_VERSION_1_0; /* Works for single digit HTTP versions. : */ http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP); if (http_version_len > 7) { lws_hdr_copy(wsi, http_version_str, sizeof(http_version_str) - 1, WSI_TOKEN_HTTP); if (http_version_str[5] == '1' && http_version_str[7] == '1') request_version = HTTP_VERSION_1_1; } wsi->u.http.request_version = request_version; /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */ if (request_version == HTTP_VERSION_1_1) connection_type = HTTP_CONNECTION_KEEP_ALIVE; else connection_type = HTTP_CONNECTION_CLOSE; /* Override default if http "Connection:" header: */ if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) { lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1, WSI_TOKEN_CONNECTION); http_conn_str[sizeof(http_conn_str) - 1] = '\0'; if (!strcasecmp(http_conn_str, "keep-alive")) connection_type = HTTP_CONNECTION_KEEP_ALIVE; else if (!strcasecmp(http_conn_str, "close")) connection_type = HTTP_CONNECTION_CLOSE; } wsi->u.http.connection_type = connection_type; } n = wsi->protocol->callback(wsi, LWS_CALLBACK_FILTER_HTTP_CONNECTION, wsi->user_space, uri_ptr, uri_len); if (n) { lwsl_info("LWS_CALLBACK_HTTP closing\n"); return 1; } /* * if there is content supposed to be coming, * put a timeout on it having arrived */ lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, wsi->context->timeout_secs); #ifdef LWS_OPENSSL_SUPPORT if (wsi->redirect_to_https) { /* * we accepted http:// only so we could redirect to * https://, so issue the redirect. Create the redirection * URI from the host: header and ignore the path part */ unsigned char *start = pt->serv_buf + LWS_PRE, *p = start, *end = p + 512; if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) goto bail_nuke_ah; n = sprintf((char *)end, "https://%s/", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY, end, n, &p, end); if ((int)n < 0) goto bail_nuke_ah; return lws_http_transaction_completed(wsi); } #endif #ifdef LWS_WITH_ACCESS_LOG /* * Produce Apache-compatible log string for wsi, like this: * * 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800] * "GET /aep-screen.png HTTP/1.1" * 200 152987 "https://libwebsockets.org/index.html" * "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36" * */ { static const char * const hver[] = { "http/1.0", "http/1.1", "http/2" }; #ifdef LWS_USE_IPV6 char ads[INET6_ADDRSTRLEN]; #else char ads[INET_ADDRSTRLEN]; #endif char da[64]; const char *pa, *me; struct tm *tmp; time_t t = time(NULL); int l = 256; if (wsi->access_log_pending) lws_access_log(wsi); wsi->access_log.header_log = lws_malloc(l); if (wsi->access_log.header_log) { tmp = localtime(&t); if (tmp) strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp); else strcpy(da, "01/Jan/1970:00:00:00 +0000"); pa = lws_get_peer_simple(wsi, ads, sizeof(ads)); if (!pa) pa = "(unknown)"; if (meth >= 0) me = method_names[meth]; else me = "unknown"; lws_snprintf(wsi->access_log.header_log, l, "%s - - [%s] \"%s %s %s\"", pa, da, me, uri_ptr, hver[wsi->u.http.request_version]); l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT); if (l) { wsi->access_log.user_agent = lws_malloc(l + 2); if (wsi->access_log.user_agent) lws_hdr_copy(wsi, wsi->access_log.user_agent, l + 1, WSI_TOKEN_HTTP_USER_AGENT); else lwsl_err("OOM getting user agent\n"); } wsi->access_log_pending = 1; } } #endif /* can we serve it from the mount list? */ hm = wsi->vhost->mount_list; while (hm) { if (uri_len >= hm->mountpoint_len && !strncmp(uri_ptr, hm->mountpoint, hm->mountpoint_len) && (uri_ptr[hm->mountpoint_len] == '\0' || uri_ptr[hm->mountpoint_len] == '/' || hm->mountpoint_len == 1) ) { if ((hm->origin_protocol == LWSMPRO_CGI || lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) && hm->mountpoint_len > best) { best = hm->mountpoint_len; hit = hm; } } hm = hm->mount_next; } if (hit) { char *s = uri_ptr + hit->mountpoint_len; lwsl_debug("*** hit %d %d %s\n", hit->mountpoint_len, hit->origin_protocol , hit->origin); /* * if we have a mountpoint like https://xxx.com/yyy * there is an implied / at the end for our purposes since * we can only mount on a "directory". * * But if we just go with that, the browser cannot understand * that he is actually looking down one "directory level", so * even though we give him /yyy/abc.html he acts like the * current directory level is /. So relative urls like "x.png" * wrongly look outside the mountpoint. * * Therefore if we didn't come in on a url with an explicit * / at the end, we must redirect to add it so the browser * understands he is one "directory level" down. */ if ((hit->mountpoint_len > 1 || (hit->origin_protocol & 4)) && (*s != '/' || (hit->origin_protocol & 4)) && (hit->origin_protocol != LWSMPRO_CGI)) { unsigned char *start = pt->serv_buf + LWS_PRE, *p = start, *end = p + 512; static const char *oprot[] = { "http://", "https://" }; lwsl_debug("Doing 301 '%s' org %s\n", s, hit->origin); if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) goto bail_nuke_ah; /* > at start indicates deal with by redirect */ if (hit->origin_protocol & 4) n = lws_snprintf((char *)end, 256, "%s%s", oprot[hit->origin_protocol & 1], hit->origin); else n = lws_snprintf((char *)end, 256, "https://%s/%s/", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST), uri_ptr); n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY, end, n, &p, end); if ((int)n < 0) goto bail_nuke_ah; return lws_http_transaction_completed(wsi); } #ifdef LWS_WITH_CGI /* did we hit something with a cgi:// origin? */ if (hit->origin_protocol == LWSMPRO_CGI) { const char *cmd[] = { NULL, /* replace with cgi path */ NULL }; unsigned char *p, *end, buffer[256]; lwsl_debug("%s: cgi\n", __func__); cmd[0] = hit->origin; n = 5; if (hit->cgi_timeout) n = hit->cgi_timeout; n = lws_cgi(wsi, cmd, hit->mountpoint_len, n, hit->cgienv); if (n) { lwsl_err("%s: cgi failed\n"); return -1; } p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION, (unsigned char *)"close", 5, &p, end)) return 1; n = lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); goto deal_body; } #endif n = strlen(s); if (s[0] == '\0' || (n == 1 && s[n - 1] == '/')) s = (char *)hit->def; if (!s) s = "index.html"; wsi->cache_secs = hit->cache_max_age; wsi->cache_reuse = hit->cache_reusable; wsi->cache_revalidate = hit->cache_revalidate; wsi->cache_intermediaries = hit->cache_intermediaries; n = lws_http_serve(wsi, s, hit->origin, hit); if (n) { /* * lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL); */ n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP, wsi->user_space, uri_ptr, uri_len); } } else n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP, wsi->user_space, uri_ptr, uri_len); if (n) { lwsl_info("LWS_CALLBACK_HTTP closing\n"); return 1; } #ifdef LWS_WITH_CGI deal_body: #endif /* * If we're not issuing a file, check for content_length or * HTTP keep-alive. No keep-alive header allocation for * ISSUING_FILE, as this uses HTTP/1.0. * * In any case, return 0 and let lws_read decide how to * proceed based on state */ if (wsi->state != LWSS_HTTP_ISSUING_FILE) /* Prepare to read body if we have a content length: */ if (wsi->u.http.content_length > 0) wsi->state = LWSS_HTTP_BODY; return 0; bail_nuke_ah: /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; lws_header_table_detach(wsi, 1); return 1; } int lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; struct _lws_header_related hdr; struct allocated_headers *ah; int protocol_len, n, hit; char protocol_list[128]; char protocol_name[64]; char *p; if (len >= 10000000) { lwsl_err("%s: assert: len %ld\n", __func__, (long)len); assert(0); } if (!wsi->u.hdr.ah) { lwsl_err("%s: assert: NULL ah\n", __func__); assert(0); } while (len--) { wsi->more_rx_waiting = !!len; if (wsi->mode != LWSCM_HTTP_SERVING && wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED) { lwsl_err("%s: bad wsi mode %d\n", __func__, wsi->mode); goto bail_nuke_ah; } if (lws_parse(wsi, *(*buf)++)) { lwsl_info("lws_parse failed\n"); goto bail_nuke_ah; } if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE) continue; lwsl_parser("%s: lws_parse sees parsing complete\n", __func__); lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__, wsi->more_rx_waiting); /* select vhost */ if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { struct lws_vhost *vhost = lws_select_vhost( context, wsi->vhost->listen_port, lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); if (vhost) wsi->vhost = vhost; } else lwsl_info("no host\n"); wsi->vhost->trans++; if (!wsi->conn_stat_done) { wsi->vhost->conn++; wsi->conn_stat_done = 1; } wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT; lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* is this websocket protocol or normal http 1.0? */ if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) { if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), "websocket")) { wsi->vhost->ws_upgrades++; lwsl_info("Upgrade to ws\n"); goto upgrade_ws; } #ifdef LWS_USE_HTTP2 if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), "h2c")) { wsi->vhost->http2_upgrades++; lwsl_info("Upgrade to h2c\n"); goto upgrade_h2c; } #endif lwsl_info("Unknown upgrade\n"); /* dunno what he wanted to upgrade to */ goto bail_nuke_ah; } /* no upgrade ack... he remained as HTTP */ lwsl_info("No upgrade\n"); ah = wsi->u.hdr.ah; lws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED); wsi->state = LWSS_HTTP; wsi->u.http.fd = LWS_INVALID_FILE; /* expose it at the same offset as u.hdr */ wsi->u.http.ah = ah; lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi, (void *)wsi->u.hdr.ah); n = lws_http_action(wsi); return n; #ifdef LWS_USE_HTTP2 upgrade_h2c: if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) { lwsl_info("missing http2_settings\n"); goto bail_nuke_ah; } lwsl_info("h2c upgrade...\n"); p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS); /* convert the peer's HTTP-Settings */ n = lws_b64_decode_string(p, protocol_list, sizeof(protocol_list)); if (n < 0) { lwsl_parser("HTTP2_SETTINGS too long\n"); return 1; } /* adopt the header info */ ah = wsi->u.hdr.ah; lws_union_transition(wsi, LWSCM_HTTP2_SERVING); /* http2 union member has http union struct at start */ wsi->u.http.ah = ah; lws_http2_init(&wsi->u.http2.peer_settings); lws_http2_init(&wsi->u.http2.my_settings); /* HTTP2 union */ lws_http2_interpret_settings_payload(&wsi->u.http2.peer_settings, (unsigned char *)protocol_list, n); strcpy(protocol_list, "HTTP/1.1 101 Switching Protocols\x0d\x0a" "Connection: Upgrade\x0d\x0a" "Upgrade: h2c\x0d\x0a\x0d\x0a"); n = lws_issue_raw(wsi, (unsigned char *)protocol_list, strlen(protocol_list)); if (n != strlen(protocol_list)) { lwsl_debug("http2 switch: ERROR writing to socket\n"); return 1; } wsi->state = LWSS_HTTP2_AWAIT_CLIENT_PREFACE; return 0; #endif upgrade_ws: if (!wsi->protocol) lwsl_err("NULL protocol at lws_read\n"); /* * It's websocket * * Select the first protocol we support from the list * the client sent us. * * Copy it to remove header fragmentation */ if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1, WSI_TOKEN_PROTOCOL) < 0) { lwsl_err("protocol list too long"); goto bail_nuke_ah; } protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL); protocol_list[protocol_len] = '\0'; p = protocol_list; hit = 0; while (*p && !hit) { n = 0; while (n < sizeof(protocol_name) - 1 && *p && *p !=',') protocol_name[n++] = *p++; protocol_name[n] = '\0'; if (*p) p++; lwsl_info("checking %s\n", protocol_name); n = 0; while (wsi->vhost->protocols[n].callback) { if (wsi->vhost->protocols[n].name && !strcmp(wsi->vhost->protocols[n].name, protocol_name)) { wsi->protocol = &wsi->vhost->protocols[n]; hit = 1; break; } n++; } } /* we didn't find a protocol he wanted? */ if (!hit) { if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) { lwsl_info("No protocol from \"%s\" supported\n", protocol_list); goto bail_nuke_ah; } /* * some clients only have one protocol and * do not send the protocol list header... * allow it and match to the vhost's default * protocol (which itself defaults to zero) */ lwsl_info("defaulting to prot handler %d\n", wsi->vhost->default_protocol_index); n = 0; wsi->protocol = &wsi->vhost->protocols[ (int)wsi->vhost->default_protocol_index]; } /* allocate wsi->user storage */ if (lws_ensure_user_space(wsi)) goto bail_nuke_ah; /* * Give the user code a chance to study the request and * have the opportunity to deny it */ if ((wsi->protocol->callback)(wsi, LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, wsi->user_space, lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) { lwsl_warn("User code denied connection\n"); goto bail_nuke_ah; } /* * Perform the handshake according to the protocol version the * client announced */ switch (wsi->ietf_spec_revision) { case 13: lwsl_parser("lws_parse calling handshake_04\n"); if (handshake_0405(context, wsi)) { lwsl_info("hs0405 has failed the connection\n"); goto bail_nuke_ah; } break; default: lwsl_info("Unknown client spec version %d\n", wsi->ietf_spec_revision); goto bail_nuke_ah; } /* * stitch protocol choice into the vh protocol linked list * We always insert ourselves at the start of the list * * X <-> B * X <-> pAn <-> pB */ //lwsl_err("%s: pre insert vhost start wsi %p, that wsi prev == %p\n", // __func__, // wsi->vhost->same_vh_protocol_list[n], // wsi->same_vh_protocol_prev); wsi->same_vh_protocol_prev = /* guy who points to us */ &wsi->vhost->same_vh_protocol_list[n]; wsi->same_vh_protocol_next = /* old first guy is our next */ wsi->vhost->same_vh_protocol_list[n]; /* we become the new first guy */ wsi->vhost->same_vh_protocol_list[n] = wsi; if (wsi->same_vh_protocol_next) /* old first guy points back to us now */ wsi->same_vh_protocol_next->same_vh_protocol_prev = &wsi->same_vh_protocol_next; /* we are upgrading to ws, so http/1.1 and keepalive + * pipelined header considerations about keeping the ah around * no longer apply. However it's common for the first ws * protocol data to have been coalesced with the browser * upgrade request and to already be in the ah rx buffer. */ lwsl_info("%s: %p: inheriting ah in ws mode (rxpos:%d, rxlen:%d)\n", __func__, wsi, wsi->u.hdr.ah->rxpos, wsi->u.hdr.ah->rxlen); lws_pt_lock(pt); hdr = wsi->u.hdr; lws_union_transition(wsi, LWSCM_WS_SERVING); /* * first service is WS mode will notice this, use the RX and * then detach the ah (caution: we are not in u.hdr union * mode any more then... ah_temp member is at start the same * though) * * Because rxpos/rxlen shows something in the ah, we will get * service guaranteed next time around the event loop * * All union members begin with hdr, so we can use it even * though we transitioned to ws union mode (the ah detach * code uses it anyway). */ wsi->u.hdr = hdr; lws_pt_unlock(pt); /* * create the frame buffer for this connection according to the * size mentioned in the protocol definition. If 0 there, use * a big default for compatibility */ n = wsi->protocol->rx_buffer_size; if (!n) n = LWS_MAX_SOCKET_IO_BUF; n += LWS_PRE; wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */); if (!wsi->u.ws.rx_ubuf) { lwsl_err("Out of Mem allocating rx buffer %d\n", n); return 1; } wsi->u.ws.rx_ubuf_alloc = n; lwsl_info("Allocating RX buffer %d\n", n); #if LWS_POSIX if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) { lwsl_warn("Failed to set SNDBUF to %d", n); return 1; } #endif lwsl_parser("accepted v%02d connection\n", wsi->ietf_spec_revision); return 0; } /* while all chars are handled */ return 0; bail_nuke_ah: /* drop the header info */ /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; lws_header_table_detach(wsi, 1); return 1; } static int lws_get_idlest_tsi(struct lws_context *context) { unsigned int lowest = ~0; int n = 0, hit = -1; for (; n < context->count_threads; n++) { if ((unsigned int)context->pt[n].fds_count != context->fd_limit_per_thread - 1 && (unsigned int)context->pt[n].fds_count < lowest) { lowest = context->pt[n].fds_count; hit = n; } } return hit; } struct lws * lws_create_new_server_wsi(struct lws_vhost *vhost) { struct lws *new_wsi; int n = lws_get_idlest_tsi(vhost->context); if (n < 0) { lwsl_err("no space for new conn\n"); return NULL; } new_wsi = lws_zalloc(sizeof(struct lws)); if (new_wsi == NULL) { lwsl_err("Out of memory for new connection\n"); return NULL; } new_wsi->tsi = n; lwsl_info("Accepted %p to tsi %d\n", new_wsi, new_wsi->tsi); new_wsi->vhost = vhost; new_wsi->context = vhost->context; new_wsi->pending_timeout = NO_PENDING_TIMEOUT; new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; /* intialize the instance struct */ new_wsi->state = LWSS_HTTP; new_wsi->mode = LWSCM_HTTP_SERVING; new_wsi->hdr_parsing_completed = 0; #ifdef LWS_OPENSSL_SUPPORT new_wsi->use_ssl = LWS_SSL_ENABLED(vhost); #endif /* * these can only be set once the protocol is known * we set an unestablished connection's protocol pointer * to the start of the supported list, so it can look * for matching ones during the handshake */ new_wsi->protocol = vhost->protocols; new_wsi->user_space = NULL; new_wsi->ietf_spec_revision = 0; new_wsi->sock = LWS_SOCK_INVALID; vhost->context->count_wsi_allocated++; /* * outermost create notification for wsi * no user_space because no protocol selection */ vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0); return new_wsi; } /** * lws_http_transaction_completed() - wait for new http transaction or close * @wsi: websocket connection * * Returns 1 if the HTTP connection must close now * Returns 0 and resets connection to wait for new HTTP header / * transaction if possible */ LWS_VISIBLE int LWS_WARN_UNUSED_RESULT lws_http_transaction_completed(struct lws *wsi) { int n = NO_PENDING_TIMEOUT; lws_access_log(wsi); lwsl_debug("%s: wsi %p\n", __func__, wsi); /* if we can't go back to accept new headers, drop the connection */ if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) { lwsl_info("%s: %p: close connection\n", __func__, wsi); return 1; } /* otherwise set ourselves up ready to go again */ wsi->state = LWSS_HTTP; wsi->mode = LWSCM_HTTP_SERVING; wsi->u.http.content_length = 0; wsi->hdr_parsing_completed = 0; #ifdef LWS_WITH_ACCESS_LOG wsi->access_log.sent = 0; #endif if (wsi->vhost->keepalive_timeout) n = PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE; lws_set_timeout(wsi, n, wsi->vhost->keepalive_timeout); /* * We already know we are on http1.1 / keepalive and the next thing * coming will be another header set. * * If there is no pending rx and we still have the ah, drop it and * reacquire a new ah when the new headers start to arrive. (Otherwise * we needlessly hog an ah indefinitely.) * * However if there is pending rx and we know from the keepalive state * that is already at least the start of another header set, simply * reset the existing header table and keep it. */ if (wsi->u.hdr.ah) { lwsl_info("%s: wsi->more_rx_waiting=%d\n", __func__, wsi->more_rx_waiting); if (!wsi->more_rx_waiting) { wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; lws_header_table_detach(wsi, 1); } else lws_header_table_reset(wsi, 1); } /* If we're (re)starting on headers, need other implied init */ wsi->u.hdr.ues = URIES_IDLE; lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi); return 0; } static struct lws * lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd) { struct lws_context *context = vh->context; struct lws *new_wsi = lws_create_new_server_wsi(vh); if (!new_wsi) { compatible_close(accept_fd); return NULL; } lwsl_info("%s: new wsi %p, sockfd %d\n", __func__, new_wsi, accept_fd); new_wsi->sock = accept_fd; /* the transport is accepted... give him time to negotiate */ lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); #if LWS_POSIX == 0 mbed3_tcp_stream_accept(accept_fd, new_wsi); #endif /* * A new connection was accepted. Give the user a chance to * set properties of the newly created wsi. There's no protocol * selected yet so we issue this to protocols[0] */ if ((context->vhost_list->protocols[0].callback)(new_wsi, LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0)) { /* force us off the timeout list by hand */ lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0); compatible_close(new_wsi->sock); lws_free(new_wsi); return NULL; } lws_libev_accept(new_wsi, new_wsi->sock); lws_libuv_accept(new_wsi, new_wsi->sock); if (!LWS_SSL_ENABLED(new_wsi->vhost)) { if (insert_wsi_socket_into_fds(context, new_wsi)) { lwsl_err("%s: fail inserting socket\n", __func__); goto fail; } } else { new_wsi->mode = LWSCM_SSL_INIT; if (lws_server_socket_service_ssl(new_wsi, accept_fd)) { lwsl_err("%s: fail ssl negotiation\n", __func__); goto fail; } } if (!lws_header_table_attach(new_wsi, 0)) lwsl_debug("Attached ah immediately\n"); return new_wsi; fail: lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS); return NULL; } /** * lws_adopt_socket() - adopt foreign socket as if listen socket accepted it * @context: lws context * @accept_fd: fd of already-accepted socket to adopt * * Either returns new wsi bound to accept_fd, or closes accept_fd and * returns NULL, having cleaned up any new wsi pieces. * * LWS adopts the socket in http serving mode, it's ready to accept an upgrade * to ws or just serve http. */ LWS_VISIBLE struct lws * lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd) { return lws_adopt_socket_vhost(context->vhost_list, accept_fd); } /** * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it * @context: lws context * @accept_fd: fd of already-accepted socket to adopt * @readbuf: NULL or pointer to data that must be drained before reading from * accept_fd * @len: The length of the data held at @readbuf * * Either returns new wsi bound to accept_fd, or closes accept_fd and * returns NULL, having cleaned up any new wsi pieces. * * LWS adopts the socket in http serving mode, it's ready to accept an upgrade * to ws or just serve http. * * If your external code did not already read from the socket, you can use * lws_adopt_socket() instead. * * This api is guaranteed to use the data at @readbuf first, before reading from * the socket. * * @readbuf is limited to the size of the ah rx buf, currently 2048 bytes. */ LWS_VISIBLE LWS_EXTERN struct lws * lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd, const char *readbuf, size_t len) { struct lws *wsi = lws_adopt_socket(context, accept_fd); struct lws_context_per_thread *pt; struct allocated_headers *ah; struct lws_pollfd *pfd; if (!wsi) return NULL; if (!readbuf) return wsi; if (len > sizeof(ah->rx)) { lwsl_err("%s: rx in too big\n", __func__); goto bail; } /* * we can't process the initial read data until we can attach an ah. * * if one is available, get it and place the data in his ah rxbuf... * wsi with ah that have pending rxbuf get auto-POLLIN service. * * no autoservice because we didn't get a chance to attach the * readbuf data to wsi or ah yet, and we will do it next if we get * the ah. */ if (wsi->u.hdr.ah || !lws_header_table_attach(wsi, 0)) { ah = wsi->u.hdr.ah; memcpy(ah->rx, readbuf, len); ah->rxpos = 0; ah->rxlen = len; lwsl_notice("%s: calling service on readbuf ah\n", __func__); pt = &context->pt[(int)wsi->tsi]; /* unlike a normal connect, we have the headers already * (or the first part of them anyway). * libuv won't come back and service us without a network * event, so we need to do the header service right here. */ pfd = &pt->fds[wsi->position_in_fds_table]; pfd->revents |= LWS_POLLIN; lwsl_err("%s: calling service\n", __func__); if (lws_service_fd_tsi(context, pfd, wsi->tsi)) /* service closed us */ return NULL; return wsi; } lwsl_err("%s: deferring handling ah\n", __func__); /* * hum if no ah came, we are on the wait list and must defer * dealing with this until the ah arrives. * * later successful lws_header_table_attach() will apply the * below to the rx buffer (via lws_header_table_reset()). */ wsi->u.hdr.preamble_rx = lws_malloc(len); if (!wsi->u.hdr.preamble_rx) { lwsl_err("OOM\n"); goto bail; } memcpy(wsi->u.hdr.preamble_rx, readbuf, len); wsi->u.hdr.preamble_rx_len = len; return wsi; bail: lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return NULL; } LWS_VISIBLE int lws_server_socket_service(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pollfd) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; lws_sockfd_type accept_fd = LWS_SOCK_INVALID; struct allocated_headers *ah; #if LWS_POSIX struct sockaddr_in cli_addr; socklen_t clilen; #endif int n, len; switch (wsi->mode) { case LWSCM_HTTP_SERVING: case LWSCM_HTTP_SERVING_ACCEPTED: case LWSCM_HTTP2_SERVING: /* handle http headers coming in */ /* pending truncated sends have uber priority */ if (wsi->trunc_len) { if (!(pollfd->revents & LWS_POLLOUT)) break; if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset, wsi->trunc_len) < 0) goto fail; /* * we can't afford to allow input processing to send * something new, so spin around he event loop until * he doesn't have any partials */ break; } /* any incoming data ready? */ if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) goto try_pollout; /* * If we previously just did POLLIN when IN and OUT were * signalled (because POLLIN processing may have used up * the POLLOUT), don't let that happen twice in a row... * next time we see the situation favour POLLOUT */ if (wsi->favoured_pollin && (pollfd->revents & pollfd->events & LWS_POLLOUT)) { wsi->favoured_pollin = 0; goto try_pollout; } /* these states imply we MUST have an ah attached */ if (wsi->state == LWSS_HTTP || wsi->state == LWSS_HTTP_ISSUING_FILE || wsi->state == LWSS_HTTP_HEADERS) { if (!wsi->u.hdr.ah) /* no autoservice beacuse we will do it next */ if (lws_header_table_attach(wsi, 0)) goto try_pollout; ah = wsi->u.hdr.ah; lwsl_debug("%s: %p: rxpos:%d rxlen:%d\n", __func__, wsi, ah->rxpos, ah->rxlen); /* if nothing in ah rx buffer, get some fresh rx */ if (ah->rxpos == ah->rxlen) { ah->rxlen = lws_ssl_capable_read(wsi, ah->rx, sizeof(ah->rx)); ah->rxpos = 0; lwsl_debug("%s: wsi %p, ah->rxlen = %d\r\n", __func__, wsi, ah->rxlen); switch (ah->rxlen) { case 0: lwsl_info("%s: read 0 len\n", __func__); /* lwsl_info(" state=%d\n", wsi->state); */ // if (!wsi->hdr_parsing_completed) // lws_header_table_detach(wsi); /* fallthru */ case LWS_SSL_CAPABLE_ERROR: goto fail; case LWS_SSL_CAPABLE_MORE_SERVICE: ah->rxlen = ah->rxpos = 0; goto try_pollout; } } if (!(ah->rxpos != ah->rxlen && ah->rxlen)) { lwsl_err("%s: assert: rxpos %d, rxlen %d\n", __func__, ah->rxpos, ah->rxlen); assert(0); } /* just ignore incoming if waiting for close */ if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) { n = lws_read(wsi, ah->rx + ah->rxpos, ah->rxlen - ah->rxpos); if (n < 0) /* we closed wsi */ return 1; if (wsi->u.hdr.ah) { if ( wsi->u.hdr.ah->rxlen) wsi->u.hdr.ah->rxpos += n; if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen && (wsi->mode != LWSCM_HTTP_SERVING && wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED && wsi->mode != LWSCM_HTTP2_SERVING)) lws_header_table_detach(wsi, 1); } break; } goto try_pollout; } len = lws_ssl_capable_read(wsi, pt->serv_buf, LWS_MAX_SOCKET_IO_BUF); lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len); switch (len) { case 0: lwsl_info("%s: read 0 len\n", __func__); /* lwsl_info(" state=%d\n", wsi->state); */ // if (!wsi->hdr_parsing_completed) // lws_header_table_detach(wsi); /* fallthru */ case LWS_SSL_CAPABLE_ERROR: goto fail; case LWS_SSL_CAPABLE_MORE_SERVICE: goto try_pollout; } /* just ignore incoming if waiting for close */ if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) { /* * this may want to send * (via HTTP callback for example) */ n = lws_read(wsi, pt->serv_buf, len); if (n < 0) /* we closed wsi */ return 1; /* * he may have used up the * writability above, if we will defer POLLOUT * processing in favour of POLLIN, note it */ if (pollfd->revents & LWS_POLLOUT) wsi->favoured_pollin = 1; break; } try_pollout: /* this handles POLLOUT for http serving fragments */ if (!(pollfd->revents & LWS_POLLOUT)) break; /* one shot */ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_notice("%s a\n", __func__); goto fail; } if (!wsi->hdr_parsing_completed) break; if (wsi->state != LWSS_HTTP_ISSUING_FILE) { n = user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_HTTP_WRITEABLE, wsi->user_space, NULL, 0); if (n < 0) { lwsl_info("writeable_fail\n"); goto fail; } break; } /* >0 == completion, <0 == error */ n = lws_serve_http_file_fragment(wsi); if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) { lwsl_info("completed\n"); goto fail; } break; case LWSCM_SERVER_LISTENER: #if LWS_POSIX /* pollin means a client has connected to us then */ do { if (!(pollfd->revents & LWS_POLLIN) || !(pollfd->events & LWS_POLLIN)) break; /* listen socket got an unencrypted connection... */ clilen = sizeof(cli_addr); lws_latency_pre(context, wsi); accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr, &clilen); lws_latency(context, wsi, "listener accept", accept_fd, accept_fd >= 0); if (accept_fd < 0) { if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) { lwsl_err("accept asks to try again\n"); break; } lwsl_err("ERROR on accept: %s\n", strerror(LWS_ERRNO)); break; } lws_plat_set_socket_options(wsi->vhost, accept_fd); lwsl_debug("accepted new conn port %u on fd=%d\n", ntohs(cli_addr.sin_port), accept_fd); #else /* not very beautiful... */ accept_fd = (lws_sockfd_type)pollfd; #endif /* * look at who we connected to and give user code a chance * to reject based on client IP. There's no protocol selected * yet so we issue this to protocols[0] */ if ((wsi->vhost->protocols[0].callback)(wsi, LWS_CALLBACK_FILTER_NETWORK_CONNECTION, NULL, (void *)(long)accept_fd, 0)) { lwsl_debug("Callback denied network connection\n"); compatible_close(accept_fd); break; } if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd)) /* already closed cleanly as necessary */ return 1; #if LWS_POSIX } while (pt->fds_count < context->fd_limit_per_thread - 1 && lws_poll_listen_fd(&pt->fds[wsi->position_in_fds_table]) > 0); #endif return 0; default: break; } if (!lws_server_socket_service_ssl(wsi, accept_fd)) return 0; fail: lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } /** * lws_serve_http_file() - Send a file back to the client using http * @wsi: Websocket instance (available from user callback) * @file: The file to issue over http * @content_type: The http content type, eg, text/html * @other_headers: NULL or pointer to header string * @other_headers_len: length of the other headers if non-NULL * * This function is intended to be called from the callback in response * to http requests from the client. It allows the callback to issue * local files down the http link in a single step. * * Returning <0 indicates error and the wsi should be closed. Returning * >0 indicates the file was completely sent and * lws_http_transaction_completed() called on the wsi (and close if != 0) * ==0 indicates the file transfer is started and needs more service later, * the wsi should be left alone. */ LWS_VISIBLE int lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, const char *other_headers, int other_headers_len) { static const char * const intermediates[] = { "private", "public" }; struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; char cache_control[50], *cc = "no-store"; unsigned char *response = pt->serv_buf + LWS_PRE; unsigned char *p = response; unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE; int ret = 0, cclen = 8; wsi->u.http.fd = lws_plat_file_open(wsi, file, &wsi->u.http.filelen, O_RDONLY); if (wsi->u.http.fd == LWS_INVALID_FILE) { lwsl_err("Unable to open '%s'\n", file); lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL); return -1; } if (lws_add_http_header_status(wsi, 200, &p, end)) return -1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)content_type, strlen(content_type), &p, end)) return -1; if (lws_add_http_header_content_length(wsi, wsi->u.http.filelen, &p, end)) return -1; if (wsi->cache_secs && wsi->cache_reuse) { if (wsi->cache_revalidate) { cc = cache_control; cclen = sprintf(cache_control, "%s max-age: %u", intermediates[wsi->cache_intermediaries], wsi->cache_secs); } else { cc = "no-cache"; cclen = 8; } } if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL, (unsigned char *)cc, cclen, &p, end)) return -1; if (other_headers) { if ((end - p) < other_headers_len) return -1; memcpy(p, other_headers, other_headers_len); p += other_headers_len; } if (lws_finalize_http_header(wsi, &p, end)) return -1; ret = lws_write(wsi, response, p - response, LWS_WRITE_HTTP_HEADERS); if (ret != (p - response)) { lwsl_err("_write returned %d from %d\n", ret, (p - response)); return -1; } wsi->u.http.filepos = 0; wsi->state = LWSS_HTTP_ISSUING_FILE; return lws_serve_http_file_fragment(wsi); } int lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len) { int m; lwsl_parser("%s: received %d byte packet\n", __func__, (int)len); #if 0 lwsl_hexdump(*buf, len); #endif /* let the rx protocol state machine have as much as it needs */ while (len) { /* * we were accepting input but now we stopped doing so */ if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { lws_rxflow_cache(wsi, *buf, 0, len); lwsl_parser("%s: cached %d\n", __func__, len); return 1; } if (wsi->u.ws.rx_draining_ext) { m = lws_rx_sm(wsi, 0); if (m < 0) return -1; continue; } /* account for what we're using in rxflow buffer */ if (wsi->rxflow_buffer) wsi->rxflow_pos++; /* consume payload bytes efficiently */ if (wsi->lws_rx_parse_state == LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) { m = lws_payload_until_length_exhausted(wsi, buf, &len); if (wsi->rxflow_buffer) wsi->rxflow_pos += m; } /* process the byte */ m = lws_rx_sm(wsi, *(*buf)++); if (m < 0) return -1; len--; } lwsl_parser("%s: exit with %d unused\n", __func__, (int)len); return 0; } LWS_VISIBLE void lws_server_get_canonical_hostname(struct lws_context *context, struct lws_context_creation_info *info) { if (lws_check_opt(info->options, LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)) return; #if LWS_POSIX /* find canonical hostname */ gethostname((char *)context->canonical_hostname, sizeof(context->canonical_hostname) - 1); lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname); #else (void)context; #endif } |
Added undroid/libwebsockets/lib/service.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" static int lws_calllback_as_writeable(struct lws *wsi) { int n; switch (wsi->mode) { case LWSCM_WS_CLIENT: n = LWS_CALLBACK_CLIENT_WRITEABLE; break; case LWSCM_WS_SERVING: n = LWS_CALLBACK_SERVER_WRITEABLE; break; default: n = LWS_CALLBACK_HTTP_WRITEABLE; break; } lwsl_debug("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space); return user_callback_handle_rxflow(wsi->protocol->callback, wsi, (enum lws_callback_reasons) n, wsi->user_space, NULL, 0); } int lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) { int write_type = LWS_WRITE_PONG; struct lws_tokens eff_buf; #ifdef LWS_USE_HTTP2 struct lws *wsi2; #endif int ret, m, n; //lwsl_err("%s: %p\n", __func__, wsi); /* * user callback is lowest priority to get these notifications * actually, since other pending things cannot be disordered */ /* Priority 1: pending truncated sends are incomplete ws fragments * If anything else sent first the protocol would be * corrupted. */ if (wsi->trunc_len) { if (lws_issue_raw(wsi, wsi->trunc_alloc + wsi->trunc_offset, wsi->trunc_len) < 0) { lwsl_info("%s signalling to close\n", __func__); return -1; } /* leave POLLOUT active either way */ return 0; } else if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) return -1; /* retry closing now */ #ifdef LWS_USE_HTTP2 /* Priority 2: protocol packets */ if (wsi->pps) { lwsl_info("servicing pps %d\n", wsi->pps); switch (wsi->pps) { case LWS_PPS_HTTP2_MY_SETTINGS: case LWS_PPS_HTTP2_ACK_SETTINGS: lws_http2_do_pps_send(lws_get_context(wsi), wsi); break; default: break; } wsi->pps = LWS_PPS_NONE; lws_rx_flow_control(wsi, 1); return 0; /* leave POLLOUT active */ } #endif #ifdef LWS_WITH_CGI if (wsi->cgi) goto user_service_go_again; #endif /* Priority 3: pending control packets (pong or close) */ if ((wsi->state == LWSS_ESTABLISHED && wsi->u.ws.ping_pending_flag) || (wsi->state == LWSS_RETURNED_CLOSE_ALREADY && wsi->u.ws.payload_is_close)) { if (wsi->u.ws.payload_is_close) write_type = LWS_WRITE_CLOSE; n = lws_write(wsi, &wsi->u.ws.ping_payload_buf[LWS_PRE], wsi->u.ws.ping_payload_len, write_type); if (n < 0) return -1; /* well he is sent, mark him done */ wsi->u.ws.ping_pending_flag = 0; if (wsi->u.ws.payload_is_close) /* oh... a close frame was it... then we are done */ return -1; /* otherwise for PING, leave POLLOUT active either way */ return 0; } /* Priority 4: if we are closing, not allowed to send more data frags * which means user callback or tx ext flush banned now */ if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY) goto user_service; /* Priority 5: Tx path extension with more to send * * These are handled as new fragments each time around * So while we must block new writeable callback to enforce * payload ordering, but since they are always complete * fragments control packets can interleave OK. */ if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) { lwsl_ext("SERVICING TX EXT DRAINING\n"); if (lws_write(wsi, NULL, 0, LWS_WRITE_CONTINUATION) < 0) return -1; /* leave POLLOUT active */ return 0; } /* Priority 6: user can get the callback */ m = lws_ext_cb_active(wsi, LWS_EXT_CB_IS_WRITEABLE, NULL, 0); if (m) return -1; #ifndef LWS_NO_EXTENSIONS if (!wsi->extension_data_pending) goto user_service; #endif /* * check in on the active extensions, see if they * had pending stuff to spill... they need to get the * first look-in otherwise sequence will be disordered * * NULL, zero-length eff_buf means just spill pending */ ret = 1; while (ret == 1) { /* default to nobody has more to spill */ ret = 0; eff_buf.token = NULL; eff_buf.token_len = 0; /* give every extension a chance to spill */ m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_PRESEND, &eff_buf, 0); if (m < 0) { lwsl_err("ext reports fatal error\n"); return -1; } if (m) /* * at least one extension told us he has more * to spill, so we will go around again after */ ret = 1; /* assuming they gave us something to send, send it */ if (eff_buf.token_len) { n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token, eff_buf.token_len); if (n < 0) { lwsl_info("closing from POLLOUT spill\n"); return -1; } /* * Keep amount spilled small to minimize chance of this */ if (n != eff_buf.token_len) { lwsl_err("Unable to spill ext %d vs %s\n", eff_buf.token_len, n); return -1; } } else continue; /* no extension has more to spill */ if (!ret) continue; /* * There's more to spill from an extension, but we just sent * something... did that leave the pipe choked? */ if (!lws_send_pipe_choked(wsi)) /* no we could add more */ continue; lwsl_info("choked in POLLOUT service\n"); /* * Yes, he's choked. Leave the POLLOUT masked on so we will * come back here when he is unchoked. Don't call the user * callback to enforce ordering of spilling, he'll get called * when we come back here and there's nothing more to spill. */ return 0; } #ifndef LWS_NO_EXTENSIONS wsi->extension_data_pending = 0; #endif user_service: /* one shot */ if (pollfd) if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_info("failed at set pollfd\n"); return 1; } if (!wsi->hdr_parsing_completed) return 0; #ifdef LWS_WITH_CGI user_service_go_again: #endif #ifdef LWS_USE_HTTP2 /* * we are the 'network wsi' for potentially many muxed child wsi with * no network connection of their own, who have to use us for all their * network actions. So we use a round-robin scheme to share out the * POLLOUT notifications to our children. * * But because any child could exhaust the socket's ability to take * writes, we can only let one child get notified each time. * * In addition children may be closed / deleted / added between POLLOUT * notifications, so we can't hold pointers */ if (wsi->mode != LWSCM_HTTP2_SERVING) { lwsl_info("%s: non http2\n", __func__); goto notify; } wsi->u.http2.requested_POLLOUT = 0; if (!wsi->u.http2.initialized) { lwsl_info("pollout on uninitialized http2 conn\n"); return 0; } lwsl_info("%s: doing children\n", __func__); wsi2 = wsi; do { wsi2 = wsi2->u.http2.next_child_wsi; lwsl_info("%s: child %p\n", __func__, wsi2); if (!wsi2) continue; if (!wsi2->u.http2.requested_POLLOUT) continue; wsi2->u.http2.requested_POLLOUT = 0; if (lws_calllback_as_writeable(wsi2)) { lwsl_debug("Closing POLLOUT child\n"); lws_close_free_wsi(wsi2, LWS_CLOSE_STATUS_NOSTATUS); } wsi2 = wsi; } while (wsi2 != NULL && !lws_send_pipe_choked(wsi)); lwsl_info("%s: completed\n", __func__); return 0; notify: #endif return lws_calllback_as_writeable(wsi); } int lws_service_timeout_check(struct lws *wsi, unsigned int sec) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; /* * if extensions want in on it (eg, we are a mux parent) * give them a chance to service child timeouts */ if (lws_ext_cb_active(wsi, LWS_EXT_CB_1HZ, NULL, sec) < 0) return 0; if (!wsi->pending_timeout) return 0; /* * if we went beyond the allowed time, kill the * connection */ if ((time_t)sec > wsi->pending_timeout_limit) { #if LWS_POSIX /* no need to log normal idle keepalive timeout */ if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE) lwsl_notice("wsi %p: TIMEDOUT WAITING on %d (did hdr %d, ah %p, wl %d, pfd events %d)\n", (void *)wsi, wsi->pending_timeout, wsi->hdr_parsing_completed, wsi->u.hdr.ah, pt->ah_wait_list_length, pt->fds[wsi->sock].events); #endif /* * Since he failed a timeout, he already had a chance to do * something and was unable to... that includes situations like * half closed connections. So process this "failed timeout" * close as a violent death and don't try to do protocol * cleanup like flush partials. */ wsi->socket_is_permanently_unusable = 1; if (wsi->mode == LWSCM_WSCL_WAITING_SSL) wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return 1; } return 0; } int lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len) { /* his RX is flowcontrolled, don't send remaining now */ if (wsi->rxflow_buffer) { /* rxflow while we were spilling prev rxflow */ lwsl_info("stalling in existing rxflow buf\n"); return 1; } /* a new rxflow, buffer it and warn caller */ lwsl_info("new rxflow input buffer len %d\n", len - n); wsi->rxflow_buffer = lws_malloc(len - n); if (!wsi->rxflow_buffer) return -1; wsi->rxflow_len = len - n; wsi->rxflow_pos = 0; memcpy(wsi->rxflow_buffer, buf + n, len - n); return 0; } /* this is used by the platform service code to stop us waiting for network * activity in poll() when we have something that already needs service */ int lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; int n; /* Figure out if we really want to wait in poll() * We only need to wait if really nothing already to do and we have * to wait for something from network */ /* 1) if we know we are draining rx ext, do not wait in poll */ if (pt->rx_draining_ext_list) return 0; #ifdef LWS_OPENSSL_SUPPORT /* 2) if we know we have non-network pending data, do not wait in poll */ if (lws_ssl_anybody_has_buffered_read_tsi(context, tsi)) { lwsl_info("ssl buffered read\n"); return 0; } #endif /* 3) if any ah has pending rx, do not wait in poll */ for (n = 0; n < context->max_http_header_pool; n++) if (pt->ah_pool[n].rxpos != pt->ah_pool[n].rxlen) { /* any ah with pending rx must be attached to someone */ if (!pt->ah_pool[n].wsi) { lwsl_err("%s: assert: no wsi attached to ah\n", __func__); assert(0); } return 0; } return timeout_ms; } /* * guys that need POLLIN service again without waiting for network action * can force POLLIN here if not flowcontrolled, so they will get service. * * Return nonzero if anybody got their POLLIN faked */ int lws_service_flag_pending(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; #ifdef LWS_OPENSSL_SUPPORT struct lws *wsi_next; #endif struct lws *wsi; int forced = 0; int n; /* POLLIN faking */ /* * 1) For all guys with already-available ext data to drain, if they are * not flowcontrolled, fake their POLLIN status */ wsi = pt->rx_draining_ext_list; while (wsi) { pt->fds[wsi->position_in_fds_table].revents |= pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN; if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN) forced = 1; wsi = wsi->u.ws.rx_draining_ext_list; } #ifdef LWS_OPENSSL_SUPPORT /* * 2) For all guys with buffered SSL read data already saved up, if they * are not flowcontrolled, fake their POLLIN status so they'll get * service to use up the buffered incoming data, even though their * network socket may have nothing */ wsi = pt->pending_read_list; while (wsi) { wsi_next = wsi->pending_read_list_next; pt->fds[wsi->position_in_fds_table].revents |= pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN; if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN) { forced = 1; /* * he's going to get serviced now, take him off the * list of guys with buffered SSL. If he still has some * at the end of the service, he'll get put back on the * list then. */ lws_ssl_remove_wsi_from_buffered_list(wsi); } wsi = wsi_next; } #endif /* * 3) For any wsi who have an ah with pending RX who did not * complete their current headers, and are not flowcontrolled, * fake their POLLIN status so they will be able to drain the * rx buffered in the ah */ for (n = 0; n < context->max_http_header_pool; n++) if (pt->ah_pool[n].rxpos != pt->ah_pool[n].rxlen && !pt->ah_pool[n].wsi->hdr_parsing_completed) { pt->fds[pt->ah_pool[n].wsi->position_in_fds_table].revents |= pt->fds[pt->ah_pool[n].wsi->position_in_fds_table].events & LWS_POLLIN; if (pt->fds[pt->ah_pool[n].wsi->position_in_fds_table].revents & LWS_POLLIN) forced = 1; } return forced; } #ifndef LWS_NO_CLIENT LWS_VISIBLE int lws_http_client_read(struct lws *wsi, char **buf, int *len) { int rlen, n; rlen = lws_ssl_capable_read(wsi, (unsigned char *)*buf, *len); if (rlen < 0) return -1; *len = rlen; if (rlen == 0) return 0; // lwsl_err("%s: read %d\n", __func__, rlen); /* allow the source to signal he has data again next time */ wsi->client_rx_avail = 0; lws_change_pollfd(wsi, 0, LWS_POLLIN); /* * server may insist on transfer-encoding: chunked, * so http client must deal with it */ spin_chunks: while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) { switch (wsi->chunk_parser) { case ELCP_HEX: if ((*buf)[0] == '\x0d') { wsi->chunk_parser = ELCP_CR; break; } n = char_to_hex((*buf)[0]); if (n < 0) return -1; wsi->chunk_remaining <<= 4; wsi->chunk_remaining |= n; break; case ELCP_CR: if ((*buf)[0] != '\x0a') return -1; wsi->chunk_parser = ELCP_CONTENT; lwsl_info("chunk %d\n", wsi->chunk_remaining); if (wsi->chunk_remaining) break; lwsl_info("final chunk\n"); goto completed; case ELCP_CONTENT: break; case ELCP_POST_CR: if ((*buf)[0] != '\x0d') return -1; wsi->chunk_parser = ELCP_POST_LF; break; case ELCP_POST_LF: if ((*buf)[0] != '\x0a') return -1; wsi->chunk_parser = ELCP_HEX; wsi->chunk_remaining = 0; break; } (*buf)++; (*len)--; } if (wsi->chunked && !wsi->chunk_remaining) return 0; if (wsi->u.http.content_remain && (int)wsi->u.http.content_remain < *len) n = wsi->u.http.content_remain; else n = *len; if (wsi->chunked && wsi->chunk_remaining && wsi->chunk_remaining < n) n = wsi->chunk_remaining; #ifdef LWS_WITH_HTTP_PROXY /* hubbub */ if (wsi->perform_rewrite) lws_rewrite_parse(wsi->rw, (unsigned char *)*buf, n); else #endif if (user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ, wsi->user_space, *buf, n)) return -1; if (wsi->chunked && wsi->chunk_remaining) { (*buf) += n; wsi->chunk_remaining -= n; *len -= n; } if (wsi->chunked && !wsi->chunk_remaining) wsi->chunk_parser = ELCP_POST_CR; if (wsi->chunked && *len) { goto spin_chunks; } if (wsi->chunked) return 0; wsi->u.http.content_remain -= n; if (wsi->u.http.content_remain || !wsi->u.http.content_length) return 0; completed: if (user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP, wsi->user_space, NULL, 0)) return -1; if (lws_http_transaction_completed_client(wsi)) return -1; return 0; } #endif /** * lws_service_fd() - Service polled socket with something waiting * @context: Websocket context * @pollfd: The pollfd entry describing the socket fd and which events * happened. * * This function takes a pollfd that has POLLIN or POLLOUT activity and * services it according to the state of the associated * struct lws. * * The one call deals with all "service" that might happen on a socket * including listen accepts, http files as well as websocket protocol. * * If a pollfd says it has something, you can just pass it to * lws_service_fd() whether it is a socket handled by lws or not. * If it sees it is a lws socket, the traffic will be handled and * pollfd->revents will be zeroed now. * * If the socket is foreign to lws, it leaves revents alone. So you can * see if you should service yourself by checking the pollfd revents * after letting lws try to service it. */ LWS_VISIBLE int lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; lws_sockfd_type our_fd = 0, tmp_fd; struct lws_tokens eff_buf; unsigned int pending = 0; struct lws *wsi, *wsi1; char draining_flow = 0; int timed_out = 0; time_t now; int n = 0, m; int more; if (!context->protocol_init_done) lws_protocol_init(context); /* * you can call us with pollfd = NULL to just allow the once-per-second * global timeout checks; if less than a second since the last check * it returns immediately then. */ time(&now); /* TODO: if using libev, we should probably use timeout watchers... */ if (context->last_timeout_check_s != now) { context->last_timeout_check_s = now; lws_plat_service_periodic(context); /* global timeout check once per second */ if (pollfd) our_fd = pollfd->fd; wsi = context->pt[tsi].timeout_list; while (wsi) { /* we have to take copies, because he may be deleted */ wsi1 = wsi->timeout_list; tmp_fd = wsi->sock; if (lws_service_timeout_check(wsi, (unsigned int)now)) { /* he did time out... */ if (tmp_fd == our_fd) /* it was the guy we came to service! */ timed_out = 1; /* he's gone, no need to mark as handled */ } wsi = wsi1; } #ifdef LWS_WITH_CGI lws_cgi_kill_terminated(pt); #endif #if 0 { char s[300], *p = s; for (n = 0; n < context->count_threads; n++) p += sprintf(p, " %7lu (%5d), ", context->pt[n].count_conns, context->pt[n].fds_count); lwsl_notice("load: %s\n", s); } #endif } /* the socket we came to service timed out, nothing to do */ if (timed_out) return 0; /* just here for timeout management? */ if (!pollfd) return 0; /* no, here to service a socket descriptor */ wsi = wsi_from_fd(context, pollfd->fd); if (!wsi) /* not lws connection ... leave revents alone and return */ return 0; /* * so that caller can tell we handled, past here we need to * zero down pollfd->revents after handling */ #if LWS_POSIX /* handle session socket closed */ if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) && (pollfd->revents & LWS_POLLHUP)) { wsi->socket_is_permanently_unusable = 1; lwsl_debug("Session Socket %p (fd=%d) dead\n", (void *)wsi, pollfd->fd); goto close_and_handled; } #ifdef _WIN32 if (pollfd->revents & LWS_POLLOUT) wsi->sock_send_blocking = FALSE; #endif #endif lwsl_debug("fd=%d, revents=%d\n", pollfd->fd, pollfd->revents); /* okay, what we came here to do... */ switch (wsi->mode) { case LWSCM_HTTP_SERVING: case LWSCM_HTTP_CLIENT: case LWSCM_HTTP_SERVING_ACCEPTED: case LWSCM_SERVER_LISTENER: case LWSCM_SSL_ACK_PENDING: if (wsi->state == LWSS_CLIENT_HTTP_ESTABLISHED) goto handled; #ifdef LWS_WITH_CGI if (wsi->cgi && (pollfd->revents & LWS_POLLOUT)) { n = lws_handle_POLLOUT_event(wsi, pollfd); if (n) goto close_and_handled; goto handled; } #endif n = lws_server_socket_service(context, wsi, pollfd); if (n) /* closed by above */ return 1; goto handled; case LWSCM_WS_SERVING: case LWSCM_WS_CLIENT: case LWSCM_HTTP2_SERVING: case LWSCM_HTTP_CLIENT_ACCEPTED: /* 1: something requested a callback when it was OK to write */ if ((pollfd->revents & LWS_POLLOUT) && (wsi->state == LWSS_ESTABLISHED || wsi->state == LWSS_HTTP2_ESTABLISHED || wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS || wsi->state == LWSS_RETURNED_CLOSE_ALREADY || wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) && lws_handle_POLLOUT_event(wsi, pollfd)) { if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY) wsi->state = LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE; lwsl_info("lws_service_fd: closing\n"); goto close_and_handled; } if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY || wsi->state == LWSS_AWAITING_CLOSE_ACK) { /* * we stopped caring about anything except control * packets. Force flow control off, defeat tx * draining. */ lws_rx_flow_control(wsi, 1); wsi->u.ws.tx_draining_ext = 0; } if (wsi->u.ws.tx_draining_ext) /* we cannot deal with new RX until the TX ext * path has been drained. It's because new * rx will, eg, crap on the wsi rx buf that * may be needed to retain state. * * TX ext drain path MUST go through event loop * to avoid blocking. */ break; if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) /* We cannot deal with any kind of new RX * because we are RX-flowcontrolled. */ break; /* 2: RX Extension needs to be drained */ if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.rx_draining_ext) { lwsl_ext("%s: RX EXT DRAINING: Service\n", __func__); #ifndef LWS_NO_CLIENT if (wsi->mode == LWSCM_WS_CLIENT) { n = lws_client_rx_sm(wsi, 0); if (n < 0) /* we closed wsi */ n = 0; } else #endif n = lws_rx_sm(wsi, 0); goto handled; } if (wsi->u.ws.rx_draining_ext) /* * We have RX EXT content to drain, but can't do it * right now. That means we cannot do anything lower * priority either. */ break; /* 3: RX Flowcontrol buffer needs to be drained */ if (wsi->rxflow_buffer) { lwsl_info("draining rxflow (len %d)\n", wsi->rxflow_len - wsi->rxflow_pos ); /* well, drain it */ eff_buf.token = (char *)wsi->rxflow_buffer + wsi->rxflow_pos; eff_buf.token_len = wsi->rxflow_len - wsi->rxflow_pos; draining_flow = 1; goto drain; } /* 4: any incoming (or ah-stashed incoming rx) data ready? * notice if rx flow going off raced poll(), rx flow wins */ if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) break; read: /* all the union members start with hdr, so even in ws mode * we can deal with the ah via u.hdr */ if (wsi->u.hdr.ah) { lwsl_info("%s: %p: inherited ah rx\n", __func__, wsi); eff_buf.token_len = wsi->u.hdr.ah->rxlen - wsi->u.hdr.ah->rxpos; eff_buf.token = (char *)wsi->u.hdr.ah->rx + wsi->u.hdr.ah->rxpos; } else { if (wsi->mode != LWSCM_HTTP_CLIENT_ACCEPTED) { eff_buf.token_len = lws_ssl_capable_read(wsi, pt->serv_buf, pending ? pending : LWS_MAX_SOCKET_IO_BUF); switch (eff_buf.token_len) { case 0: lwsl_info("%s: zero length read\n", __func__); goto close_and_handled; case LWS_SSL_CAPABLE_MORE_SERVICE: lwsl_info("SSL Capable more service\n"); n = 0; goto handled; case LWS_SSL_CAPABLE_ERROR: lwsl_info("Closing when error\n"); goto close_and_handled; } eff_buf.token = (char *)pt->serv_buf; } } drain: #ifndef LWS_NO_CLIENT if (wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED) { /* * simply mark ourselves as having readable data * and turn off our POLLIN */ wsi->client_rx_avail = 1; lws_change_pollfd(wsi, LWS_POLLIN, 0); /* let user code know, he'll usually ask for writeable * callback and drain / reenable it there */ if (user_callback_handle_rxflow( wsi->protocol->callback, wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP, wsi->user_space, NULL, 0)) goto close_and_handled; } #endif /* * give any active extensions a chance to munge the buffer * before parse. We pass in a pointer to an lws_tokens struct * prepared with the default buffer and content length that's in * there. Rather than rewrite the default buffer, extensions * that expect to grow the buffer can adapt .token to * point to their own per-connection buffer in the extension * user allocation. By default with no extensions or no * extension callback handling, just the normal input buffer is * used then so it is efficient. */ do { more = 0; m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_RX_PREPARSE, &eff_buf, 0); if (m < 0) goto close_and_handled; if (m) more = 1; /* service incoming data */ if (eff_buf.token_len) { /* * if draining from rxflow buffer, not * critical to track what was used since at the * use it bumps wsi->rxflow_pos. If we come * around again it will pick up from where it * left off. */ n = lws_read(wsi, (unsigned char *)eff_buf.token, eff_buf.token_len); if (n < 0) { /* we closed wsi */ n = 0; goto handled; } } eff_buf.token = NULL; eff_buf.token_len = 0; } while (more); if (wsi->u.hdr.ah) { lwsl_info("%s: %p: detaching inherited used ah\n", __func__, wsi); /* show we used all the pending rx up */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; /* we can run the normal ah detach flow despite * being in ws union mode, since all union members * start with hdr */ lws_header_table_detach(wsi, 0); } pending = lws_ssl_pending(wsi); if (pending) { pending = pending > LWS_MAX_SOCKET_IO_BUF ? LWS_MAX_SOCKET_IO_BUF : pending; goto read; } if (draining_flow && wsi->rxflow_buffer && wsi->rxflow_pos == wsi->rxflow_len) { lwsl_info("flow buffer: drained\n"); lws_free_set_NULL(wsi->rxflow_buffer); /* having drained the rxflow buffer, can rearm POLLIN */ #ifdef LWS_NO_SERVER n = #endif _lws_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */ } break; #ifdef LWS_WITH_CGI case LWSCM_CGI: /* we exist to handle a cgi's stdin/out/err data... * do the callback on our master wsi */ { struct lws_cgi_args args; if (wsi->cgi_channel >= LWS_STDOUT && !(pollfd->revents & pollfd->events & LWS_POLLIN)) break; if (wsi->cgi_channel == LWS_STDIN && !(pollfd->revents & pollfd->events & LWS_POLLOUT)) break; if (wsi->cgi_channel == LWS_STDIN) if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_info("failed at set pollfd\n"); return 1; } args.ch = wsi->cgi_channel; args.stdwsi = &wsi->parent->cgi->stdwsi[0]; args.hdr_state = wsi->hdr_state; //lwsl_err("CGI LWS_STDOUT waiting wsi %p mode %d state %d\n", // wsi->parent, wsi->parent->mode, wsi->parent->state); if (user_callback_handle_rxflow( wsi->parent->protocol->callback, wsi->parent, LWS_CALLBACK_CGI, wsi->parent->user_space, (void *)&args, 0)) return 1; break; } #endif default: #ifdef LWS_NO_CLIENT break; #else n = lws_client_socket_service(context, wsi, pollfd); if (n) return 1; goto handled; #endif } n = 0; goto handled; close_and_handled: lwsl_debug("Close and handled\n"); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); /* * pollfd may point to something else after the close * due to pollfd swapping scheme on delete on some platforms * we can't clear revents now because it'd be the wrong guy's revents */ return 1; handled: pollfd->revents = 0; return n; } LWS_VISIBLE int lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd) { return lws_service_fd_tsi(context, pollfd, 0); } /** * lws_service() - Service any pending websocket activity * @context: Websocket context * @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed * service otherwise block and service immediately, returning * after the timeout if nothing needed service. * * This function deals with any pending websocket traffic, for three * kinds of event. It handles these events on both server and client * types of connection the same. * * 1) Accept new connections to our context's server * * 2) Call the receive callback for incoming frame data received by * server or client connections. * * You need to call this service function periodically to all the above * functions to happen; if your application is single-threaded you can * just call it in your main event loop. * * Alternatively you can fork a new process that asynchronously handles * calling this service in a loop. In that case you are happy if this * call blocks your thread until it needs to take care of something and * would call it with a large nonzero timeout. Your loop then takes no * CPU while there is nothing happening. * * If you are calling it in a single-threaded app, you don't want it to * wait around blocking other things in your loop from happening, so you * would call it with a timeout_ms of 0, so it returns immediately if * nothing is pending, or as soon as it services whatever was pending. */ LWS_VISIBLE int lws_service(struct lws_context *context, int timeout_ms) { return lws_plat_service(context, timeout_ms); } LWS_VISIBLE int lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi) { return lws_plat_service_tsi(context, timeout_ms, tsi); } |
Added undroid/libwebsockets/lib/sha-1.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * FIPS pub 180-1: Secure Hash Algorithm (SHA-1) * based on: http://csrc.nist.gov/fips/fip180-1.txt * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org> */ #include "private-libwebsockets.h" #ifdef LWS_HAVE_SYS_TYPES_H #include <sys/types.h> #endif struct sha1_ctxt { union { unsigned char b8[20]; unsigned int b32[5]; } h; union { unsigned char b8[8]; u_int64_t b64[1]; } c; union { unsigned char b8[64]; unsigned int b32[16]; } m; unsigned char count; }; /* sanity check */ #if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) # define unsupported 1 #elif BYTE_ORDER != BIG_ENDIAN # if BYTE_ORDER != LITTLE_ENDIAN # define unsupported 1 # endif #endif #ifndef unsupported /* constant table */ static const unsigned int _K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; #define K(t) _K[(t) / 20] #define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d))) #define F1(b, c, d) (((b) ^ (c)) ^ (d)) #define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d))) #define F3(b, c, d) (((b) ^ (c)) ^ (d)) #define S(n, x) (((x) << (n)) | ((x) >> (32 - n))) #define H(n) (ctxt->h.b32[(n)]) #define COUNT (ctxt->count) #define BCOUNT (ctxt->c.b64[0] / 8) #define W(n) (ctxt->m.b32[(n)]) #define PUTBYTE(x) { \ ctxt->m.b8[(COUNT % 64)] = (x); \ COUNT++; \ COUNT %= 64; \ ctxt->c.b64[0] += 8; \ if (COUNT % 64 == 0) \ sha1_step(ctxt); \ } #define PUTPAD(x) { \ ctxt->m.b8[(COUNT % 64)] = (x); \ COUNT++; \ COUNT %= 64; \ if (COUNT % 64 == 0) \ sha1_step(ctxt); \ } static void sha1_step(struct sha1_ctxt *ctxt) { unsigned int a, b, c, d, e, tmp; size_t t, s; #if BYTE_ORDER == LITTLE_ENDIAN struct sha1_ctxt tctxt; memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64); ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2]; ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0]; ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6]; ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4]; ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10]; ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8]; ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14]; ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12]; ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18]; ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16]; ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22]; ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20]; ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26]; ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24]; ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30]; ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28]; ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34]; ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32]; ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38]; ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36]; ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42]; ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40]; ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46]; ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44]; ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50]; ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48]; ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54]; ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52]; ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58]; ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56]; ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62]; ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60]; #endif a = H(0); b = H(1); c = H(2); d = H(3); e = H(4); for (t = 0; t < 20; t++) { s = t & 0x0f; if (t >= 16) W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } for (t = 20; t < 40; t++) { s = t & 0x0f; W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } for (t = 40; t < 60; t++) { s = t & 0x0f; W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } for (t = 60; t < 80; t++) { s = t & 0x0f; W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s)); tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t); e = d; d = c; c = S(30, b); b = a; a = tmp; } H(0) = H(0) + a; H(1) = H(1) + b; H(2) = H(2) + c; H(3) = H(3) + d; H(4) = H(4) + e; bzero(&ctxt->m.b8[0], 64); } /*------------------------------------------------------------*/ static void _sha1_init(struct sha1_ctxt *ctxt) { bzero(ctxt, sizeof(struct sha1_ctxt)); H(0) = 0x67452301; H(1) = 0xefcdab89; H(2) = 0x98badcfe; H(3) = 0x10325476; H(4) = 0xc3d2e1f0; } void sha1_pad(struct sha1_ctxt *ctxt) { size_t padlen; /*pad length in bytes*/ size_t padstart; PUTPAD(0x80); padstart = COUNT % 64; padlen = 64 - padstart; if (padlen < 8) { bzero(&ctxt->m.b8[padstart], padlen); COUNT += (unsigned char)padlen; COUNT %= 64; sha1_step(ctxt); padstart = COUNT % 64; /* should be 0 */ padlen = 64 - padstart; /* should be 64 */ } bzero(&ctxt->m.b8[padstart], padlen - 8); COUNT += ((unsigned char)padlen - 8); COUNT %= 64; #if BYTE_ORDER == BIG_ENDIAN PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]); #else PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]); #endif } void sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len) { size_t gaplen; size_t gapstart; size_t off; size_t copysiz; off = 0; while (off < len) { gapstart = COUNT % 64; gaplen = 64 - gapstart; copysiz = (gaplen < len - off) ? gaplen : len - off; memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz); COUNT += (unsigned char)copysiz; COUNT %= 64; ctxt->c.b64[0] += copysiz * 8; if (COUNT % 64 == 0) sha1_step(ctxt); off += copysiz; } } void sha1_result(struct sha1_ctxt *ctxt, void *digest0) { unsigned char *digest; digest = (unsigned char *)digest0; sha1_pad(ctxt); #if BYTE_ORDER == BIG_ENDIAN memcpy(digest, &ctxt->h.b8[0], 20); #else digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2]; digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0]; digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6]; digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4]; digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10]; digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8]; digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14]; digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12]; digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18]; digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16]; #endif } /* * This should look and work like the libcrypto implementation */ LWS_VISIBLE unsigned char * lws_SHA1(const unsigned char *d, size_t n, unsigned char *md) { struct sha1_ctxt ctx; _sha1_init(&ctx); sha1_loop(&ctx, d, n); sha1_result(&ctx, (void *)md); return md; } #endif /*unsupported*/ |
Added undroid/libwebsockets/lib/ssl-client.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" extern int openssl_websocket_private_data_index, openssl_SSL_CTX_private_data_index; extern void lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info); extern int lws_ssl_get_error(struct lws *wsi, int n); int lws_ssl_client_bio_create(struct lws *wsi) { #if defined(LWS_USE_POLARSSL) return 0; #else #if defined(LWS_USE_MBEDTLS) #else struct lws_context *context = wsi->context; const char *hostname = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST); X509_VERIFY_PARAM *param; (void)hostname; (void)param; wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx); if (!wsi->ssl) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(lws_ssl_get_error(wsi, 0), NULL)); lws_decode_ssl_error(); return -1; } #if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host param = SSL_get0_param(wsi->ssl); /* Enable automatic hostname checks */ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, hostname, 0); /* Configure a non-zero callback if desired */ SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, 0); #endif #ifndef USE_WOLFSSL SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #endif /* * use server name indication (SNI), if supported, * when establishing connection */ #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL #ifdef CYASSL_SNI_HOST_NAME CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname)); #endif #else #ifdef WOLFSSL_SNI_HOST_NAME wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname)); #endif #endif #else #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_set_tlsext_host_name(wsi->ssl, hostname); #endif #endif #ifdef USE_WOLFSSL /* * wolfSSL/CyaSSL does certificate verification differently * from OpenSSL. * If we should ignore the certificate, we need to set * this before SSL_new and SSL_connect is called. * Otherwise the connect will simply fail with error code -155 */ #ifdef USE_OLD_CYASSL if (wsi->use_ssl == 2) CyaSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL); #else if (wsi->use_ssl == 2) wolfSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL); #endif #endif /* USE_WOLFSSL */ wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE); SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio); #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->ssl, 1); #else wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */ #endif SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, context); return 0; #endif #endif } int lws_ssl_client_connect1(struct lws *wsi) { struct lws_context *context = wsi->context; int n = 0; lws_latency_pre(context, wsi); #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else n = SSL_connect(wsi->ssl); #endif #endif lws_latency(context, wsi, "SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE", n, n > 0); if (n < 0) { n = lws_ssl_get_error(wsi, n); if (n == SSL_ERROR_WANT_READ) goto some_wait; if (n == SSL_ERROR_WANT_WRITE) { /* * wants us to retry connect due to * state of the underlying ssl layer... * but since it may be stalled on * blocked write, no incoming data may * arrive to trigger the retry. * Force (possibly many times if the SSL * state persists in returning the * condition code, but other sockets * are getting serviced inbetweentimes) * us to get called back when writable. */ lwsl_info("%s: WANT_WRITE... retrying\n", __func__); lws_callback_on_writable(wsi); some_wait: wsi->mode = LWSCM_WSCL_WAITING_SSL; return 0; /* no error */ } n = -1; } if (n <= 0) { /* * retry if new data comes until we * run into the connection timeout or win */ #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else n = ERR_get_error(); if (n != SSL_ERROR_NONE) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; char *p = (char *)&pt->serv_buf[0]; char *sb = p; lwsl_err("SSL connect error %lu: %s\n", n, ERR_error_string(n, sb)); return -1; } #endif #endif } return 1; } int lws_ssl_client_connect2(struct lws *wsi) { struct lws_context *context = wsi->context; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; char *p = (char *)&pt->serv_buf[0]; char *sb = p; #endif #endif int n = 0; if (wsi->mode == LWSCM_WSCL_WAITING_SSL) { lws_latency_pre(context, wsi); #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else n = SSL_connect(wsi->ssl); #endif #endif lws_latency(context, wsi, "SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0); if (n < 0) { n = lws_ssl_get_error(wsi, n); if (n == SSL_ERROR_WANT_READ) { wsi->mode = LWSCM_WSCL_WAITING_SSL; return 0; /* no error */ } if (n == SSL_ERROR_WANT_WRITE) { /* * wants us to retry connect due to * state of the underlying ssl layer... * but since it may be stalled on * blocked write, no incoming data may * arrive to trigger the retry. * Force (possibly many times if the SSL * state persists in returning the * condition code, but other sockets * are getting serviced inbetweentimes) * us to get called back when writable. */ lwsl_info("SSL_connect WANT_WRITE... retrying\n"); lws_callback_on_writable(wsi); wsi->mode = LWSCM_WSCL_WAITING_SSL; return 0; /* no error */ } n = -1; } if (n <= 0) { /* * retry if new data comes until we * run into the connection timeout or win */ #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else n = ERR_get_error(); if (n != SSL_ERROR_NONE) { lwsl_err("SSL connect error %lu: %s\n", n, ERR_error_string(n, sb)); return -1; } #endif #endif } } #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #ifndef USE_WOLFSSL /* * See comment above about wolfSSL certificate * verification */ lws_latency_pre(context, wsi); n = SSL_get_verify_result(wsi->ssl); lws_latency(context, wsi, "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0); if (n != X509_V_OK) { if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) && wsi->use_ssl == 2) { lwsl_notice("accepting self-signed certificate\n"); } else { lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n", n, ERR_error_string(n, sb)); lws_ssl_elaborate_error(); return -1; } } #endif /* USE_WOLFSSL */ #endif #endif return 1; } int lws_context_init_client_ssl(struct lws_context_creation_info *info, struct lws_vhost *vhost) { #if defined(LWS_USE_POLARSSL) return 0; #else #if defined(LWS_USE_MBEDTLS) #else int error; int n; SSL_METHOD *method; struct lws wsi; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) return 0; if (info->provided_client_ssl_ctx) { /* use the provided OpenSSL context if given one */ vhost->ssl_client_ctx = info->provided_client_ssl_ctx; /* nothing for lib to delete */ vhost->user_supplied_ssl_ctx = 1; return 0; } if (info->port != CONTEXT_PORT_NO_LISTEN) return 0; /* basic openssl init */ SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); method = (SSL_METHOD *)SSLv23_client_method(); if (!method) { error = ERR_get_error(); lwsl_err("problem creating ssl method %lu: %s\n", error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } /* create context */ vhost->ssl_client_ctx = SSL_CTX_new(method); if (!vhost->ssl_client_ctx) { error = ERR_get_error(); lwsl_err("problem creating ssl context %lu: %s\n", error, ERR_error_string(error, (char *)vhost->context->pt[0].serv_buf)); return 1; } #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_NO_COMPRESSION); #endif SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->ssl_client_ctx, info->ssl_cipher_list); #ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) /* loads OS default CA certs */ SSL_CTX_set_default_verify_paths(vhost->ssl_client_ctx); #endif /* openssl init for cert verification (for client sockets) */ if (!info->ssl_ca_filepath) { if (!SSL_CTX_load_verify_locations( vhost->ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS)) lwsl_err( "Unable to load SSL Client certs from %s " "(set by --with-client-cert-dir= " "in configure) -- client ssl isn't " "going to work", LWS_OPENSSL_CLIENT_CERTS); } else if (!SSL_CTX_load_verify_locations( vhost->ssl_client_ctx, info->ssl_ca_filepath, NULL)) lwsl_err( "Unable to load SSL Client certs " "file from %s -- client ssl isn't " "going to work", info->ssl_ca_filepath); else lwsl_info("loaded ssl_ca_filepath\n"); /* * callback allowing user code to load extra verification certs * helping the client to verify server identity */ /* support for client-side certificate authentication */ if (info->ssl_cert_filepath) { n = SSL_CTX_use_certificate_chain_file(vhost->ssl_client_ctx, info->ssl_cert_filepath); if (n != 1) { lwsl_err("problem getting cert '%s' %lu: %s\n", info->ssl_cert_filepath, ERR_get_error(), ERR_error_string(ERR_get_error(), (char *)vhost->context->pt[0].serv_buf)); return 1; } } if (info->ssl_private_key_filepath) { lws_ssl_bind_passphrase(vhost->ssl_client_ctx, info); /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->ssl_client_ctx, info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { lwsl_err("use_PrivateKey_file '%s' %lu: %s\n", info->ssl_private_key_filepath, ERR_get_error(), ERR_error_string(ERR_get_error(), (char *)vhost->context->pt[0].serv_buf)); return 1; } /* verify private key */ if (!SSL_CTX_check_private_key(vhost->ssl_client_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); return 1; } } /* * give him a fake wsi with context set, so he can use * lws_get_context() in the callback */ memset(&wsi, 0, sizeof(wsi)); wsi.vhost = vhost; wsi.context = vhost->context; vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, vhost->ssl_client_ctx, NULL, 0); return 0; #endif #endif } |
Added undroid/libwebsockets/lib/ssl-http2.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * * Some or all of this file is based on code from nghttp2, which has the * following license. Since it's more liberal than lws license, you're also * at liberty to get the original code from * https://github.com/tatsuhiro-t/nghttp2 under his liberal terms alone. * * nghttp2 - HTTP/2.0 C Library * * Copyright (c) 2012 Tatsuhiro Tsujikawa * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "private-libwebsockets.h" #ifndef LWS_NO_SERVER #ifdef LWS_OPENSSL_SUPPORT #if OPENSSL_VERSION_NUMBER >= 0x10002000L struct alpn_ctx { unsigned char *data; unsigned short len; }; static int npn_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg) { struct alpn_ctx *alpn_ctx = arg; lwsl_info("%s\n", __func__); *data = alpn_ctx->data; *len = alpn_ctx->len; return SSL_TLSEXT_ERR_OK; } static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { struct alpn_ctx *alpn_ctx = arg; if (SSL_select_next_proto((unsigned char **)out, outlen, alpn_ctx->data, alpn_ctx->len, in, inlen) != OPENSSL_NPN_NEGOTIATED) return SSL_TLSEXT_ERR_NOACK; return SSL_TLSEXT_ERR_OK; } #endif LWS_VISIBLE void lws_context_init_http2_ssl(struct lws_vhost *vhost) { #if OPENSSL_VERSION_NUMBER >= 0x10002000L static struct alpn_ctx protos = { (unsigned char *)"\x02h2" "\x08http/1.1", 6 + 9 }; SSL_CTX_set_next_protos_advertised_cb(vhost->ssl_ctx, npn_cb, &protos); // ALPN selection callback SSL_CTX_set_alpn_select_cb(vhost->ssl_ctx, alpn_cb, &protos); lwsl_notice(" HTTP2 / ALPN enabled\n"); #else lwsl_notice( " HTTP2 / ALPN configured but not supported by OpenSSL 0x%x\n", OPENSSL_VERSION_NUMBER); #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L } void lws_http2_configure_if_upgraded(struct lws *wsi) { #if OPENSSL_VERSION_NUMBER >= 0x10002000L struct allocated_headers *ah; const char *method = "alpn"; const unsigned char *name; unsigned len; SSL_get0_alpn_selected(wsi->ssl, &name, &len); if (!len) { SSL_get0_next_proto_negotiated(wsi->ssl, &name, &len); method = "npn"; } if (!len) { lwsl_info("no npn/alpn upgrade\n"); return; } (void)method; lwsl_info("negotiated %s using %s\n", name, method); wsi->use_ssl = 1; if (strncmp((char *)name, "http/1.1", 8) == 0) return; /* http2 */ /* adopt the header info */ ah = wsi->u.hdr.ah; lws_union_transition(wsi, LWSCM_HTTP2_SERVING); wsi->state = LWSS_HTTP2_AWAIT_CLIENT_PREFACE; /* http2 union member has http union struct at start */ wsi->u.http.ah = ah; lws_http2_init(&wsi->u.http2.peer_settings); lws_http2_init(&wsi->u.http2.my_settings); /* HTTP2 union */ #endif } #endif #endif |
Added undroid/libwebsockets/lib/ssl-server.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else extern int openssl_websocket_private_data_index, openssl_SSL_CTX_private_data_index; extern void lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info); static int OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { SSL *ssl; int n; struct lws_vhost *vh; struct lws wsi; ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); /* * !!! nasty openssl requires the index to come as a library-scope * static */ vh = SSL_get_ex_data(ssl, openssl_websocket_private_data_index); /* * give him a fake wsi with context set, so he can use lws_get_context() * in the callback */ memset(&wsi, 0, sizeof(wsi)); wsi.vhost = vh; wsi.context = vh->context; n = vh->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, x509_ctx, ssl, preverify_ok); /* convert return code from 0 = OK to 1 = OK */ return !n; } static int lws_context_ssl_init_ecdh(struct lws_vhost *vhost) { #ifdef LWS_SSL_SERVER_WITH_ECDH_CERT EC_KEY *EC_key = NULL; EVP_PKEY *pkey; int KeyType; X509 *x; if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH)) return 0; lwsl_notice(" Using ECDH certificate support\n"); /* Get X509 certificate from ssl context */ x = sk_X509_value(vhost->ssl_ctx->extra_certs, 0); if (!x) { lwsl_err("%s: x is NULL\n", __func__); return 1; } /* Get the public key from certificate */ pkey = X509_get_pubkey(x); if (!pkey) { lwsl_err("%s: pkey is NULL\n", __func__); return 1; } /* Get the key type */ KeyType = EVP_PKEY_type(pkey->type); if (EVP_PKEY_EC != KeyType) { lwsl_notice("Key type is not EC\n"); return 0; } /* Get the key */ EC_key = EVP_PKEY_get1_EC_KEY(pkey); /* Set ECDH parameter */ if (!EC_key) { lwsl_err("%s: ECDH key is NULL \n", __func__); return 1; } SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, EC_key); EC_KEY_free(EC_key); #endif return 0; } static int lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info, struct lws_vhost *vhost) { #ifdef LWS_HAVE_OPENSSL_ECDH_H EC_KEY *ecdh; int ecdh_nid; const char *ecdh_curve = "prime256v1"; if (info->ecdh_curve) ecdh_curve = info->ecdh_curve; ecdh_nid = OBJ_sn2nid(ecdh_curve); if (NID_undef == ecdh_nid) { lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve); return 1; } ecdh = EC_KEY_new_by_curve_name(ecdh_nid); if (NULL == ecdh) { lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve); return 1; } SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, ecdh); EC_KEY_free(ecdh); SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_ECDH_USE); lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve); #else lwsl_notice(" OpenSSL doesn't support ECDH\n"); #endif return 0; } #ifndef OPENSSL_NO_TLSEXT static int lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg) { struct lws_context *context; struct lws_vhost *vhost, *vh; const char *servername; int port; if (!ssl) return SSL_TLSEXT_ERR_NOACK; context = (struct lws_context *)SSL_CTX_get_ex_data( SSL_get_SSL_CTX(ssl), openssl_SSL_CTX_private_data_index); /* * We can only get ssl accepted connections by using a vhost's ssl_ctx * find out which listening one took us and only match vhosts on the * same port. */ vh = context->vhost_list; while (vh) { if (vh->ssl_ctx == SSL_get_SSL_CTX(ssl)) break; vh = vh->vhost_next; } assert(vh); /* we cannot get an ssl without using a vhost ssl_ctx */ port = vh->listen_port; servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername) { vhost = lws_select_vhost(context, port, servername); if (vhost) { lwsl_debug("SNI: Found: %s (port %d)\n", servername, port); SSL_set_SSL_CTX(ssl, vhost->ssl_ctx); return SSL_TLSEXT_ERR_OK; } lwsl_err("SNI: Unknown ServerName: %s\n", servername); } return SSL_TLSEXT_ERR_OK; } #endif #endif #endif LWS_VISIBLE int lws_context_init_server_ssl(struct lws_context_creation_info *info, struct lws_vhost *vhost) { struct lws_context *context = vhost->context; struct lws wsi; int error; int n; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) { vhost->use_ssl = 0; return 0; } if (info->port != CONTEXT_PORT_NO_LISTEN) { vhost->use_ssl = info->ssl_cert_filepath != NULL; if (vhost->use_ssl && info->ssl_cipher_list) lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list); if (vhost->use_ssl) lwsl_notice(" Using SSL mode\n"); else lwsl_notice(" Using non-SSL mode\n"); } /* * give him a fake wsi with context + vhost set, so he can use * lws_get_context() in the callback */ memset(&wsi, 0, sizeof(wsi)); wsi.vhost = vhost; wsi.context = context; (void)n; (void)error; #if defined(LWS_USE_POLARSSL) lwsl_notice(" Compiled with PolarSSL support\n"); vhost->ssl_ctx = lws_zalloc(sizeof (*vhost->ssl_ctx)); /* Load the trusted CA */ if (info->ssl_ca_filepath) { n = x509_crt_parse_file(&vhost->ssl_ctx->ca, info->ssl_ca_filepath); if (n < 0) { // error_strerror(ret, errorbuf, sizeof(errorbuf)); lwsl_err("%s: Failed to load ca cert\n", __func__); return -1; } } /* Load our cert */ if (info->ssl_cert_filepath) { n = x509_crt_parse_file(&vhost->ssl_ctx->certificate, info->ssl_cert_filepath); if (n < 0) { // error_strerror(ret, errorbuf, sizeof(errorbuf)); lwsl_err("%s: Failed to load cert\n", __func__); return -1; } } /* Load cert private key */ if (info->ssl_private_key_filepath) { pk_context pk; pk_init(&pk); n = pk_parse_keyfile(&pk, info->ssl_private_key_filepath, info->ssl_private_key_password); if (!n && !pk_can_do(&pk, POLARSSL_PK_RSA)) n = POLARSSL_ERR_PK_TYPE_MISMATCH; if (!n) rsa_copy(&vhost->ssl_ctx->key, pk_rsa(pk)); else rsa_free(&vhost->ssl_ctx->key); pk_free(&pk); if (n) { //error_strerror(ret, errorbuf, sizeof(errorbuf)); lwsl_err("%s: error reading private key\n", __func__); return -1; } } #else #if defined(LWS_USE_MBEDTLS) lwsl_notice(" Compiled with mbedTLS support\n"); #else /* * Firefox insists on SSLv23 not SSLv3 * Konq disables SSLv2 by default now, SSLv23 works * * SSLv23_server_method() is the openssl method for "allow all TLS * versions", compared to e.g. TLSv1_2_server_method() which only allows * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options() */ { SSL_METHOD *method; method = (SSL_METHOD *)SSLv23_server_method(); if (!method) { error = ERR_get_error(); lwsl_err("problem creating ssl method %lu: %s\n", error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } vhost->ssl_ctx = SSL_CTX_new(method); /* create context */ if (!vhost->ssl_ctx) { error = ERR_get_error(); lwsl_err("problem creating ssl context %lu: %s\n", error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } } /* associate the lws context with the SSL_CTX */ SSL_CTX_set_ex_data(vhost->ssl_ctx, openssl_SSL_CTX_private_data_index, vhost->context); /* Disable SSLv2 and SSLv3 */ SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION); #endif SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (info->ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->ssl_ctx, info->ssl_cipher_list); /* as a server, are we requiring clients to identify themselves? */ if (lws_check_opt(info->options, LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) { int verify_options = SSL_VERIFY_PEER; if (!lws_check_opt(info->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; SSL_CTX_set_session_id_context(vhost->ssl_ctx, (unsigned char *)context, sizeof(void *)); /* absolutely require the client cert */ SSL_CTX_set_verify(vhost->ssl_ctx, verify_options, OpenSSL_verify_callback); } #ifndef OPENSSL_NO_TLSEXT SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx, lws_ssl_server_name_cb); #endif /* * give user code a chance to load certs into the server * allowing it to verify incoming client certs */ if (info->ssl_ca_filepath && !SSL_CTX_load_verify_locations(vhost->ssl_ctx, info->ssl_ca_filepath, NULL)) { lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__); } if (vhost->use_ssl) { if (lws_context_ssl_init_ecdh_curve(info, vhost)) return -1; vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, vhost->ssl_ctx, NULL, 0); } if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT)) /* Normally SSL listener rejects non-ssl, optionally allow */ vhost->allow_non_ssl_on_ssl_port = 1; if (vhost->use_ssl) { /* openssl init for server sockets */ /* set the local certificate from CertFile */ n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx, info->ssl_cert_filepath); if (n != 1) { error = ERR_get_error(); lwsl_err("problem getting cert '%s' %lu: %s\n", info->ssl_cert_filepath, error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } lws_ssl_bind_passphrase(vhost->ssl_ctx, info); if (info->ssl_private_key_filepath != NULL) { /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx, info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { error = ERR_get_error(); lwsl_err("ssl problem getting key '%s' %lu: %s\n", info->ssl_private_key_filepath, error, ERR_error_string(error, (char *)context->pt[0].serv_buf)); return 1; } } else if (vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, vhost->ssl_ctx, NULL, 0)) { lwsl_err("ssl private key not set\n"); return 1; } /* verify private key */ if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); return 1; } if (lws_context_ssl_init_ecdh(vhost)) return 1; /* * SSL is happy and has a cert it's content with * If we're supporting HTTP2, initialize that */ lws_context_init_http2_ssl(vhost); } #endif #endif return 0; } |
Added undroid/libwebsockets/lib/ssl.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "private-libwebsockets.h" #if defined(LWS_USE_POLARSSL) static const int ciphers[] = { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, 0 }; static int urandom_bytes(void *ctx, unsigned char *dest, size_t len) { int cur; int fd = open("/dev/urandom", O_RDONLY); while (len) { cur = read(fd, dest, len); if (cur < 0) continue; len -= cur; } close(fd); return 0; } static void pssl_debug(void *ctx, int level, const char *str) { lwsl_err("PolarSSL [level %d]: %s", level, str); } #endif int openssl_websocket_private_data_index, openssl_SSL_CTX_private_data_index; int lws_ssl_get_error(struct lws *wsi, int n) { #if defined(LWS_USE_POLARSSL) #define ERR_error_string(a, b) "" return n; #else #if defined(LWS_USE_MBEDTLS) return n; #else return SSL_get_error(wsi->ssl, n); #endif #endif } void lws_ssl_elaborate_error(void) { #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else char buf[256]; u_long err; while ((err = ERR_get_error()) != 0) { ERR_error_string_n(err, buf, sizeof(buf)); lwsl_err("*** %s\n", buf); } #endif #endif } #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else static int lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata) { struct lws_context_creation_info * info = (struct lws_context_creation_info *)userdata; strncpy(buf, info->ssl_private_key_password, size); buf[size - 1] = '\0'; return strlen(buf); } #endif #endif void lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info) { if (!info->ssl_private_key_password) return; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else /* * password provided, set ssl callback and user data * for checking password which will be trigered during * SSL_CTX_use_PrivateKey_file function */ SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info); SSL_CTX_set_default_passwd_cb(ssl_ctx, lws_context_init_ssl_pem_passwd_cb); #endif #endif } int lws_context_init_ssl_library(struct lws_context_creation_info *info) { #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL lwsl_notice(" Compiled with CyaSSL support\n"); #else lwsl_notice(" Compiled with wolfSSL support\n"); #endif #else #if defined(LWS_USE_POLARSSL) lwsl_notice(" Compiled with PolarSSL support\n"); #else #if defined(LWS_USE_MBEDTLS) lwsl_notice(" Compiled with mbedTLS support\n"); #else lwsl_notice(" Compiled with OpenSSL support\n"); #endif #endif #endif if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) { lwsl_notice(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n"); return 0; } /* basic openssl init */ #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); openssl_websocket_private_data_index = SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL); openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL); #endif #endif return 0; } LWS_VISIBLE void lws_ssl_destroy(struct lws_vhost *vhost) { if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) return; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else if (vhost->ssl_ctx) SSL_CTX_free(vhost->ssl_ctx); if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx) SSL_CTX_free(vhost->ssl_client_ctx); #if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL) ERR_remove_state(0); #else #if (OPENSSL_VERSION_NUMBER >= 0x10100005L) && \ !defined(LIBRESSL_VERSION_NUMBER) && \ !defined(OPENSSL_IS_BORINGSSL) ERR_remove_thread_state(); #else ERR_remove_thread_state(NULL); #endif #endif ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif #endif } LWS_VISIBLE void lws_decode_ssl_error(void) { #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else char buf[256]; u_long err; while ((err = ERR_get_error()) != 0) { ERR_error_string_n(err, buf, sizeof(buf)); lwsl_err("*** %lu %s\n", err, buf); } #endif #endif } LWS_VISIBLE void lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; if (!wsi->pending_read_list_prev && !wsi->pending_read_list_next && pt->pending_read_list != wsi) /* we are not on the list */ return; /* point previous guy's next to our next */ if (!wsi->pending_read_list_prev) pt->pending_read_list = wsi->pending_read_list_next; else wsi->pending_read_list_prev->pending_read_list_next = wsi->pending_read_list_next; /* point next guy's previous to our previous */ if (wsi->pending_read_list_next) wsi->pending_read_list_next->pending_read_list_prev = wsi->pending_read_list_prev; wsi->pending_read_list_prev = NULL; wsi->pending_read_list_next = NULL; } LWS_VISIBLE int lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n = 0; if (!wsi->ssl) return lws_ssl_capable_read_no_ssl(wsi, buf, len); #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else n = SSL_read(wsi->ssl, buf, len); #endif #endif /* manpage: returning 0 means connection shut down */ if (!n) return LWS_SSL_CAPABLE_ERROR; if (n < 0) { n = lws_ssl_get_error(wsi, n); if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) return LWS_SSL_CAPABLE_MORE_SERVICE; return LWS_SSL_CAPABLE_ERROR; } if (wsi->vhost) wsi->vhost->rx += n; /* * if it was our buffer that limited what we read, * check if SSL has additional data pending inside SSL buffers. * * Because these won't signal at the network layer with POLLIN * and if we don't realize, this data will sit there forever */ if (n != len) goto bail; if (!wsi->ssl) goto bail; #if defined(LWS_USE_POLARSSL) if (ssl_get_bytes_avail(wsi->ssl) <= 0) goto bail; #else #if defined(LWS_USE_MBEDTLS) #else if (!SSL_pending(wsi->ssl)) goto bail; #endif #endif if (wsi->pending_read_list_next) return n; if (wsi->pending_read_list_prev) return n; if (pt->pending_read_list == wsi) return n; /* add us to the linked list of guys with pending ssl */ if (pt->pending_read_list) pt->pending_read_list->pending_read_list_prev = wsi; wsi->pending_read_list_next = pt->pending_read_list; wsi->pending_read_list_prev = NULL; pt->pending_read_list = wsi; return n; bail: lws_ssl_remove_wsi_from_buffered_list(wsi); return n; } LWS_VISIBLE int lws_ssl_pending(struct lws *wsi) { if (!wsi->ssl) return 0; #if defined(LWS_USE_POLARSSL) return ssl_get_bytes_avail(wsi->ssl) > 0; #else #if defined(LWS_USE_MBEDTLS) return ssl_get_bytes_avail(wsi->ssl) > 0;; #else return SSL_pending(wsi->ssl); #endif #endif } LWS_VISIBLE int lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len) { int n; if (!wsi->ssl) return lws_ssl_capable_write_no_ssl(wsi, buf, len); #if defined(LWS_USE_POLARSSL) n = ssl_write(wsi->ssl, buf, len); #else #if defined(LWS_USE_MBEDTLS) #else n = SSL_write(wsi->ssl, buf, len); #endif #endif if (n > 0) return n; n = lws_ssl_get_error(wsi, n); if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) { if (n == SSL_ERROR_WANT_WRITE) lws_set_blocking_send(wsi); return LWS_SSL_CAPABLE_MORE_SERVICE; } return LWS_SSL_CAPABLE_ERROR; } LWS_VISIBLE int lws_ssl_close(struct lws *wsi) { int n; if (!wsi->ssl) return 0; /* not handled */ #if defined(LWS_USE_POLARSSL) ssl_close_notify(wsi->ssl); (void)n; /* we need to close the fd? */ ssl_free(wsi->ssl); #else #if defined(LWS_USE_MBEDTLS) #else n = SSL_get_fd(wsi->ssl); SSL_shutdown(wsi->ssl); compatible_close(n); SSL_free(wsi->ssl); #endif #endif wsi->ssl = NULL; return 1; /* handled */ } /* leave all wsi close processing to the caller */ LWS_VISIBLE int lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; int n, m; #if !defined(USE_WOLFSSL) && !defined(LWS_USE_POLARSSL) && !defined(LWS_USE_MBEDTLS) BIO *bio; #endif if (!LWS_SSL_ENABLED(wsi->vhost)) return 0; switch (wsi->mode) { case LWSCM_SSL_INIT: if (wsi->ssl) lwsl_err("%s: leaking ssl\n", __func__); if (accept_fd == LWS_SOCK_INVALID) assert(0); #if defined(LWS_USE_POLARSSL) { ssl_session *ssn; int rc; wsi->ssl = lws_zalloc(sizeof(ssl_context)); ssn = lws_zalloc(sizeof(ssl_session)); rc = ssl_init(wsi->ssl); if (rc) { lwsl_err("ssl_init failed\n"); goto fail; } ssl_set_endpoint(wsi->ssl, SSL_IS_SERVER); ssl_set_authmode(wsi->ssl, SSL_VERIFY_OPTIONAL); ssl_set_rng(wsi->ssl, urandom_bytes, NULL); ssl_set_dbg(wsi->ssl, pssl_debug, NULL); ssl_set_bio(wsi->ssl, net_recv, &wsi->sock, net_send, &wsi->sock); ssl_set_ciphersuites(wsi->ssl, ciphers); ssl_set_session(wsi->ssl, ssn); ssl_set_ca_chain(wsi->ssl, &wsi->vhost->ssl_ctx->ca, NULL, NULL); ssl_set_own_cert_rsa(wsi->ssl, &wsi->vhost->ssl_ctx->certificate, &wsi->vhost->ssl_ctx->key); // ssl_set_dh_param(wsi->ssl, my_dhm_P, my_dhm_G); lwsl_err("%s: polarssl init done\n", __func__); } #else #if defined(LWS_USE_MBEDTLS) #else wsi->ssl = SSL_new(wsi->vhost->ssl_ctx); if (wsi->ssl == NULL) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(lws_ssl_get_error(wsi, 0), NULL)); lws_decode_ssl_error(); if (accept_fd != LWS_SOCK_INVALID) compatible_close(accept_fd); goto fail; } SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi->vhost); SSL_set_fd(wsi->ssl, accept_fd); #endif #endif #ifdef USE_WOLFSSL #ifdef USE_OLD_CYASSL CyaSSL_set_using_nonblock(wsi->ssl, 1); #else wolfSSL_set_using_nonblock(wsi->ssl, 1); #endif #else #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); bio = SSL_get_rbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); bio = SSL_get_wbio(wsi->ssl); if (bio) BIO_set_nbio(bio, 1); /* nonblocking */ else lwsl_notice("NULL rbio\n"); #endif #endif #endif /* * we are not accepted yet, but we need to enter ourselves * as a live connection. That way we can retry when more * pieces come if we're not sorted yet */ wsi->mode = LWSCM_SSL_ACK_PENDING; if (insert_wsi_socket_into_fds(context, wsi)) { lwsl_err("%s: failed to insert into fds\n", __func__); goto fail; } lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT, context->timeout_secs); lwsl_info("inserted SSL accept into fds, trying SSL_accept\n"); /* fallthru */ case LWSCM_SSL_ACK_PENDING: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_err("%s: lws_change_pollfd failed\n", __func__); goto fail; } lws_latency_pre(context, wsi); n = recv(wsi->sock, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF, MSG_PEEK); /* * optionally allow non-SSL connect on SSL listening socket * This is disabled by default, if enabled it goes around any * SSL-level access control (eg, client-side certs) so leave * it disabled unless you know it's not a problem for you */ if (wsi->vhost->allow_non_ssl_on_ssl_port) { if (n >= 1 && pt->serv_buf[0] >= ' ') { /* * TLS content-type for Handshake is 0x16, and * for ChangeCipherSpec Record, it's 0x14 * * A non-ssl session will start with the HTTP * method in ASCII. If we see it's not a legit * SSL handshake kill the SSL for this * connection and try to handle as a HTTP * connection upgrade directly. */ wsi->use_ssl = 0; #if defined(LWS_USE_POLARSSL) ssl_close_notify(wsi->ssl); ssl_free(wsi->ssl); #else #if defined(LWS_USE_MBEDTLS) #else SSL_shutdown(wsi->ssl); SSL_free(wsi->ssl); #endif #endif wsi->ssl = NULL; if (lws_check_opt(context->options, LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS)) wsi->redirect_to_https = 1; goto accepted; } if (!n) /* * connection is gone, or nothing to read * if it's gone, we will timeout on * PENDING_TIMEOUT_SSL_ACCEPT */ break; if (n < 0 && (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK)) { /* * well, we get no way to know ssl or not * so go around again waiting for something * to come and give us a hint, or timeout the * connection. */ m = SSL_ERROR_WANT_READ; goto go_again; } } /* normal SSL connection processing path */ #if defined(LWS_USE_POLARSSL) n = ssl_handshake(wsi->ssl); #else #if defined(LWS_USE_MBEDTLS) #else n = SSL_accept(wsi->ssl); #endif #endif lws_latency(context, wsi, "SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1); if (n == 1) goto accepted; m = lws_ssl_get_error(wsi, n); lwsl_debug("SSL_accept failed %d / %s\n", m, ERR_error_string(m, NULL)); go_again: if (m == SSL_ERROR_WANT_READ) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_err("%s: WANT_READ change_pollfd failed\n", __func__); goto fail; } lwsl_info("SSL_ERROR_WANT_READ\n"); break; } if (m == SSL_ERROR_WANT_WRITE) { if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { lwsl_err("%s: WANT_WRITE change_pollfd failed\n", __func__); goto fail; } break; } lwsl_err("SSL_accept failed skt %u: %s\n", wsi->sock, ERR_error_string(m, NULL)); lws_ssl_elaborate_error(); goto fail; accepted: /* OK, we are accepted... give him some time to negotiate */ lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); wsi->mode = LWSCM_HTTP_SERVING; lws_http2_configure_if_upgraded(wsi); lwsl_debug("accepted new SSL conn\n"); break; } return 0; fail: return 1; } void lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost) { if (vhost->ssl_ctx) { #if defined(LWS_USE_POLARSSL) lws_free(vhost->ssl_ctx); #else #if defined(LWS_USE_MBEDTLS) #else SSL_CTX_free(vhost->ssl_ctx); #endif #endif } if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx) { #if defined(LWS_USE_POLARSSL) lws_free(vhost->ssl_client_ctx); #else #if defined(LWS_USE_MBEDTLS) #else SSL_CTX_free(vhost->ssl_client_ctx); #endif #endif } } void lws_ssl_context_destroy(struct lws_context *context) { #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL) ERR_remove_state(0); #else #if (OPENSSL_VERSION_NUMBER >= 0x10100005L) && \ !defined(LIBRESSL_VERSION_NUMBER) && \ !defined(OPENSSL_IS_BORINGSSL) ERR_remove_thread_state(); #else ERR_remove_thread_state(NULL); #endif #endif ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); #endif #endif } |
Added undroid/libwebsockets/libwebsockets-api-doc.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 | <h2>lws_client_reset - retarget a connected wsi to start over with a new connection (ie, redirect) this only works if still in HTTP, ie, not upgraded yet</h2> <i>struct lws *</i> <b>lws_client_reset</b> (<i>struct lws *</i> <b>wsi</b>, <i>int</i> <b>ssl</b>, <i>const char *</i> <b>address</b>, <i>int</i> <b>port</b>, <i>const char *</i> <b>path</b>, <i>const char *</i> <b>host</b>) <h3>Arguments</h3> <dl> </dl> <h3>wsi</h3> <blockquote> connection to reset </blockquote> <h3>address</h3> <blockquote> network address of the new server </blockquote> <h3>port</h3> <blockquote> port to connect to </blockquote> <h3>path</h3> <blockquote> uri path to connect to on the new server </blockquote> <h3>host</h3> <blockquote> host header to send to the new server </blockquote> <hr> <h2>lws_client_connect_via_info - Connect to another websocket server</h2> <i>struct lws *</i> <b>lws_client_connect_via_info</b> (<i>struct lws_client_connect_info *</i> <b>i</b>) <h3>Arguments</h3> <dl> <dt><b>i</b> <dd>pointer to lws_client_connect_info struct </dl> <h3>Description</h3> <blockquote> This function creates a connection to a remote server </blockquote> <hr> <h2>lws_client_connect_extended - Connect to another websocket server DEPRECATED use lws_client_connect_via_info</h2> <i>struct lws *</i> <b>lws_client_connect_extended</b> (<i>struct lws_context *</i> <b>context</b>, <i>const char *</i> <b>address</b>, <i>int</i> <b>port</b>, <i>int</i> <b>ssl_connection</b>, <i>const char *</i> <b>path</b>, <i>const char *</i> <b>host</b>, <i>const char *</i> <b>origin</b>, <i>const char *</i> <b>protocol</b>, <i>int</i> <b>ietf_version_or_minus_one</b>, <i>void *</i> <b>userdata</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context <dt><b>address</b> <dd>Remote server address, eg, "myserver.com" <dt><b>port</b> <dd>Port to connect to on the remote server, eg, 80 <dt><b>ssl_connection</b> <dd>0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self signed certs <dt><b>path</b> <dd>Websocket path on server <dt><b>host</b> <dd>Hostname on server <dt><b>origin</b> <dd>Socket origin name <dt><b>protocol</b> <dd>Comma-separated list of protocols being asked for from the server, or just one. The server will pick the one it likes best. <dt><b>ietf_version_or_minus_one</b> <dd>-1 to ask to connect using the default, latest protocol supported, or the specific protocol ordinal <dt><b>userdata</b> <dd>Pre-allocated user data </dl> <h3>Description</h3> <blockquote> This function creates a connection to a remote server </blockquote> <hr> <h2>lws_client_connect - Connect to another websocket server DEPRECATED use lws_client_connect_via_info</h2> <i>struct lws *</i> <b>lws_client_connect</b> (<i>struct lws_context *</i> <b>context</b>, <i>const char *</i> <b>address</b>, <i>int</i> <b>port</b>, <i>int</i> <b>ssl_connection</b>, <i>const char *</i> <b>path</b>, <i>const char *</i> <b>host</b>, <i>const char *</i> <b>origin</b>, <i>const char *</i> <b>protocol</b>, <i>int</i> <b>ietf_version_or_minus_one</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context <dt><b>address</b> <dd>Remote server address, eg, "myserver.com" <dt><b>port</b> <dd>Port to connect to on the remote server, eg, 80 <dt><b>ssl_connection</b> <dd>0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self signed certs <dt><b>path</b> <dd>Websocket path on server <dt><b>host</b> <dd>Hostname on server <dt><b>origin</b> <dd>Socket origin name <dt><b>protocol</b> <dd>Comma-separated list of protocols being asked for from the server, or just one. The server will pick the one it likes best. If you don't want to specify a protocol, which is legal, use NULL here. <dt><b>ietf_version_or_minus_one</b> <dd>-1 to ask to connect using the default, latest protocol supported, or the specific protocol ordinal </dl> <h3>Description</h3> <blockquote> This function creates a connection to a remote server </blockquote> <hr> <h2>lws_http_transaction_completed_client - wait for new http transaction or close</h2> <i>int LWS_WARN_UNUSED_RESULT</i> <b>lws_http_transaction_completed_client</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection </dl> <h3>Description</h3> <blockquote> Returns 1 if the HTTP connection must close now Returns 0 and resets connection to wait for new HTTP header / transaction if possible </blockquote> <hr> <h2>lws_get_library_version - </h2> <i>const char *</i> <b>lws_get_library_version</b> (<i></i> <b>void</b>) <h3>Arguments</h3> <dl> <dt><b>void</b> <dd>no arguments </dl> <h3>Description</h3> <blockquote> <p> returns a const char * to a string like "1.1 178d78c" representing the library version followed by the git head hash it was built from </blockquote> <hr> <h2>lws_create_context - Create the websocket handler</h2> <i>struct lws_context *</i> <b>lws_create_context</b> (<i>struct lws_context_creation_info *</i> <b>info</b>) <h3>Arguments</h3> <dl> <dt><b>info</b> <dd>pointer to struct with parameters </dl> <h3>Description</h3> <blockquote> This function creates the listening socket (if serving) and takes care of all initialization in one step. <p> After initialization, it returns a struct lws_context * that represents this server. After calling, user code needs to take care of calling <b>lws_service</b> with the context pointer to get the server's sockets serviced. This must be done in the same process context as the initialization call. <p> The protocol callback functions are called for a handful of events including http requests coming in, websocket connections becoming established, and data arriving; it's also called periodically to allow async transmission. <p> HTTP requests are sent always to the FIRST protocol in <tt><b>protocol</b></tt>, since at that time websocket protocol has not been negotiated. Other protocols after the first one never see any HTTP callack activity. <p> The server created is a simple http server by default; part of the websocket standard is upgrading this http connection to a websocket one. <p> This allows the same server to provide files like scripts and favicon / images or whatever over http and dynamic data over websockets all in one place; they're all handled in the user callback. </blockquote> <hr> <h2>lws_context_destroy - Destroy the websocket context</h2> <i>void</i> <b>lws_context_destroy</b> (<i>struct lws_context *</i> <b>context</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context </dl> <h3>Description</h3> <blockquote> This function closes any active connections and then frees the context. After calling this, any further use of the context is undefined. </blockquote> <hr> <h2>lws_set_extension_option - </h2> <i>int</i> <b>lws_set_extension_option</b> (<i>struct lws *</i> <b>wsi</b>, <i>const char *</i> <b>ext_name</b>, <i>const char *</i> <b>opt_name</b>, <i>const char *</i> <b>opt_val</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection <dt><b>ext_name</b> <dd>name of ext, like "permessage-deflate" <dt><b>opt_name</b> <dd>name of option, like "rx_buf_size" <dt><b>opt_val</b> <dd>value to set option to </dl> <hr> <h2>lws_return_http_status - Return simple http status</h2> <i>int</i> <b>lws_return_http_status</b> (<i>struct lws *</i> <b>wsi</b>, <i>unsigned int</i> <b>code</b>, <i>const char *</i> <b>html_body</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket instance (available from user callback) <dt><b>code</b> <dd>Status index, eg, 404 <dt><b>html_body</b> <dd>User-readable HTML description < 1KB, or NULL </dl> <h3>Description</h3> <blockquote> Helper to report HTTP errors back to the client cleanly and consistently </blockquote> <hr> <h2>lws_set_timeout - marks the wsi as subject to a timeout</h2> <i>void</i> <b>lws_set_timeout</b> (<i>struct lws *</i> <b>wsi</b>, <i>enum pending_timeout</i> <b>reason</b>, <i>int</i> <b>secs</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket connection instance <dt><b>reason</b> <dd>timeout reason <dt><b>secs</b> <dd>how many seconds </dl> <h3>Description</h3> <blockquote> <p> You will not need this unless you are doing something special </blockquote> <hr> <h2>lws_get_peer_addresses - Get client address information</h2> <i>void</i> <b>lws_get_peer_addresses</b> (<i>struct lws *</i> <b>wsi</b>, <i>lws_sockfd_type</i> <b>fd</b>, <i>char *</i> <b>name</b>, <i>int</i> <b>name_len</b>, <i>char *</i> <b>rip</b>, <i>int</i> <b>rip_len</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Local struct lws associated with <dt><b>fd</b> <dd>Connection socket descriptor <dt><b>name</b> <dd>Buffer to take client address name <dt><b>name_len</b> <dd>Length of client address name buffer <dt><b>rip</b> <dd>Buffer to take client address IP dotted quad <dt><b>rip_len</b> <dd>Length of client address IP buffer </dl> <h3>Description</h3> <blockquote> This function fills in <tt><b>name</b></tt> and <tt><b>rip</b></tt> with the name and IP of the client connected with socket descriptor <tt><b>fd</b></tt>. Names may be truncated if there is not enough room. If either cannot be determined, they will be returned as valid zero-length strings. </blockquote> <hr> <h2>lws_context_user - get the user data associated with the context</h2> <i>LWS_EXTERN void *</i> <b>lws_context_user</b> (<i>struct lws_context *</i> <b>context</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context </dl> <h3>Description</h3> <blockquote> This returns the optional user allocation that can be attached to the context the sockets live in at context_create time. It's a way to let all sockets serviced in the same context share data without using globals statics in the user code. </blockquote> <hr> <h2>lws_callback_all_protocol - Callback all connections using the given protocol with the given reason</h2> <i>int</i> <b>lws_callback_all_protocol</b> (<i>struct lws_context *</i> <b>context</b>, <i>const struct lws_protocols *</i> <b>protocol</b>, <i>int</i> <b>reason</b>) <h3>Arguments</h3> <dl> <dt><b>protocol</b> <dd>Protocol whose connections will get callbacks <dt><b>reason</b> <dd>Callback reason index </dl> <hr> <h2>lws_callback_all_protocol_vhost - Callback all connections using the given protocol with the given reason</h2> <i>int</i> <b>lws_callback_all_protocol_vhost</b> (<i>struct lws_vhost *</i> <b>vh</b>, <i>const struct lws_protocols *</i> <b>protocol</b>, <i>int</i> <b>reason</b>) <h3>Arguments</h3> <dl> <dt><b>vh</b> <dd>Vhost whose connections will get callbacks <dt><b>protocol</b> <dd>Which protocol to match <dt><b>reason</b> <dd>Callback reason index </dl> <hr> <h2>lws_get_socket_fd - returns the socket file descriptor</h2> <i>int</i> <b>lws_get_socket_fd</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket connection instance </dl> <h3>Description</h3> <blockquote> <p> You will not need this unless you are doing something special </blockquote> <hr> <h2>lws_rx_flow_control - Enable and disable socket servicing for received packets.</h2> <i>int</i> <b>lws_rx_flow_control</b> (<i>struct lws *</i> <b>wsi</b>, <i>int</i> <b>enable</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket connection instance to get callback for <dt><b>enable</b> <dd>0 = disable read servicing for this connection, 1 = enable </dl> <h3>Description</h3> <blockquote> <p> If the output side of a server process becomes choked, this allows flow control for the input side. </blockquote> <hr> <h2>lws_rx_flow_allow_all_protocol - Allow all connections with this protocol to receive</h2> <i>void</i> <b>lws_rx_flow_allow_all_protocol</b> (<i>const struct lws_context *</i> <b>context</b>, <i>const struct lws_protocols *</i> <b>protocol</b>) <h3>Arguments</h3> <dl> <dt><b>protocol</b> <dd>all connections using this protocol will be allowed to receive </dl> <h3>Description</h3> <blockquote> <p> When the user server code realizes it can accept more input, it can call this to have the RX flow restriction removed from all connections using the given protocol. </blockquote> <hr> <h2>lws_canonical_hostname - returns this host's hostname</h2> <i>const char *</i> <b>lws_canonical_hostname</b> (<i>struct lws_context *</i> <b>context</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context </dl> <h3>Description</h3> <blockquote> <p> This is typically used by client code to fill in the host parameter when making a client connection. You can only call it after the context has been created. </blockquote> <hr> <h2>lws_set_proxy - Setups proxy to lws_context.</h2> <i>int</i> <b>lws_set_proxy</b> (<i>struct lws_vhost *</i> <b>vhost</b>, <i>const char *</i> <b>proxy</b>) <h3>Arguments</h3> <dl> <dt><b>proxy</b> <dd>pointer to c string containing proxy in format address:port </dl> <h3>Description</h3> <blockquote> Returns 0 if proxy string was parsed and proxy was setup. Returns -1 if <tt><b>proxy</b></tt> is NULL or has incorrect format. <p> This is only required if your OS does not provide the http_proxy environment variable (eg, OSX) <p> IMPORTANT! You should call this function right after creation of the lws_context and before call to connect. If you call this function after connect behavior is undefined. This function will override proxy settings made on lws_context creation with <b>genenv</b> call. </blockquote> <hr> <h2>lws_get_protocol - Returns a protocol pointer from a websocket connection.</h2> <i>const struct lws_protocols *</i> <b>lws_get_protocol</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>pointer to struct websocket you want to know the protocol of </dl> <h3>Description</h3> <blockquote> <p> Some apis can act on all live connections of a given protocol, this is how you can get a pointer to the active protocol if needed. </blockquote> <hr> <h2>lwsl_timestamp - </h2> <i>int</i> <b>lwsl_timestamp</b> (<i>int</i> <b>level</b>, <i>char *</i> <b>p</b>, <i>int</i> <b>len</b>) <h3>Arguments</h3> <dl> <dt><b>level</b> <dd>logging level <dt><b>p</b> <dd>char * buffer to take timestamp <dt><b>len</b> <dd>length of p </dl> <h3>Description</h3> <blockquote> returns length written in p </blockquote> <hr> <h2>lws_set_log_level - Set the logging bitfield</h2> <i>void</i> <b>lws_set_log_level</b> (<i>int</i> <b>level</b>, <i>void (*</i><b>func</b>) <i>(int level, const char *line)</i>) <h3>Arguments</h3> <dl> <dt><b>level</b> <dd>OR together the LLL_ debug contexts you want output from </dl> <h3>Description</h3> <blockquote> log level defaults to "err", "warn" and "notice" contexts enabled and emission on stderr. </blockquote> <hr> <h2>lws_is_ssl - Find out if connection is using SSL</h2> <i>int</i> <b>lws_is_ssl</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection to check </dl> <h3>Description</h3> <blockquote> Returns 0 if the connection is not using SSL, 1 if using SSL and using verified cert, and 2 if using SSL but the cert was not checked (appears for client wsi told to skip check on connection) </blockquote> <hr> <h2>lws_partial_buffered - find out if lws buffered the last write</h2> <i>int</i> <b>lws_partial_buffered</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection to check </dl> <h3>Description</h3> <blockquote> Returns 1 if you cannot use lws_write because the last write on this connection is still buffered, and can't be cleared without returning to the service loop and waiting for the connection to be writeable again. <p> If you will try to do >1 lws_write call inside a single WRITEABLE callback, you must check this after every write and bail if set, ask for a new writeable callback and continue writing from there. <p> This is never set at the start of a writeable callback, but any write may set it. </blockquote> <hr> <h2>lws_get_context - Allow geting lws_context from a Websocket connection instance</h2> <i>LWS_EXTERN struct lws_context *</i> <b>lws_get_context</b> (<i>const struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket connection instance </dl> <h3>Description</h3> <blockquote> <p> With this function, users can access context in the callback function. Otherwise users may have to declare context as a global variable. </blockquote> <hr> <h2>lws_parse_uri - </h2> <i>LWS_EXTERN int</i> <b>lws_parse_uri</b> (<i>char *</i> <b>p</b>, <i>const char **</i> <b>prot</b>, <i>const char **</i> <b>ads</b>, <i>int *</i> <b>port</b>, <i>const char **</i> <b>path</b>) <h3>Arguments</h3> <dl> <dt><b>p</b> <dd>incoming uri string.. will get written to <dt><b>prot</b> <dd>result pointer for protocol part (https://) <dt><b>ads</b> <dd>result pointer for address part <dt><b>port</b> <dd>result pointer for port part <dt><b>path</b> <dd>result pointer for path part </dl> <h3>Description</h3> <blockquote> Notice it does so by dropping '\0' into input string and the leading / on the path is consequently lost </blockquote> <hr> <h2>lws_cgi - connected cgi process</h2> <i>LWS_EXTERN int</i> <b>lws_cgi</b> (<i>struct lws *</i> <b>wsi</b>, <i>const char *const *</i> <b>exec_array</b>, <i>int</i> <b>script_uri_path_len</b>, <i>int</i> <b>timeout_secs</b>, <i>const struct lws_protocol_vhost_options *</i> <b>mp_cgienv</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>connection to own the process <dt><b>exec_array</b> <dd>array of "exec-name" "arg1" ... "argn" NULL </dl> <hr> <h2>lws_cgi_write_split_stdout_headers - </h2> <i>LWS_EXTERN int</i> <b>lws_cgi_write_split_stdout_headers</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>connection to own the process </dl> <hr> <h2>lws_cgi_kill - </h2> <i>LWS_EXTERN int</i> <b>lws_cgi_kill</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>connection to own the process </dl> <hr> <h2>lws_cancel_service - Cancel servicing of pending websocket activity</h2> <i>void</i> <b>lws_cancel_service</b> (<i>struct lws_context *</i> <b>context</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context </dl> <h3>Description</h3> <blockquote> This function let a call to <b>lws_service</b> waiting for a timeout immediately return. <p> There is no <b>poll</b> in MBED3, he will fire callbacks when he feels like it. </blockquote> <hr> <h2>lws_cancel_service_pt - Cancel servicing of pending socket activity on one thread</h2> <i>void</i> <b>lws_cancel_service_pt</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Cancel service on the thread this wsi is serviced by </dl> <h3>Description</h3> <blockquote> This function let a call to <b>lws_service</b> waiting for a timeout immediately return. </blockquote> <hr> <h2>lws_cancel_service - Cancel ALL servicing of pending socket activity</h2> <i>void</i> <b>lws_cancel_service</b> (<i>struct lws_context *</i> <b>context</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context </dl> <h3>Description</h3> <blockquote> This function let a call to <b>lws_service</b> waiting for a timeout immediately return. </blockquote> <hr> <h2>lws_cancel_service - Cancel servicing of pending websocket activity</h2> <i>void</i> <b>lws_cancel_service</b> (<i>struct lws_context *</i> <b>context</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context </dl> <h3>Description</h3> <blockquote> This function let a call to <b>lws_service</b> waiting for a timeout immediately return. </blockquote> <hr> <h2>lws_write - Apply protocol then write data to client</h2> <i>int</i> <b>lws_write</b> (<i>struct lws *</i> <b>wsi</b>, <i>unsigned char *</i> <b>buf</b>, <i>size_t</i> <b>len</b>, <i>enum lws_write_protocol</i> <b>wp</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket instance (available from user callback) <dt><b>buf</b> <dd>The data to send. For data being sent on a websocket connection (ie, not default http), this buffer MUST have LWS_PRE bytes valid BEFORE the pointer. This is so the protocol header data can be added in-situ. <dt><b>len</b> <dd>Count of the data bytes in the payload starting from buf </dl> <h3>Description</h3> <blockquote> This function provides the way to issue data back to the client for both http and websocket protocols. <p> In the case of sending using websocket protocol, be sure to allocate valid storage before and after buf as explained above. This scheme allows maximum efficiency of sending data and protocol in a single packet while not burdening the user code with any protocol knowledge. <p> Return may be -1 for a fatal error needing connection close, or a positive number reflecting the amount of bytes actually sent. This can be less than the requested number of bytes due to OS memory pressure at any given time. </blockquote> <hr> <h2>lws_hdr_fragment_length - </h2> <i>int</i> <b>lws_hdr_fragment_length</b> (<i>struct lws *</i> <b>wsi</b>, <i>enum lws_token_indexes</i> <b>h</b>, <i>int</i> <b>frag_idx</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection <dt><b>h</b> <dd>which header index we are interested in <dt><b>frag_idx</b> <dd>which fragment of <tt><b>h</b></tt> we want to get the length of </dl> <h3>Description</h3> <blockquote> The returned length does not include the space for a terminating '\0' </blockquote> <hr> <h2>lws_hdr_total_length - </h2> <i>int</i> <b>lws_hdr_total_length</b> (<i>struct lws *</i> <b>wsi</b>, <i>enum lws_token_indexes</i> <b>h</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection <dt><b>h</b> <dd>which header index we are interested in </dl> <h3>Description</h3> <blockquote> The returned length does not include the space for a terminating '\0' </blockquote> <hr> <h2>lws_hdr_copy_fragment - </h2> <i>int</i> <b>lws_hdr_copy_fragment</b> (<i>struct lws *</i> <b>wsi</b>, <i>char *</i> <b>dst</b>, <i>int</i> <b>len</b>, <i>enum lws_token_indexes</i> <b>h</b>, <i>int</i> <b>frag_idx</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection <dt><b>dst</b> <dd>destination buffer <dt><b>len</b> <dd>length of destination buffer <dt><b>h</b> <dd>which header index we are interested in </dl> <h3>Description</h3> <blockquote> The buffer length <tt><b>len</b></tt> must include space for an additional terminating '\0', or it will fail returning -1. If the requested fragment index is not present, it fails returning -1. </blockquote> <hr> <h2>lws_hdr_copy - </h2> <i>int</i> <b>lws_hdr_copy</b> (<i>struct lws *</i> <b>wsi</b>, <i>char *</i> <b>dst</b>, <i>int</i> <b>len</b>, <i>enum lws_token_indexes</i> <b>h</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection <dt><b>dst</b> <dd>destination buffer <dt><b>len</b> <dd>length of destination buffer <dt><b>h</b> <dd>which header index we are interested in </dl> <h3>Description</h3> <blockquote> The buffer length <tt><b>len</b></tt> must include space for an additional terminating '\0', or it will fail returning -1. </blockquote> <hr> <h2>lws_frame_is_binary - </h2> <i>int</i> <b>lws_frame_is_binary</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>the connection we are inquiring about </dl> <h3>Description</h3> <blockquote> This is intended to be called from the LWS_CALLBACK_RECEIVE callback if it's interested to see if the frame it's dealing with was sent in binary mode. </blockquote> <hr> <h2>lws_remaining_packet_payload - Bytes to come before "overall" rx packet is complete</h2> <i>size_t</i> <b>lws_remaining_packet_payload</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket instance (available from user callback) </dl> <h3>Description</h3> <blockquote> This function is intended to be called from the callback if the user code is interested in "complete packets" from the client. libwebsockets just passes through payload as it comes and issues a buffer additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE callback handler can use this API to find out if the buffer it has just been given is the last piece of a "complete packet" from the client -- when that is the case <b>lws_remaining_packet_payload</b> will return 0. <p> Many protocols won't care becuse their packets are always small. </blockquote> <hr> <h2>lws_callback_on_writable - Request a callback when this socket becomes able to be written to without blocking</h2> <i>int</i> <b>lws_callback_on_writable</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket connection instance to get callback for </dl> <hr> <h2>lws_callback_on_writable_all_protocol_vhost - Request a callback for all connections using the given protocol when it becomes possible to write to each socket without blocking in turn.</h2> <i>int</i> <b>lws_callback_on_writable_all_protocol_vhost</b> (<i>const struct lws_vhost *</i> <b>vhost</b>, <i>const struct lws_protocols *</i> <b>protocol</b>) <h3>Arguments</h3> <dl> <dt><b>vhost</b> <dd>Only consider connections on this lws_vhost <dt><b>protocol</b> <dd>Protocol whose connections will get callbacks </dl> <h3>Description</h3> <blockquote> <p> This calls back connections with the same protocol ON THE SAME VHOST ONLY. </blockquote> <hr> <h2>lws_callback_on_writable_all_protocol - Request a callback for all connections using the given protocol when it becomes possible to write to each socket without blocking in turn.</h2> <i>int</i> <b>lws_callback_on_writable_all_protocol</b> (<i>const struct lws_context *</i> <b>context</b>, <i>const struct lws_protocols *</i> <b>protocol</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>lws_context <dt><b>protocol</b> <dd>Protocol whose connections will get callbacks </dl> <h3>Description</h3> <blockquote> <p> This calls back any connection using the same protocol on ANY VHOST. </blockquote> <hr> <h2>lws_http_transaction_completed - wait for new http transaction or close</h2> <i>int LWS_WARN_UNUSED_RESULT</i> <b>lws_http_transaction_completed</b> (<i>struct lws *</i> <b>wsi</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>websocket connection </dl> <h3>Description</h3> <blockquote> Returns 1 if the HTTP connection must close now Returns 0 and resets connection to wait for new HTTP header / transaction if possible </blockquote> <hr> <h2>lws_adopt_socket - adopt foreign socket as if listen socket accepted it</h2> <i>struct lws *</i> <b>lws_adopt_socket</b> (<i>struct lws_context *</i> <b>context</b>, <i>lws_sockfd_type</i> <b>accept_fd</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>lws context <dt><b>accept_fd</b> <dd>fd of already-accepted socket to adopt </dl> <h3>Description</h3> <blockquote> Either returns new wsi bound to accept_fd, or closes accept_fd and returns NULL, having cleaned up any new wsi pieces. <p> LWS adopts the socket in http serving mode, it's ready to accept an upgrade to ws or just serve http. </blockquote> <hr> <h2>lws_adopt_socket_readbuf - adopt foreign socket and first rx as if listen socket accepted it</h2> <i>LWS_EXTERN struct lws *</i> <b>lws_adopt_socket_readbuf</b> (<i>struct lws_context *</i> <b>context</b>, <i>lws_sockfd_type</i> <b>accept_fd</b>, <i>const char *</i> <b>readbuf</b>, <i>size_t</i> <b>len</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>lws context <dt><b>accept_fd</b> <dd>fd of already-accepted socket to adopt <dt><b>readbuf</b> <dd>NULL or pointer to data that must be drained before reading from accept_fd <dt><b>len</b> <dd>The length of the data held at <tt><b>readbuf</b></tt> </dl> <h3>Description</h3> <blockquote> Either returns new wsi bound to accept_fd, or closes accept_fd and returns NULL, having cleaned up any new wsi pieces. <p> LWS adopts the socket in http serving mode, it's ready to accept an upgrade to ws or just serve http. <p> If your external code did not already read from the socket, you can use <b>lws_adopt_socket</b> instead. <p> This api is guaranteed to use the data at <tt><b>readbuf</b></tt> first, before reading from the socket. <p> <tt><b>readbuf</b></tt> is limited to the size of the ah rx buf, currently 2048 bytes. </blockquote> <hr> <h2>lws_serve_http_file - Send a file back to the client using http</h2> <i>int</i> <b>lws_serve_http_file</b> (<i>struct lws *</i> <b>wsi</b>, <i>const char *</i> <b>file</b>, <i>const char *</i> <b>content_type</b>, <i>const char *</i> <b>other_headers</b>, <i>int</i> <b>other_headers_len</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Websocket instance (available from user callback) <dt><b>file</b> <dd>The file to issue over http <dt><b>content_type</b> <dd>The http content type, eg, text/html <dt><b>other_headers</b> <dd>NULL or pointer to header string <dt><b>other_headers_len</b> <dd>length of the other headers if non-NULL </dl> <h3>Description</h3> <blockquote> This function is intended to be called from the callback in response to http requests from the client. It allows the callback to issue local files down the http link in a single step. <p> Returning <0 indicates error and the wsi should be closed. Returning >0 indicates the file was completely sent and <b>lws_http_transaction_completed</b> called on the wsi (and close if != 0) ==0 indicates the file transfer is started and needs more service later, the wsi should be left alone. </blockquote> <hr> <h2>lws_service_fd_tsi - Service polled socket with something waiting</h2> <i>int</i> <b>lws_service_fd_tsi</b> (<i>struct lws_context *</i> <b>context</b>, <i>struct lws_pollfd *</i> <b>pollfd</b>, <i>int</i> <b>tsi</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context <dt><b>pollfd</b> <dd>The pollfd entry describing the socket fd and which events happened. </dl> <h3>Description</h3> <blockquote> This function takes a pollfd that has POLLIN or POLLOUT activity and services it according to the state of the associated struct lws. <p> The one call deals with all "service" that might happen on a socket including listen accepts, http files as well as websocket protocol. <p> If a pollfd says it has something, you can just pass it to <b>lws_service_fd</b> whether it is a socket handled by lws or not. If it sees it is a lws socket, the traffic will be handled and pollfd->revents will be zeroed now. <p> If the socket is foreign to lws, it leaves revents alone. So you can see if you should service yourself by checking the pollfd revents after letting lws try to service it. </blockquote> <hr> <h2>lws_service - Service any pending websocket activity</h2> <i>int</i> <b>lws_service</b> (<i>struct lws_context *</i> <b>context</b>, <i>int</i> <b>timeout_ms</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websocket context <dt><b>timeout_ms</b> <dd>Timeout for poll; 0 means return immediately if nothing needed service otherwise block and service immediately, returning after the timeout if nothing needed service. </dl> <h3>Description</h3> <blockquote> This function deals with any pending websocket traffic, for three kinds of event. It handles these events on both server and client types of connection the same. <p> 1) Accept new connections to our context's server <p> 2) Call the receive callback for incoming frame data received by server or client connections. <p> You need to call this service function periodically to all the above functions to happen; if your application is single-threaded you can just call it in your main event loop. <p> Alternatively you can fork a new process that asynchronously handles calling this service in a loop. In that case you are happy if this call blocks your thread until it needs to take care of something and would call it with a large nonzero timeout. Your loop then takes no CPU while there is nothing happening. <p> If you are calling it in a single-threaded app, you don't want it to wait around blocking other things in your loop from happening, so you would call it with a timeout_ms of 0, so it returns immediately if nothing is pending, or as soon as it services whatever was pending. </blockquote> <hr> <h2>struct lws_plat_file_ops - Platform-specific file operations</h2> <b>struct lws_plat_file_ops</b> {<br> <i>lws_filefd_type (*</i><b>open</b>) <i>(struct lws *wsi, const char *filename,unsigned long *filelen, int flags)</i>;<br> <i>int (*</i><b>close</b>) <i>(struct lws *wsi, lws_filefd_type fd)</i>;<br> <i>unsigned long (*</i><b>seek_cur</b>) <i>(struct lws *wsi, lws_filefd_type fd,long offset_from_cur_pos)</i>;<br> <i>int (*</i><b>read</b>) <i>(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,unsigned char *buf, unsigned long len)</i>;<br> <i>int (*</i><b>write</b>) <i>(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,unsigned char *buf, unsigned long len)</i>;<br> };<br> <h3>Members</h3> <dl> <dt><b>open</b> <dd>Open file (always binary access if plat supports it) filelen is filled on exit to be the length of the file flags should be set to O_RDONLY or O_RDWR <dt><b>close</b> <dd>Close file <dt><b>seek_cur</b> <dd>Seek from current position <dt><b>read</b> <dd>Read fron file *amount is set on exit to amount read <dt><b>write</b> <dd>Write to file *amount is set on exit as amount written </dl> <h3>Description</h3> <blockquote> <p> These provide platform-agnostic ways to deal with filesystem access in the library and in the user code. </blockquote> <hr> <h2>lws_callback_function - User server actions</h2> <i>typedef int</i> <b>lws_callback_function</b> (<i>struct lws *</i> <b>wsi</b>, <i>enum lws_callback_reasons</i> <b>reason</b>, <i>void *</i> <b>user</b>, <i>void *</i> <b>in</b>, <i>size_t</i> <b>len</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>Opaque websocket instance pointer <dt><b>reason</b> <dd>The reason for the call <dt><b>user</b> <dd>Pointer to per-session user data allocated by library <dt><b>in</b> <dd>Pointer used for some callback reasons <dt><b>len</b> <dd>Length set for some callback reasons </dl> <h3>Description</h3> <blockquote> This callback is the way the user controls what is served. All the protocol detail is hidden and handled by the library. <p> For each connection / session there is user data allocated that is pointed to by "user". You set the size of this user data area when the library is initialized with lws_create_server. <p> You get an opportunity to initialize user data when called back with LWS_CALLBACK_ESTABLISHED reason. </blockquote> <h3>LWS_CALLBACK_ESTABLISHED</h3> <blockquote> after the server completes a handshake with an incoming client. If you built the library with ssl support, <tt><b>in</b></tt> is a pointer to the ssl struct associated with the connection or NULL. </blockquote> <h3>LWS_CALLBACK_CLIENT_CONNECTION_ERROR</h3> <blockquote> the request client connection has been unable to complete a handshake with the remote server. If in is non-NULL, you can find an error string of length len where it points to. </blockquote> <h3>LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH</h3> <blockquote> this is the last chance for the client user code to examine the http headers and decide to reject the connection. If the content in the headers is interesting to the client (url, etc) it needs to copy it out at this point since it will be destroyed before the CLIENT_ESTABLISHED call </blockquote> <h3>LWS_CALLBACK_CLIENT_ESTABLISHED</h3> <blockquote> after your client connection completed a handshake with the remote server </blockquote> <h3>LWS_CALLBACK_CLOSED</h3> <blockquote> when the websocket session ends </blockquote> <h3>LWS_CALLBACK_CLOSED_HTTP</h3> <blockquote> when a HTTP (non-websocket) session ends </blockquote> <h3>LWS_CALLBACK_RECEIVE</h3> <blockquote> data has appeared for this server endpoint from a remote client, it can be found at *in and is len bytes long </blockquote> <h3>LWS_CALLBACK_CLIENT_RECEIVE_PONG</h3> <blockquote> if you elected to see PONG packets, they appear with this callback reason. PONG packets only exist in 04+ protocol </blockquote> <h3>LWS_CALLBACK_CLIENT_RECEIVE</h3> <blockquote> data has appeared from the server for the client connection, it can be found at *in and is len bytes long </blockquote> <h3>LWS_CALLBACK_HTTP</h3> <blockquote> an http request has come from a client that is not asking to upgrade the connection to a websocket one. This is a chance to serve http content, for example, to send a script to the client which will then open the websockets connection. <tt><b>in</b></tt> points to the URI path requested and <b>lws_serve_http_file</b> makes it very simple to send back a file to the client. Normally after sending the file you are done with the http connection, since the rest of the activity will come by websockets from the script that was delivered by http, so you will want to return 1; to close and free up the connection. That's important because it uses a slot in the total number of client connections allowed set by MAX_CLIENTS. </blockquote> <h3>LWS_CALLBACK_HTTP_BODY</h3> <blockquote> the next <tt><b>len</b></tt> bytes data from the http request body HTTP connection is now available in <tt><b>in</b></tt>. </blockquote> <h3>LWS_CALLBACK_HTTP_BODY_COMPLETION</h3> <blockquote> the expected amount of http request body has been delivered </blockquote> <h3>LWS_CALLBACK_HTTP_WRITEABLE</h3> <blockquote> you can write more down the http protocol link now. </blockquote> <h3>LWS_CALLBACK_HTTP_FILE_COMPLETION</h3> <blockquote> a file requested to be send down http link has completed. </blockquote> <h3>LWS_CALLBACK_SERVER_WRITEABLE</h3> <blockquote> If you call <b>lws_callback_on_writable</b> on a connection, you will get one of these callbacks coming when the connection socket is able to accept another write packet without blocking. If it already was able to take another packet without blocking, you'll get this callback at the next call to the service loop function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE and servers get LWS_CALLBACK_SERVER_WRITEABLE. </blockquote> <h3>LWS_CALLBACK_FILTER_NETWORK_CONNECTION</h3> <blockquote> called when a client connects to the server at network level; the connection is accepted but then passed to this callback to decide whether to hang up immediately or not, based on the client IP. <tt><b>in</b></tt> contains the connection socket's descriptor. Since the client connection information is not available yet, <tt><b>wsi</b></tt> still pointing to the main server socket. Return non-zero to terminate the connection before sending or receiving anything. Because this happens immediately after the network connection from the client, there's no websocket protocol selected yet so this callback is issued only to protocol 0. </blockquote> <h3>LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED</h3> <blockquote> A new client just had been connected, accepted, and instantiated into the pool. This callback allows setting any relevant property to it. Because this happens immediately after the instantiation of a new client, there's no websocket protocol selected yet so this callback is issued only to protocol 0. Only <tt><b>wsi</b></tt> is defined, pointing to the new client, and the return value is ignored. </blockquote> <h3>LWS_CALLBACK_FILTER_HTTP_CONNECTION</h3> <blockquote> called when the request has been received and parsed from the client, but the response is not sent yet. Return non-zero to disallow the connection. <tt><b>user</b></tt> is a pointer to the connection user space allocation, <tt><b>in</b></tt> is the URI, eg, "/" In your handler you can use the public APIs <b>lws_hdr_total_length</b> / <b>lws_hdr_copy</b> to access all of the headers using the header enums lws_token_indexes from libwebsockets.h to check for and read the supported header presence and content before deciding to allow the http connection to proceed or to kill the connection. </blockquote> <h3>LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION</h3> <blockquote> called when the handshake has been received and parsed from the client, but the response is not sent yet. Return non-zero to disallow the connection. <tt><b>user</b></tt> is a pointer to the connection user space allocation, <tt><b>in</b></tt> is the requested protocol name In your handler you can use the public APIs <b>lws_hdr_total_length</b> / <b>lws_hdr_copy</b> to access all of the headers using the header enums lws_token_indexes from libwebsockets.h to check for and read the supported header presence and content before deciding to allow the handshake to proceed or to kill the connection. </blockquote> <h3>LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS</h3> <blockquote> if configured for including OpenSSL support, this callback allows your user code to perform extra <b>SSL_CTX_load_verify_locations</b> or similar calls to direct OpenSSL where to find certificates the client can use to confirm the remote server identity. <tt><b>user</b></tt> is the OpenSSL SSL_CTX* </blockquote> <h3>LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS</h3> <blockquote> if configured for including OpenSSL support, this callback allows your user code to load extra certifcates into the server which allow it to verify the validity of certificates returned by clients. <tt><b>user</b></tt> is the server's OpenSSL SSL_CTX* </blockquote> <h3>LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY</h3> <blockquote> if configured for including OpenSSL support but no private key file has been specified (ssl_private_key_filepath is NULL), this is called to allow the user to set the private key directly via libopenssl and perform further operations if required; this might be useful in situations where the private key is not directly accessible by the OS, for example if it is stored on a smartcard <tt><b>user</b></tt> is the server's OpenSSL SSL_CTX* </blockquote> <h3>LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION</h3> <blockquote> if the libwebsockets context was created with the option LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this callback is generated during OpenSSL verification of the cert sent from the client. It is sent to protocol[0] callback as no protocol has been negotiated on the connection yet. Notice that the libwebsockets context and wsi are both NULL during this callback. See </blockquote> <h3>http</h3> <blockquote> //www.openssl.org/docs/ssl/SSL_CTX_set_verify.html to understand more detail about the OpenSSL callback that generates this libwebsockets callback and the meanings of the arguments passed. In this callback, <tt><b>user</b></tt> is the x509_ctx, <tt><b>in</b></tt> is the ssl pointer and <tt><b>len</b></tt> is preverify_ok Notice that this callback maintains libwebsocket return conventions, return 0 to mean the cert is OK or 1 to fail it. This also means that if you don't handle this callback then the default callback action of returning 0 allows the client certificates. </blockquote> <h3>LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER</h3> <blockquote> this callback happens when a client handshake is being compiled. <tt><b>user</b></tt> is NULL, <tt><b>in</b></tt> is a char **, it's pointing to a char * which holds the next location in the header buffer where you can add headers, and <tt><b>len</b></tt> is the remaining space in the header buffer, which is typically some hundreds of bytes. So, to add a canned cookie, your handler code might look similar to: <p> char **p = (char **)in; <p> if (len < 100) return 1; <p> *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); <p> return 0; <p> Notice if you add anything, you just have to take care about the CRLF on the line you added. Obviously this callback is optional, if you don't handle it everything is fine. <p> Notice the callback is coming to protocols[0] all the time, because there is no specific protocol handshook yet. </blockquote> <h3>LWS_CALLBACK_CONFIRM_EXTENSION_OKAY</h3> <blockquote> When the server handshake code sees that it does support a requested extension, before accepting the extension by additing to the list sent back to the client it gives this callback just to check that it's okay to use that extension. It calls back to the requested protocol and with <tt><b>in</b></tt> being the extension name, <tt><b>len</b></tt> is 0 and <tt><b>user</b></tt> is valid. Note though at this time the ESTABLISHED callback hasn't happened yet so if you initialize <tt><b>user</b></tt> content there, <tt><b>user</b></tt> content during this callback might not be useful for anything. Notice this callback comes to protocols[0]. </blockquote> <h3>LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED</h3> <blockquote> When a client connection is being prepared to start a handshake to a server, each supported extension is checked with protocols[0] callback with this reason, giving the user code a chance to suppress the claim to support that extension by returning non-zero. If unhandled, by default 0 will be returned and the extension support included in the header to the server. Notice this callback comes to protocols[0]. </blockquote> <h3>LWS_CALLBACK_PROTOCOL_INIT</h3> <blockquote> One-time call per protocol so it can do initial setup / allocations etc </blockquote> <h3>LWS_CALLBACK_PROTOCOL_DESTROY</h3> <blockquote> One-time call per protocol indicating this protocol won't get used at all after this callback, the context is getting destroyed. Take the opportunity to deallocate everything that was allocated by the protocol. </blockquote> <h3>LWS_CALLBACK_WSI_CREATE</h3> <blockquote> outermost (earliest) wsi create notification </blockquote> <h3>LWS_CALLBACK_WSI_DESTROY</h3> <blockquote> outermost (latest) wsi destroy notification <p> The next five reasons are optional and only need taking care of if you will be integrating libwebsockets sockets into an external polling array. <p> For these calls, <tt><b>in</b></tt> points to a struct lws_pollargs that contains <tt><b>fd</b></tt>, <tt><b>events</b></tt> and <tt><b>prev_events</b></tt> members </blockquote> <h3>LWS_CALLBACK_ADD_POLL_FD</h3> <blockquote> libwebsocket deals with its <b>poll</b> loop internally, but in the case you are integrating with another server you will need to have libwebsocket sockets share a polling array with the other server. This and the other POLL_FD related callbacks let you put your specialized poll array interface code in the callback for protocol 0, the first protocol you support, usually the HTTP protocol in the serving case. This callback happens when a socket needs to be </blockquote> <h3>added to the polling loop</h3> <blockquote> <tt><b>in</b></tt> points to a struct lws_pollargs; the <tt><b>fd</b></tt> member of the struct is the file descriptor, and <tt><b>events</b></tt> contains the active events. <p> If you are using the internal polling loop (the "service" callback), you can just ignore these callbacks. </blockquote> <h3>LWS_CALLBACK_DEL_POLL_FD</h3> <blockquote> This callback happens when a socket descriptor needs to be removed from an external polling array. <tt><b>in</b></tt> is again the struct lws_pollargs containing the <tt><b>fd</b></tt> member to be removed. If you are using the internal polling loop, you can just ignore it. </blockquote> <h3>LWS_CALLBACK_CHANGE_MODE_POLL_FD</h3> <blockquote> This callback happens when libwebsockets wants to modify the events for a connectiion. <tt><b>in</b></tt> is the struct lws_pollargs with the <tt><b>fd</b></tt> to change. The new event mask is in <tt><b>events</b></tt> member and the old mask is in the <tt><b>prev_events</b></tt> member. If you are using the internal polling loop, you can just ignore it. </blockquote> <h3>LWS_CALLBACK_UNLOCK_POLL</h3> <blockquote> These allow the external poll changes driven by libwebsockets to participate in an external thread locking scheme around the changes, so the whole thing is threadsafe. These are called around three activities in the library, - inserting a new wsi in the wsi / fd table (len=1) - deleting a wsi from the wsi / fd table (len=1) - changing a wsi's POLLIN/OUT state (len=0) Locking and unlocking external synchronization objects when len == 1 allows external threads to be synchronized against wsi lifecycle changes if it acquires the same lock for the duration of wsi dereference from the other thread context. </blockquote> <h3>LWS_CALLBACK_WS_PEER_INITIATED_CLOSE</h3> <blockquote> The peer has sent an unsolicited Close WS packet. <tt><b>in</b></tt> and <tt><b>len</b></tt> are the optional close code (first 2 bytes, network order) and the optional additional information which is not defined in the standard, and may be a string or non-human- readble data. If you return 0 lws will echo the close and then close the connection. If you return nonzero lws will just close the connection. </blockquote> <hr> <h2>lws_extension_callback_function - Hooks to allow extensions to operate</h2> <i>typedef int</i> <b>lws_extension_callback_function</b> (<i>struct lws_context *</i> <b>context</b>, <i>const struct lws_extension *</i> <b>ext</b>, <i>struct lws *</i> <b>wsi</b>, <i>enum lws_extension_callback_reasons</i> <b>reason</b>, <i>void *</i> <b>user</b>, <i>void *</i> <b>in</b>, <i>size_t</i> <b>len</b>) <h3>Arguments</h3> <dl> <dt><b>context</b> <dd>Websockets context <dt><b>ext</b> <dd>This extension <dt><b>wsi</b> <dd>Opaque websocket instance pointer <dt><b>reason</b> <dd>The reason for the call <dt><b>user</b> <dd>Pointer to ptr to per-session user data allocated by library <dt><b>in</b> <dd>Pointer used for some callback reasons <dt><b>len</b> <dd>Length set for some callback reasons </dl> <h3>Description</h3> <blockquote> Each extension that is active on a particular connection receives callbacks during the connection lifetime to allow the extension to operate on websocket data and manage itself. <p> Libwebsockets takes care of allocating and freeing "user" memory for each active extension on each connection. That is what is pointed to by the <tt><b>user</b></tt> parameter. </blockquote> <h3>LWS_EXT_CB_CONSTRUCT</h3> <blockquote> called when the server has decided to select this extension from the list provided by the client, just before the server will send back the handshake accepting the connection with this extension active. This gives the extension a chance to initialize its connection context found in <tt><b>user</b></tt>. </blockquote> <h3>LWS_EXT_CB_CLIENT_CONSTRUCT</h3> <blockquote> same as LWS_EXT_CB_CONSTRUCT but called when client is instantiating this extension. Some extensions will work the same on client and server side and then you can just merge handlers for both CONSTRUCTS. </blockquote> <h3>LWS_EXT_CB_DESTROY</h3> <blockquote> called when the connection the extension was being used on is about to be closed and deallocated. It's the last chance for the extension to deallocate anything it has allocated in the user data (pointed to by <tt><b>user</b></tt>) before the user data is deleted. This same callback is used whether you are in client or server instantiation context. </blockquote> <h3>LWS_EXT_CB_PACKET_RX_PREPARSE</h3> <blockquote> when this extension was active on a connection, and a packet of data arrived at the connection, it is passed to this callback to give the extension a chance to change the data, eg, decompress it. <tt><b>user</b></tt> is pointing to the extension's private connection context data, <tt><b>in</b></tt> is pointing to an lws_tokens struct, it consists of a char * pointer called token, and an int called token_len. At entry, these are set to point to the received buffer and set to the content length. If the extension will grow the content, it should use a new buffer allocated in its private user context data and set the pointed-to lws_tokens members to point to its buffer. </blockquote> <h3>LWS_EXT_CB_PACKET_TX_PRESEND</h3> <blockquote> this works the same way as LWS_EXT_CB_PACKET_RX_PREPARSE above, except it gives the extension a chance to change websocket data just before it will be sent out. Using the same lws_token pointer scheme in <tt><b>in</b></tt>, the extension can change the buffer and the length to be transmitted how it likes. Again if it wants to grow the buffer safely, it should copy the data into its own buffer and set the lws_tokens token pointer to it. </blockquote> <hr> <h2>struct lws_protocols - List of protocols and handlers server supports.</h2> <b>struct lws_protocols</b> {<br> <i>const char *</i> <b>name</b>;<br> <i>lws_callback_function *</i> <b>callback</b>;<br> <i>size_t</i> <b>per_session_data_size</b>;<br> <i>size_t</i> <b>rx_buffer_size</b>;<br> <i>unsigned int</i> <b>id</b>;<br> <i>void *</i> <b>user</b>;<br> };<br> <h3>Members</h3> <dl> <dt><b>name</b> <dd>Protocol name that must match the one given in the client Javascript new WebSocket(url, 'protocol') name. <dt><b>callback</b> <dd>The service callback used for this protocol. It allows the service action for an entire protocol to be encapsulated in the protocol-specific callback <dt><b>per_session_data_size</b> <dd>Each new connection using this protocol gets this much memory allocated on connection establishment and freed on connection takedown. A pointer to this per-connection allocation is passed into the callback in the 'user' parameter <dt><b>rx_buffer_size</b> <dd>if you want atomic frames delivered to the callback, you should set this to the size of the biggest legal frame that you support. If the frame size is exceeded, there is no error, but the buffer will spill to the user callback when full, which you can detect by using <b>lws_remaining_packet_payload</b>. Notice that you just talk about frame size here, the LWS_PRE and post-padding are automatically also allocated on top. <dt><b>id</b> <dd>ignored by lws, but useful to contain user information bound to the selected protocol. For example if this protocol was called "myprotocol-v2", you might set id to 2, and the user code that acts differently according to the version can do so by switch (wsi->protocol->id), user code might use some bits as capability flags based on selected protocol version, etc. <dt><b>user</b> <dd>User provided context data at the protocol level. Accessible via lws_get_protocol(wsi)->user This should not be confused with wsi->user, it is not the same. The library completely ignores any value in here. </dl> <h3>Description</h3> <blockquote> This structure represents one protocol supported by the server. An array of these structures is passed to <b>lws_create_server</b> allows as many protocols as you like to be handled by one server. <p> The first protocol given has its callback used for user callbacks when there is no agreed protocol name, that's true during HTTP part of the </blockquote> <h3>connection and true if the client did not send a Protocol</h3> <blockquote> header. </blockquote> <hr> <h2>struct lws_ext_options - Option arguments to the extension. These are used in the negotiation at ws upgrade time. The helper function lws_ext_parse_options() uses these to generate callbacks</h2> <b>struct lws_ext_options</b> {<br> <i>const char *</i> <b>name</b>;<br> <i>enum lws_ext_options_types</i> <b>type</b>;<br> };<br> <h3>Members</h3> <dl> <dt><b>name</b> <dd>Option name, eg, "server_no_context_takeover" <dt><b>type</b> <dd>What kind of args the option can take </dl> <hr> <h2>struct lws_extension - An extension we know how to cope with</h2> <b>struct lws_extension</b> {<br> <i>const char *</i> <b>name</b>;<br> <i>lws_extension_callback_function *</i> <b>callback</b>;<br> <i>const char *</i> <b>client_offer</b>;<br> };<br> <h3>Members</h3> <dl> <dt><b>name</b> <dd>Formal extension name, eg, "permessage-deflate" <dt><b>callback</b> <dd>Service callback <dt><b>client_offer</b> <dd>String containing exts and options client offers </dl> <hr> <h2>struct lws_context_creation_info - parameters to create context with</h2> <b>struct lws_context_creation_info</b> {<br> <i>int</i> <b>port</b>;<br> <i>const char *</i> <b>iface</b>;<br> <i>const struct lws_protocols *</i> <b>protocols</b>;<br> <i>const struct lws_extension *</i> <b>extensions</b>;<br> <i>const struct lws_token_limits *</i> <b>token_limits</b>;<br> <i>const char *</i> <b>ssl_cert_filepath</b>;<br> <i>const char *</i> <b>ssl_private_key_filepath</b>;<br> <i>const char *</i> <b>ssl_ca_filepath</b>;<br> <i>const char *</i> <b>ssl_cipher_list</b>;<br> <i>const char *</i> <b>http_proxy_address</b>;<br> <i>unsigned int</i> <b>http_proxy_port</b>;<br> <i>int</i> <b>gid</b>;<br> <i>int</i> <b>uid</b>;<br> <i>unsigned int</i> <b>options</b>;<br> <i>void *</i> <b>user</b>;<br> <i>int</i> <b>ka_time</b>;<br> <i>int</i> <b>ka_probes</b>;<br> <i>int</i> <b>ka_interval</b>;<br> #ifdef LWS_OPENSSL_SUPPORT<br> <i>void *</i> <b>provided_client_ssl_ctx</b>;<br> #else<br> <i>void *</i> <b>provided_client_ssl_ctx</b>;<br> #endif<br> <i>short</i> <b>max_http_header_data</b>;<br> <i>short</i> <b>max_http_header_pool</b>;<br> <i>unsigned int</i> <b>count_threads</b>;<br> <i>unsigned int</i> <b>fd_limit_per_thread</b>;<br> <i>unsigned int</i> <b>timeout_secs</b>;<br> <i>const char *</i> <b>ecdh_curve</b>;<br> <i>const char *</i> <b>vhost_name</b>;<br> <i>const char *const *</i> <b>plugin_dirs</b>;<br> <i>const struct lws_protocol_vhost_options *</i> <b>pvo</b>;<br> <i>int</i> <b>keepalive_timeout</b>;<br> <i>const char *</i> <b>log_filepath</b>;<br> <i>const struct lws_http_mount *</i> <b>mounts</b>;<br> <i>const char *</i> <b>server_string</b>;<br> };<br> <h3>Members</h3> <dl> <dt><b>port</b> <dd>VHOST: Port to listen on... you can use CONTEXT_PORT_NO_LISTEN to suppress listening on any port, that's what you want if you are not running a websocket server at all but just using it as a client <dt><b>iface</b> <dd>VHOST: NULL to bind the listen socket to all interfaces, or the interface name, eg, "eth2" If options specifies LWS_SERVER_OPTION_UNIX_SOCK, this member is the pathname of a UNIX domain socket. you can use the UNIX domain sockets in abstract namespace, by prepending an @ symbole to the socket name. <dt><b>protocols</b> <dd>VHOST: Array of structures listing supported protocols and a protocol- specific callback for each one. The list is ended with an entry that has a NULL callback pointer. It's not const because we write the owning_server member <dt><b>extensions</b> <dd>VHOST: NULL or array of lws_extension structs listing the extensions this context supports. If you configured with --without-extensions, you should give NULL here. <dt><b>token_limits</b> <dd>CONTEXT: NULL or struct lws_token_limits pointer which is initialized with a token length limit for each possible WSI_TOKEN_*** <dt><b>ssl_cert_filepath</b> <dd>VHOST: If libwebsockets was compiled to use ssl, and you want to listen using SSL, set to the filepath to fetch the server cert from, otherwise NULL for unencrypted <dt><b>ssl_private_key_filepath</b> <dd>VHOST: filepath to private key if wanting SSL mode; if this is set to NULL but sll_cert_filepath is set, the OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY callback is called to allow setting of the private key directly via openSSL library calls <dt><b>ssl_ca_filepath</b> <dd>VHOST: CA certificate filepath or NULL <dt><b>ssl_cipher_list</b> <dd>VHOST: List of valid ciphers to use (eg, "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" or you can leave it as NULL to get "DEFAULT" <dt><b>http_proxy_address</b> <dd>VHOST: If non-NULL, attempts to proxy via the given address. If proxy auth is required, use format "username:password<tt><b>server</b></tt>:port" <dt><b>http_proxy_port</b> <dd>VHOST: If http_proxy_address was non-NULL, uses this port at the address <dt><b>gid</b> <dd>CONTEXT: group id to change to after setting listen socket, or -1. <dt><b>uid</b> <dd>CONTEXT: user id to change to after setting listen socket, or -1. <dt><b>options</b> <dd>VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields <dt><b>user</b> <dd>CONTEXT: optional user pointer that can be recovered via the context pointer using lws_context_user <dt><b>ka_time</b> <dd>CONTEXT: 0 for no keepalive, otherwise apply this keepalive timeout to all libwebsocket sockets, client or server <dt><b>ka_probes</b> <dd>CONTEXT: if ka_time was nonzero, after the timeout expires how many times to try to get a response from the peer before giving up and killing the connection <dt><b>ka_interval</b> <dd>CONTEXT: if ka_time was nonzero, how long to wait before each ka_probes attempt <dt><b>provided_client_ssl_ctx</b> <dd>CONTEXT: If non-null, swap out libwebsockets ssl implementation for the one provided by provided_ssl_ctx. Libwebsockets no longer is responsible for freeing the context if this option is selected. <dt><b>provided_client_ssl_ctx</b> <dd>CONTEXT: If non-null, swap out libwebsockets ssl implementation for the one provided by provided_ssl_ctx. Libwebsockets no longer is responsible for freeing the context if this option is selected. <dt><b>max_http_header_data</b> <dd>CONTEXT: The max amount of header payload that can be handled in an http request (unrecognized header payload is dropped) <dt><b>max_http_header_pool</b> <dd>CONTEXT: The max number of connections with http headers that can be processed simultaneously (the corresponding memory is allocated for the lifetime of the context). If the pool is busy new incoming connections must wait for accept until one becomes free. <dt><b>count_threads</b> <dd>CONTEXT: how many contexts to create in an array, 0 = 1 <dt><b>fd_limit_per_thread</b> <dd>CONTEXT: nonzero means restrict each service thread to this many fds, 0 means the default which is divide the process fd limit by the number of threads. <dt><b>timeout_secs</b> <dd>VHOST: various processes involving network roundtrips in the library are protected from hanging forever by timeouts. If nonzero, this member lets you set the timeout used in seconds. Otherwise a default timeout is used. <dt><b>ecdh_curve</b> <dd>VHOST: if NULL, defaults to initializing server with "prime256v1" <dt><b>vhost_name</b> <dd>VHOST: name of vhost, must match external DNS name used to access the site, like "warmcat.com" as it's used to match <dt><b>plugin_dirs</b> <dd>CONTEXT: NULL, or NULL-terminated array of directories to scan for lws protocol plugins at context creation time <dt><b>pvo</b> <dd>VHOST: pointer to optional linked list of per-vhost options made accessible to protocols <dt><b>keepalive_timeout</b> <dd>VHOST: (default = 0 = 60s) seconds to allow remote client to hold on to an idle HTTP/1.1 connection <dt><b>log_filepath</b> <dd>VHOST: filepath to append logs to... this is opened before any dropping of initial privileges <dt><b>mounts</b> <dd>VHOST: optional linked list of mounts for this vhost <dt><b>server_string</b> <dd>CONTEXT: string used in HTTP headers to identify server software, if NULL, "libwebsockets". </dl> <h3>Description</h3> <blockquote> <p> This is also used to create vhosts.... if LWS_SERVER_OPTION_EXPLICIT_VHOSTS is not given, then for backwards compatibility one vhost is created at context-creation time using the info from this struct. <p> If LWS_SERVER_OPTION_EXPLICIT_VHOSTS is given, then no vhosts are created at the same time as the context, they are expected to be created afterwards. </blockquote> <h3>Host</h3> <blockquote> header and / or SNI name for SSL. </blockquote> <hr> <h2>struct lws_client_connect_info - parameters to connect with when using lws_client_connect_via_info()</h2> <b>struct lws_client_connect_info</b> {<br> <i>struct lws_context *</i> <b>context</b>;<br> <i>const char *</i> <b>address</b>;<br> <i>int</i> <b>port</b>;<br> <i>int</i> <b>ssl_connection</b>;<br> <i>const char *</i> <b>path</b>;<br> <i>const char *</i> <b>host</b>;<br> <i>const char *</i> <b>origin</b>;<br> <i>const char *</i> <b>protocol</b>;<br> <i>int</i> <b>ietf_version_or_minus_one</b>;<br> <i>void *</i> <b>userdata</b>;<br> <i>const struct lws_extension *</i> <b>client_exts</b>;<br> <i>const char *</i> <b>method</b>;<br> <i>struct lws *</i> <b>parent_wsi</b>;<br> <i>const char *</i> <b>uri_replace_from</b>;<br> <i>const char *</i> <b>uri_replace_to</b>;<br> <i>struct lws_vhost *</i> <b>vhost</b>;<br> };<br> <h3>Members</h3> <dl> <dt><b>context</b> <dd>lws context to create connection in <dt><b>address</b> <dd>remote address to connect to <dt><b>port</b> <dd>remote port to connect to <dt><b>ssl_connection</b> <dd>nonzero for ssl <dt><b>path</b> <dd>uri path <dt><b>host</b> <dd>content of host header <dt><b>origin</b> <dd>content of origin header <dt><b>protocol</b> <dd>list of ws protocols <dt><b>ietf_version_or_minus_one</b> <dd>currently leave at 0 or -1 <dt><b>userdata</b> <dd>if non-NULL, use this as wsi user_data instead of malloc it <dt><b>client_exts</b> <dd>array of extensions that may be used on connection <dt><b>method</b> <dd>if non-NULL, do this http method instead of ws[s] upgrade. use "GET" to be a simple http client connection <dt><b>parent_wsi</b> <dd>if another wsi is responsible for this connection, give it here. this is used to make sure if the parent closes so do any child connections first. <dt><b>uri_replace_from</b> <dd>if non-NULL, when this string is found in URIs in text/html content-encoding, it's replaced with <tt><b>uri_replace_to</b></tt> <dt><b>uri_replace_to</b> <dd>see above <dt><b>vhost</b> <dd>vhost to bind to (used to determine related SSL_CTX) </dl> <hr> <h2>lws_close_reason - Set reason and aux data to send with Close packet If you are going to return nonzero from the callback requesting the connection to close, you can optionally call this to set the reason the peer will be told if possible.</h2> <i>LWS_EXTERN void</i> <b>lws_close_reason</b> (<i>struct lws *</i> <b>wsi</b>, <i>enum lws_close_status</i> <b>status</b>, <i>unsigned char *</i> <b>buf</b>, <i>size_t</i> <b>len</b>) <h3>Arguments</h3> <dl> <dt><b>wsi</b> <dd>The websocket connection to set the close reason on <dt><b>status</b> <dd>A valid close status from websocket standard <dt><b>buf</b> <dd>NULL or buffer containing up to 124 bytes of auxiliary data <dt><b>len</b> <dd>Length of data in <tt><b>buf</b></tt> to send </dl> <hr> <h2>lws_snprintf - </h2> <i>LWS_EXTERN int</i> <b>lws_snprintf</b> (<i>char *</i> <b>str</b>, <i>size_t</i> <b>size</b>, <i>const char *</i> <b>format</b>, <i></i> <b>...</b>) <h3>Arguments</h3> <dl> <dt><b>...</b> <dd>variable arguments </dl> <h3>Description</h3> <blockquote> <p> \param str: destination buffer \param size: bytes left in destination buffer \param format: format string \param ...: args for format <p> This lets you correctly truncate buffers by concatenating lengths, if you reach the limit the reported length doesn't exceed the limit. </blockquote> <hr> |
Added undroid/libwebsockets/libwebsockets.spec.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Name: libwebsockets Version: 2.0.3 Release: 1%{?dist} Summary: Websocket Server and Client Library Group: System Environment/Libraries License: LGPLv2 with exceptions URL: https://libwebsockets.org Source0: %{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) BuildRequires: openssl-devel cmake Requires: openssl %description Webserver server and client library %package devel Summary: Development files for libwebsockets Group: Development/Libraries Requires: %{name} = %{version}-%{release} Requires: openssl-devel %description devel Development files for libwebsockets %prep %setup -q %build mkdir -p build cd build %cmake .. make %install rm -rf $RPM_BUILD_ROOT cd build make install DESTDIR=$RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %attr(755,root,root) /usr/bin/libwebsockets-test-server /usr/bin/libwebsockets-test-server-extpoll /usr/bin/libwebsockets-test-server-pthreads /usr/bin/libwebsockets-test-client /usr/bin/libwebsockets-test-ping /usr/bin/libwebsockets-test-echo /usr/bin/libwebsockets-test-fraggle /usr/bin/libwebsockets-test-fuzxy /%{_libdir}/libwebsockets.so.8.1 /%{_libdir}/libwebsockets.so /%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake /%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake /%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets.cmake /usr/share/libwebsockets-test-server %doc %files devel %defattr(-,root,root,-) /usr/include/* %attr(755,root,root) /%{_libdir}/libwebsockets.a /%{_libdir}/pkgconfig/libwebsockets.pc %changelog * Thu Sep 15 2016 Andy Green <andy@warmcat.com> 2.0.3-1 - MAJOR Upstream 2.0.3 release * Mon Jun 06 2016 Andy Green <andy@warmcat.com> 2.0.2-1 - MINOR Upstream 2.0.2 release * Thu May 12 2016 Andy Green <andy@warmcat.com> 2.0.1-1 - MINOR Upstream 2.0.1 release * Thu May 05 2016 Andy Green <andy@warmcat.com> 2.0.0-1 - MAJOR SONAMEBUMP APICHANGES Upstream 2.0.0 release * Tue Feb 16 2016 Andy Green <andy@warmcat.com> 1.7.0-1 - MAJOR SONAMEBUMP APICHANGES Upstream 1.7.0 release * Sun Jan 17 2016 Andrew Cooks <acooks@linux.com> 1.6.0-1 - Bump version to 1.6.0 |
Added undroid/libwebsockets/lws_config.h.in.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* lws_config.h Generated from lws_config.h.in */ #ifndef NDEBUG #ifndef _DEBUG #define _DEBUG #endif #endif /* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL. * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ #cmakedefine USE_WOLFSSL /* Also define to 1 (in addition to USE_WOLFSSL) when using the (older) CyaSSL library */ #cmakedefine USE_OLD_CYASSL #cmakedefine LWS_USE_MBEDTLS #cmakedefine LWS_USE_POLARSSL #cmakedefine LWS_WITH_PLUGINS /* The Libwebsocket version */ #cmakedefine LWS_LIBRARY_VERSION "${LWS_LIBRARY_VERSION}" #define LWS_LIBRARY_VERSION_MAJOR ${LWS_LIBRARY_VERSION_MAJOR} #define LWS_LIBRARY_VERSION_MINOR ${LWS_LIBRARY_VERSION_MINOR} #define LWS_LIBRARY_VERSION_PATCH ${LWS_LIBRARY_VERSION_PATCH} /* LWS_LIBRARY_VERSION_NUMBER looks like 1005001 for e.g. version 1.5.1 */ #define LWS_LIBRARY_VERSION_NUMBER (LWS_LIBRARY_VERSION_MAJOR*1000000)+(LWS_LIBRARY_VERSION_MINOR*1000)+LWS_LIBRARY_VERSION_PATCH /* The current git commit hash that we're building from */ #cmakedefine LWS_BUILD_HASH "${LWS_BUILD_HASH}" /* Build with OpenSSL support */ #cmakedefine LWS_OPENSSL_SUPPORT /* The client should load and trust CA root certs it finds in the OS */ #cmakedefine LWS_SSL_CLIENT_USE_OS_CA_CERTS /* Sets the path where the client certs should be installed. */ #cmakedefine LWS_OPENSSL_CLIENT_CERTS "${LWS_OPENSSL_CLIENT_CERTS}" /* Turn off websocket extensions */ #cmakedefine LWS_NO_EXTENSIONS /* Enable libev io loop */ #cmakedefine LWS_USE_LIBEV /* Enable libuv io loop */ #cmakedefine LWS_USE_LIBUV /* Build with support for ipv6 */ #cmakedefine LWS_USE_IPV6 /* Build with support for UNIX domain socket */ #cmakedefine LWS_USE_UNIX_SOCK /* Build with support for HTTP2 */ #cmakedefine LWS_USE_HTTP2 /* Turn on latency measuring code */ #cmakedefine LWS_LATENCY /* Don't build the daemonizeation api */ #cmakedefine LWS_NO_DAEMONIZE /* Build without server support */ #cmakedefine LWS_NO_SERVER /* Build without client support */ #cmakedefine LWS_NO_CLIENT /* If we should compile with MinGW support */ #cmakedefine LWS_MINGW_SUPPORT /* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ #cmakedefine LWS_BUILTIN_GETIFADDRS /* use SHA1() not internal libwebsockets_SHA1 */ #cmakedefine LWS_SHA1_USE_OPENSSL_NAME /* SSL server using ECDH certificate */ #cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT #cmakedefine LWS_HAVE_SSL_CTX_set1_param #cmakedefine LWS_HAVE_X509_VERIFY_PARAM_set1_host /* CGI apis */ #cmakedefine LWS_WITH_CGI /* whether the Openssl is recent enough, and / or built with, ecdh */ #cmakedefine LWS_HAVE_OPENSSL_ECDH_H /* HTTP Proxy support */ #cmakedefine LWS_WITH_HTTP_PROXY /* Http access log support */ #cmakedefine LWS_WITH_ACCESS_LOG #cmakedefine LWS_WITH_SERVER_STATUS /* Maximum supported service threads */ #define LWS_MAX_SMP ${LWS_MAX_SMP} ${LWS_SIZEOFPTR_CODE} |
Added undroid/libwebsockets/lws_config_private.h.in.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* lws_config_private.h.in. Private compilation options. */ #ifndef NDEBUG #ifndef _DEBUG #define _DEBUG #endif #endif /* Define to 1 to use CyaSSL as a replacement for OpenSSL. * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ #cmakedefine USE_CYASSL /* Define to 1 if you have the `bzero' function. */ #cmakedefine LWS_HAVE_BZERO /* Define to 1 if you have the <dlfcn.h> header file. */ #cmakedefine LWS_HAVE_DLFCN_H /* Define to 1 if you have the <fcntl.h> header file. */ #cmakedefine LWS_HAVE_FCNTL_H /* Define to 1 if you have the `fork' function. */ #cmakedefine LWS_HAVE_FORK /* Define to 1 if you have the `getenv’ function. */ #cmakedefine LWS_HAVE_GETENV /* Define to 1 if you have the <in6addr.h> header file. */ #cmakedefine LWS_HAVE_IN6ADDR_H /* Define to 1 if you have the <inttypes.h> header file. */ #cmakedefine LWS_HAVE_INTTYPES_H /* Define to 1 if you have the `ssl' library (-lssl). */ //#cmakedefine LWS_HAVE_LIBSSL /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #cmakedefine LWS_HAVE_MALLOC /* Define to 1 if you have the <memory.h> header file. */ #cmakedefine LWS_HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #cmakedefine LWS_HAVE_MEMSET /* Define to 1 if you have the <netinet/in.h> header file. */ #cmakedefine LWS_HAVE_NETINET_IN_H /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #cmakedefine LWS_HAVE_REALLOC /* Define to 1 if you have the `socket' function. */ #cmakedefine LWS_HAVE_SOCKET /* Define to 1 if you have the <stdint.h> header file. */ #cmakedefine LWS_HAVE_STDINT_H /* Define to 1 if you have the <stdlib.h> header file. */ #cmakedefine LWS_HAVE_STDLIB_H /* Define to 1 if you have the `strerror' function. */ #cmakedefine LWS_HAVE_STRERROR /* Define to 1 if you have the <strings.h> header file. */ #cmakedefine LWS_HAVE_STRINGS_H /* Define to 1 if you have the <string.h> header file. */ #cmakedefine LWS_HAVE_STRING_H /* Define to 1 if you have the <sys/prctl.h> header file. */ #cmakedefine LWS_HAVE_SYS_PRCTL_H /* Define to 1 if you have the <sys/socket.h> header file. */ #cmakedefine LWS_HAVE_SYS_SOCKET_H /* Define to 1 if you have the <sys/stat.h> header file. */ #cmakedefine LWS_HAVE_SYS_STAT_H /* Define to 1 if you have the <sys/types.h> header file. */ #cmakedefine LWS_HAVE_SYS_TYPES_H /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine LWS_HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #cmakedefine LWS_HAVE_VFORK /* Define to 1 if you have the <vfork.h> header file. */ #cmakedefine LWS_HAVE_VFORK_H /* Define to 1 if `fork' works. */ #cmakedefine LWS_HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #cmakedefine LWS_HAVE_WORKING_VFORK /* Define to 1 if execvpe() exists */ #cmakedefine LWS_HAVE_EXECVPE /* Define to 1 if you have the <zlib.h> header file. */ #cmakedefine LWS_HAVE_ZLIB_H #cmakedefine LWS_HAVE_GETLOADAVG /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR // We're not using libtool /* Define to rpl_malloc if the replacement function should be used. */ #cmakedefine malloc /* Define to rpl_realloc if the replacement function should be used. */ #cmakedefine realloc /* Define to 1 if we have getifaddrs */ #cmakedefine LWS_HAVE_GETIFADDRS /* Define if the inline keyword doesn't exist. */ #cmakedefine inline ${inline} |
Added undroid/libwebsockets/lwsws/conf.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets web server application * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "lwsws.h" static const char * const paths_global[] = { "global.uid", "global.gid", "global.count-threads", "global.init-ssl", "global.server-string", "global.plugin-dir" }; enum lejp_global_paths { LEJPGP_UID, LEJPGP_GID, LEJPGP_COUNT_THREADS, LWJPGP_INIT_SSL, LEJPGP_SERVER_STRING, LEJPGP_PLUGIN_DIR }; static const char * const paths_vhosts[] = { "vhosts[]", "vhosts[].mounts[]", "vhosts[].name", "vhosts[].port", "vhosts[].interface", "vhosts[].unix-socket", "vhosts[].sts", "vhosts[].host-ssl-key", "vhosts[].host-ssl-cert", "vhosts[].host-ssl-ca", "vhosts[].access-log", "vhosts[].mounts[].mountpoint", "vhosts[].mounts[].origin", "vhosts[].mounts[].default", "vhosts[].mounts[].cgi-timeout", "vhosts[].mounts[].cgi-env[].*", "vhosts[].mounts[].cache-max-age", "vhosts[].mounts[].cache-reuse", "vhosts[].mounts[].cache-revalidate", "vhosts[].mounts[].cache-intermediaries", "vhosts[].mounts[].extra-mimetypes.*", "vhosts[].ws-protocols[].*.*", "vhosts[].ws-protocols[].*", "vhosts[].ws-protocols[]", "vhosts[].keepalive_timeout", "vhosts[].ciphers", "vhosts[].ecdh-curve", }; enum lejp_vhost_paths { LEJPVP, LEJPVP_MOUNTS, LEJPVP_NAME, LEJPVP_PORT, LEJPVP_INTERFACE, LEJPVP_UNIXSKT, LEJPVP_STS, LEJPVP_HOST_SSL_KEY, LEJPVP_HOST_SSL_CERT, LEJPVP_HOST_SSL_CA, LEJPVP_ACCESS_LOG, LEJPVP_MOUNTPOINT, LEJPVP_ORIGIN, LEJPVP_DEFAULT, LEJPVP_CGI_TIMEOUT, LEJPVP_CGI_ENV, LEJPVP_MOUNT_CACHE_MAX_AGE, LEJPVP_MOUNT_CACHE_REUSE, LEJPVP_MOUNT_CACHE_REVALIDATE, LEJPVP_MOUNT_CACHE_INTERMEDIARIES, LEJPVP_MOUNT_EXTRA_MIMETYPES, LEJPVP_PROTOCOL_NAME_OPT, LEJPVP_PROTOCOL_NAME, LEJPVP_PROTOCOL, LEJPVP_KEEPALIVE_TIMEOUT, LEJPVP_CIPHERS, LEJPVP_ECDH_CURVE, }; #define MAX_PLUGIN_DIRS 10 struct jpargs { struct lws_context_creation_info *info; struct lws_context *context; const struct lws_protocols *protocols; const struct lws_extension *extensions; char *p, *end, valid; struct lws_http_mount *head, *last; struct lws_protocol_vhost_options *pvo; struct lws_protocol_vhost_options *pvo_em; struct lws_http_mount m; const char **plugin_dirs; int count_plugin_dirs; unsigned int fresh_mount:1; }; static void * lwsws_align(struct jpargs *a) { if ((unsigned long)(a->p) & 15) a->p += 16 - ((unsigned long)(a->p) & 15); return a->p; } static int arg_to_bool(const char *s) { static const char * const on[] = { "on", "yes", "true" }; int n = atoi(s); if (n) return 1; for (n = 0; n < ARRAY_SIZE(on); n++) if (!strcasecmp(s, on[n])) return 1; return 0; } static char lejp_globals_cb(struct lejp_ctx *ctx, char reason) { struct jpargs *a = (struct jpargs *)ctx->user; /* we only match on the prepared path strings */ if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) return 0; switch (ctx->path_match - 1) { case LEJPGP_UID: a->info->uid = atoi(ctx->buf); return 0; case LEJPGP_GID: a->info->gid = atoi(ctx->buf); return 0; case LEJPGP_COUNT_THREADS: a->info->count_threads = atoi(ctx->buf); return 0; case LWJPGP_INIT_SSL: if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; return 0; case LEJPGP_SERVER_STRING: a->info->server_string = a->p; break; case LEJPGP_PLUGIN_DIR: if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) { lwsl_err("Too many plugin dirs\n"); return -1; } a->plugin_dirs[a->count_plugin_dirs++] = a->p; break; default: return 0; } a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf); return 0; } static char lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) { struct jpargs *a = (struct jpargs *)ctx->user; struct lws_protocol_vhost_options *pvo, *mp_cgienv; struct lws_http_mount *m; int n; #if 0 lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match); for (n = 0; n < ctx->wildcount; n++) lwsl_notice(" %d\n", ctx->wild[n]); #endif if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) { /* set the defaults for this vhost */ a->valid = 1; a->head = NULL; a->last = NULL; a->info->port = 0; a->info->iface = NULL; a->info->protocols = a->protocols; a->info->extensions = a->extensions; a->info->ssl_cert_filepath = NULL; a->info->ssl_private_key_filepath = NULL; a->info->ssl_ca_filepath = NULL; a->info->timeout_secs = 5; a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "DHE-RSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-SHA384:" "HIGH:!aNULL:!eNULL:!EXPORT:" "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" "!DHE-RSA-AES128-SHA256:" "!AES128-GCM-SHA256:" "!AES128-SHA256:" "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; a->info->pvo = NULL; a->info->keepalive_timeout = 60; a->info->log_filepath = NULL; a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK | LWS_SERVER_OPTION_STS); } if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP_MOUNTS + 1) { a->fresh_mount = 1; memset(&a->m, 0, sizeof(a->m)); } /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */ if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) { a->pvo = lwsws_align(a); a->p += sizeof(*a->pvo); n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ a->pvo->next = a->info->pvo; a->info->pvo = a->pvo; a->pvo->name = a->p; lwsl_notice(" adding protocol %s\n", a->p); a->p += n; a->pvo->value = a->p; a->pvo->options = NULL; a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf); *(a->p)++ = '\0'; } if (reason == LEJPCB_OBJECT_END && (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) && a->valid) { //lwsl_notice("%s\n", ctx->path); if (!a->info->port) { lwsl_err("Port required (eg, 443)"); return 1; } a->valid = 0; a->info->mounts = a->head; if (!lws_create_vhost(a->context, a->info)) { lwsl_err("Failed to create vhost %s\n", a->info->vhost_name); return 1; } return 0; } if (reason == LEJPCB_OBJECT_END && ctx->path_match == LEJPVP_MOUNTS + 1) { static const char * const mount_protocols[] = { "http://", "https://", "file://", "cgi://", ">http://", ">https://", }; if (!a->fresh_mount) return 0; if (!a->m.mountpoint || !a->m.origin) { lwsl_err("mountpoint and origin required\n"); return 1; } lwsl_debug("adding mount %s\n", a->m.mountpoint); m = lwsws_align(a); memcpy(m, &a->m, sizeof(*m)); if (a->last) a->last->mount_next = m; for (n = 0; n < ARRAY_SIZE(mount_protocols); n++) if (!strncmp(a->m.origin, mount_protocols[n], strlen(mount_protocols[n]))) { m->origin_protocol = n; m->origin = a->m.origin + strlen(mount_protocols[n]); break; } if (n == ARRAY_SIZE(mount_protocols)) { lwsl_err("unsupported protocol:// %s\n", a->m.origin); return 1; } a->p += sizeof(*m); if (!a->head) a->head = m; a->last = m; a->fresh_mount = 0; } /* we only match on the prepared path strings */ if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) return 0; switch (ctx->path_match - 1) { case LEJPVP_NAME: a->info->vhost_name = a->p; break; case LEJPVP_PORT: a->info->port = atoi(ctx->buf); return 0; case LEJPVP_INTERFACE: a->info->iface = a->p; break; case LEJPVP_UNIXSKT: if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK; else a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK); return 0; case LEJPVP_STS: if (arg_to_bool(ctx->buf)) a->info->options |= LWS_SERVER_OPTION_STS; else a->info->options &= ~(LWS_SERVER_OPTION_STS); return 0; case LEJPVP_HOST_SSL_KEY: a->info->ssl_private_key_filepath = a->p; break; case LEJPVP_HOST_SSL_CERT: a->info->ssl_cert_filepath = a->p; break; case LEJPVP_HOST_SSL_CA: a->info->ssl_ca_filepath = a->p; break; case LEJPVP_ACCESS_LOG: a->info->log_filepath = a->p; break; case LEJPVP_MOUNTPOINT: a->m.mountpoint = a->p; a->m.mountpoint_len = strlen(ctx->buf); break; case LEJPVP_ORIGIN: a->m.origin = a->p; break; case LEJPVP_DEFAULT: a->m.def = a->p; break; case LEJPVP_MOUNT_CACHE_MAX_AGE: a->m.cache_max_age = atoi(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_REUSE: a->m.cache_reusable = arg_to_bool(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_REVALIDATE: a->m.cache_revalidate = arg_to_bool(ctx->buf); return 0; case LEJPVP_MOUNT_CACHE_INTERMEDIARIES: a->m.cache_intermediaries = arg_to_bool(ctx->buf);; return 0; case LEJPVP_CGI_TIMEOUT: a->m.cgi_timeout = atoi(ctx->buf); return 0; case LEJPVP_KEEPALIVE_TIMEOUT: a->info->keepalive_timeout = atoi(ctx->buf); return 0; case LEJPVP_CIPHERS: a->info->ssl_cipher_list = a->p; break; case LEJPVP_ECDH_CURVE: a->info->ecdh_curve = a->p; break; case LEJPVP_CGI_ENV: mp_cgienv = lwsws_align(a); a->p += sizeof(*a->m.cgienv); mp_cgienv->next = a->m.cgienv; a->m.cgienv = mp_cgienv; n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); mp_cgienv->name = a->p; a->p += n; mp_cgienv->value = a->p; mp_cgienv->options = NULL; a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf); *(a->p)++ = '\0'; lwsl_notice(" adding cgi-env '%s' = '%s'\n", mp_cgienv->name, mp_cgienv->value); break; case LEJPVP_PROTOCOL_NAME_OPT: /* this catches, eg, * vhosts[].ws-protocols[].xxx-protocol.yyy-option * ie, these are options attached to a protocol with { } */ pvo = lwsws_align(a); a->p += sizeof(*a->pvo); n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ pvo->next = a->pvo->options; a->pvo->options = pvo; pvo->name = a->p; a->p += n; pvo->value = a->p; pvo->options = NULL; break; case LEJPVP_MOUNT_EXTRA_MIMETYPES: a->pvo_em = lwsws_align(a); a->p += sizeof(*a->pvo_em); n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p); /* ie, enable this protocol, no options yet */ a->pvo_em->next = a->m.extra_mimetypes; a->m.extra_mimetypes = a->pvo_em; a->pvo_em->name = a->p; lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf); a->p += n; a->pvo_em->value = a->p; a->pvo_em->options = NULL; break; default: return 0; } a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf); *(a->p)++ = '\0'; return 0; } /* * returns 0 = OK, 1 = can't open, 2 = parsing error */ static int lwsws_get_config(void *user, const char *f, const char * const *paths, int count_paths, lejp_callback cb) { unsigned char buf[128]; struct lejp_ctx ctx; int n, m, fd; fd = open(f, O_RDONLY); if (fd < 0) { lwsl_err("Cannot open %s\n", f); return 1; } lwsl_info("%s: %s\n", __func__, f); lejp_construct(&ctx, cb, user, paths, count_paths); do { n = read(fd, buf, sizeof(buf)); if (!n) break; m = (int)(signed char)lejp_parse(&ctx, buf, n); } while (m == LEJP_CONTINUE); close(fd); n = ctx.line; lejp_destruct(&ctx); if (m < 0) { lwsl_err("%s(%u): parsing error %d\n", f, n, m); return 2; } return 0; } #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0 static int lwsws_get_config_d(void *user, const char *d, const char * const *paths, int count_paths, lejp_callback cb) { uv_dirent_t dent; uv_fs_t req; char path[256]; int ret = 0; uv_loop_t loop; uv_loop_init(&loop); if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) { lwsl_err("Scandir on %s failed\n", d); return 1; } while (uv_fs_scandir_next(&req, &dent) != UV_EOF) { lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name); ret = lwsws_get_config(user, path, paths, count_paths, cb); if (ret) goto bail; } bail: uv_fs_req_cleanup(&req); uv_loop_close(&loop); return ret; } #else #ifndef _WIN32 static int filter(const struct dirent *ent) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) return 0; return 1; } #endif static int lwsws_get_config_d(void *user, const char *d, const char * const *paths, int count_paths, lejp_callback cb) { #ifndef _WIN32 struct dirent **namelist; char path[256]; int n, i, ret = 0; n = scandir(d, &namelist, filter, alphasort); if (n < 0) { lwsl_err("Scandir on %d failed\n", d); } for (i = 0; i < n; i++) { lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, namelist[i]->d_name); ret = lwsws_get_config(user, path, paths, count_paths, cb); if (ret) { while (i++ < n) free(namelist[i]); goto bail; } free(namelist[i]); } bail: free(namelist); return ret; #else return 0; #endif } #endif int lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d, char **cs, int *len) { struct jpargs a; const char * const *old = info->plugin_dirs; memset(&a, 0, sizeof(a)); a.info = info; a.p = *cs; a.end = (a.p + *len) - 1; a.valid = 0; lwsws_align(&a); info->plugin_dirs = (void *)a.p; a.plugin_dirs = (void *)a.p; /* writeable version */ a.p += MAX_PLUGIN_DIRS * sizeof(void *); /* copy any default paths */ while (old && *old) { a.plugin_dirs[a.count_plugin_dirs++] = *old; old++; } if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global, ARRAY_SIZE(paths_global), lejp_globals_cb) > 1) return 1; if (lwsws_get_config_d(&a, d, paths_global, ARRAY_SIZE(paths_global), lejp_globals_cb) > 1) return 1; a.plugin_dirs[a.count_plugin_dirs] = NULL; *cs = a.p; *len = a.end - a.p; return 0; } int lwsws_get_config_vhosts(struct lws_context *context, struct lws_context_creation_info *info, const char *d, char **cs, int *len) { struct jpargs a; memset(&a, 0, sizeof(a)); a.info = info; a.p = *cs; a.end = a.p + *len; a.valid = 0; a.context = context; a.protocols = info->protocols; a.extensions = info->extensions; if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts, ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1) return 1; if (lwsws_get_config_d(&a, d, paths_vhosts, ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1) return 1; *cs = a.p; *len = a.end - a.p; lws_finalize_startup(context); return 0; } |
Added undroid/libwebsockets/lwsws/etc-logrotate.d-lwsws.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | /var/log/lwsws/*log { copytruncate missingok notifempty delaycompress postrotate /bin/systemctl reload lwsws.service > /dev/null 2>/dev/null || true endscript } |
Added undroid/libwebsockets/lwsws/etc-lwsws-conf-EXAMPLE.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # these are the server global settings # stuff related to vhosts should go in one # file per vhost in ../conf.d/ { "global": { "uid": "48", "gid": "48", "interface": "eth0", "count-threads": "1", "server-string": "lwsws", "init-ssl": "yes" } } |
Added undroid/libwebsockets/lwsws/etc-lwsws-conf.d-localhost-EXAMPLE.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # comment { "vhosts": [ { "name": "libwebsockets.org", "port": "443", "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", "access-log": "/var/log/httpd/lws-access-log", "sts": "on", "mounts": [{ "mountpoint": "/", "origin": "file:///var/www/libwebsockets.org", "default": "index.html", "cache-max-age": "60", "cache-reuse": "1", "cache-revalidate": "1", "cache-intermediaries": "0" }, { # this hooks us up to cgit cgi part "mountpoint": "/git", "origin": "cgi:///var/www/cgi-bin/cgit", "default": "/", "cgi-env": [{ "CGIT_CONFIG": "/etc/cgitrc/git.libwebsockets.org" }], # we can also set up per-cgi process timeout "cgi-timeout": "30" }, { # this hooks us up to cgit static assets "mountpoint": "/git/cgit-data", "origin": "file:///usr/share/cgit", "default": "/" }, { "mountpoint": "/mailman", "origin": ">https://libwebsockets.org/mailman/listinfo" }, { "mountpoint": "/mailman/listinfo", "origin": "cgi:///usr/lib/mailman/cgi-bin/listinfo" }, { "mountpoint": "/mailman/admin", "origin": "cgi:///usr/lib/mailman/cgi-bin/admin" }, { "mountpoint": "/mailman/admindb", "origin": "cgi:///usr/lib/mailman/cgi-bin/admindb" }, { "mountpoint": "/mailman/confirm", "origin": "cgi:///usr/lib/mailman/cgi-bin/confirm" }, { "mountpoint": "/mailman/create", "origin": "cgi:///usr/lib/mailman/cgi-bin/create" }, { "mountpoint": "/mailman/edithtml", "origin": "cgi:///usr/lib/mailman/cgi-bin/edithtml" }, { "mountpoint": "/mailman/options", "origin": "cgi:///usr/lib/mailman/cgi-bin/options" }, { "mountpoint": "/mailman/private", "origin": "cgi:///usr/lib/mailman/cgi-bin/private" }, { "mountpoint": "/mailman/rmlist", "origin": "cgi:///usr/lib/mailman/cgi-bin/rmlist" }, { "mountpoint": "/mailman/roster", "origin": "cgi:///usr/lib/mailman/cgi-bin/roster" }, { "mountpoint": "/mailman/subscribe", "origin": "cgi:///usr/lib/mailman/cgi-bin/subscribe" }, { "mountpoint": "/pipermail", "origin": "file:///var/lib/mailman/archives/public", "default": "index.html" }, { # we used to have a trac, redirect anyone using it to github "mountpoint": "/trac", "origin": ">https://github.com/warmcat/libwebsockets" }, { "mountpoint": "/server-status", "origin": "file:///usr/local/share/libwebsockets-test-server/server-status", "default": "server-status.html" }, { "mountpoint": "/testserver", "origin": "file:///usr/local/share/libwebsockets-test-server", "default": "test.html" } ], # which protocols are enabled for this vhost, and optional # vhost-specific config options for the protocol # "ws-protocols": [{ "dumb-increment-protocol": { "status": "ok" }, "lws-mirror-protocol": { "status": "ok" }, "lws-status": { "status": "ok" }, "lws-server-status": { "status": "ok", "update-ms": "5000" } }], "ws-extensions": [{ "extension": "permessage-deflate" }] }, # redirect any guys coming in on http to https { "name": "libwebsockets.org", "port": "80", "sts": "on", "mounts": [{ "mountpoint": "/", "origin": ">https://libwebsockets.org" }] }, { # the old test server ran this on :7681, put a redirect # there to take us to the new location "name": "libwebsockets.org", "port": "7681", "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", "mounts": [{ "mountpoint": "/", "origin": ">https://libwebsockets.org/testserver/" }] }, # old site for mailing list redirect to new one { "name": "ml.libwebsockets.org", "port": "80", "mounts": [{ "mountpoint": "/", "origin": ">https://libwebsockets.org/mailman" }] }, # old site for mailing list redirect to new one { "name": "ml.libwebsockets.org", "port": "443", "mounts": [{ "mountpoint": "/", "origin": ">https://libwebsockets.org/mailman" }] }, # redirect any guys coming in on http to https { "name": "git.libwebsockets.org", "port": "80", "mounts": [{ "mountpoint": "/", "origin": ">https://libwebsockets.org/git" }] }, { # the old test server ran this on :7681, put a redirect # there to take us to the new location "name": "git.libwebsockets.org", "port": "443", "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", "mounts": [{ "mountpoint": "/", "origin": ">https://libwebsockets.org/git" }] } }] } |
Added undroid/libwebsockets/lwsws/http.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets web server application * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "lwsws.h" /* http server gets files from this path */ #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" char *resource_path = LOCAL_RESOURCE_PATH; /* * We take a strict whitelist approach to stop ../ attacks */ struct serveable { const char *urlpath; const char *mimetype; }; const char * get_mimetype(const char *file) { int n = strlen(file); if (n < 5) return NULL; if (!strcmp(&file[n - 4], ".ico")) return "image/x-icon"; if (!strcmp(&file[n - 4], ".png")) return "image/png"; if (!strcmp(&file[n - 4], ".jpg")) return "image/jpeg"; if (!strcmp(&file[n - 5], ".html")) return "text/html"; if (!strcmp(&file[n - 4], ".css")) return "text/css"; return NULL; } /* this protocol server (always the first one) handles HTTP, * * Some misc callbacks that aren't associated with a protocol also turn up only * here on the first protocol server. */ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__http *pss = (struct per_session_data__http *)user; unsigned char buffer[4096 + LWS_PRE]; char leaf_path[1024]; const char *mimetype; char *other_headers; unsigned char *end, *start; struct timeval tv; unsigned char *p; #ifndef LWS_NO_CLIENT struct per_session_data__http *pss1; struct lws *wsi1; #endif char buf[256]; char b64[64]; int n, m; #ifdef EXTERNAL_POLL struct lws_pollargs *pa = (struct lws_pollargs *)in; #endif // lwsl_err("%s: reason %d\n", __func__, reason); switch (reason) { case LWS_CALLBACK_HTTP: { char name[100], rip[50]; lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip)); sprintf(buf, "%s (%s)", name, rip); lwsl_notice("HTTP connect from %s\n", buf); } if (len < 1) { lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } #ifndef LWS_NO_CLIENT if (!strncmp(in, "/proxytest", 10)) { struct lws_client_connect_info i; char *rootpath = "/"; const char *p = (const char *)in; if (lws_get_child(wsi)) break; pss->client_finished = 0; memset(&i,0, sizeof(i)); i.context = lws_get_context(wsi); i.address = "git.libwebsockets.org"; i.port = 80; i.ssl_connection = 0; if (p[10]) i.path = (char *)in + 10; else i.path = rootpath; i.host = "git.libwebsockets.org"; i.origin = NULL; i.method = "GET"; i.parent_wsi = wsi; i.uri_replace_from = "git.libwebsockets.org/"; i.uri_replace_to = "/proxytest/"; if (!lws_client_connect_via_info(&i)) { lwsl_err("proxy connect fail\n"); break; } break; } #endif #if 0 /* this example server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL); goto try_to_reuse; } #endif if (strlen(in) >= 12 && !strncmp((char *)in + strlen(in) - 12, "/postresults", 12)) { m = sprintf(buf, "<html><body>Form results: '%s'<br>" "</body></html>", pss->post_string); p = buffer + LWS_PRE; start = p; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, m, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n < 0) return 1; n = lws_write(wsi, (unsigned char *)buf, m, LWS_WRITE_HTTP); if (n < 0) return 1; goto try_to_reuse; } /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; strncpy(buf, resource_path, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(buf) - 1); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); lws_return_http_status(wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demonstrates how to set a cookie on / */ other_headers = leaf_path; p = (unsigned char *)leaf_path; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)b64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; } if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *) "max-age=15768000 ; " "includeSubDomains", 36, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; n = (char *)p - leaf_path; n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: lwsl_notice("LWS_CALLBACK_HTTP_BODY: len %d\n", (int)len); strncpy(pss->post_string, in, sizeof (pss->post_string) -1); pss->post_string[sizeof(pss->post_string) - 1] = '\0'; break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* * the whole of the sent body arrived, * respond to the client with a redirect to show the * results */ p = (unsigned char *)buf + LWS_PRE; n = lws_http_redirect(wsi, HTTP_STATUS_SEE_OTHER, /* 303 */ (unsigned char *)"postresults", 12, /* location + len */ &p, /* temp buffer to use */ p + sizeof(buf) - 1 - LWS_PRE /* buffer len */ ); goto try_to_reuse; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: // lwsl_notice("LWS_CALLBACK_HTTP_WRITEABLE\n"); #ifdef LWS_WITH_CGI if (pss->reason_bf & 1) { if (lws_cgi_write_split_stdout_headers(wsi) < 0) { lwsl_debug("lws_cgi_write_split_stdout_headers says close\n"); return -1; } pss->reason_bf &= ~1; break; } #endif #ifndef LWS_NO_CLIENT if (pss->reason_bf & 2) { char *px = buf + LWS_PRE; int lenx = sizeof(buf) - LWS_PRE; /* * our sink is writeable and our source has something * to read. So read a lump of source material of * suitable size to send or what's available, whichever * is the smaller. */ pss->reason_bf &= ~2; wsi1 = lws_get_child(wsi); if (!wsi1) break; if (lws_http_client_read(wsi1, &px, &lenx) < 0) return -1; if (pss->client_finished) return -1; break; } #endif break; #ifndef LWS_NO_CLIENT case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: { char ctype[64], ctlen = 0; lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n"); p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(lws_get_parent(wsi), 200, &p, end)) return 1; if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE); if (ctlen > 0) { if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)ctype, ctlen, &p, end)) return 1; } #if 0 if (lws_add_http_header_content_length(lws_get_parent(wsi), file_len, &p, end)) return 1; #endif if (lws_finalize_http_header(lws_get_parent(wsi), &p, end)) return 1; *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) return -1; break; } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); return -1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; // lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p: sock: %d, parent_wsi: %p, parent_sock:%d, len %d\n", // wsi, lws_get_socket_fd(wsi), // lws_get_parent(wsi), // lws_get_socket_fd(lws_get_parent(wsi)), len); pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->reason_bf |= 2; lws_callback_on_writable(lws_get_parent(wsi)); break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len); assert(lws_get_parent(wsi)); m = lws_write(lws_get_parent(wsi), (unsigned char *)in, len, LWS_WRITE_HTTP); if (m < 0) return -1; break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n"); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->client_finished = 1; break; #endif #ifdef LWS_WITH_CGI /* CGI IO events (POLLIN/OUT) appear here our demo user code policy is * * - POST data goes on subprocess stdin * - subprocess stdout goes on http via writeable callback * - subprocess stderr goes to the logs */ case LWS_CALLBACK_CGI: pss->args = *((struct lws_cgi_args *)in); //lwsl_notice("LWS_CALLBACK_CGI: ch %d\n", pss->args.ch); switch (pss->args.ch) { /* which of stdin/out/err ? */ case LWS_STDIN: /* TBD stdin rx flow control */ break; case LWS_STDOUT:; pss->reason_bf |= 1; /* when writing to MASTER would not block */ lws_callback_on_writable(wsi); break; case LWS_STDERR: n = read(lws_get_socket_fd(pss->args.stdwsi[LWS_STDERR]), buf, 127); //lwsl_notice("stderr reads %d\n", n); if (n > 0) { if (buf[n - 1] != '\n') buf[n++] = '\n'; buf[n] = '\0'; lwsl_notice("CGI-stderr: %s\n", buf); } break; } break; case LWS_CALLBACK_CGI_TERMINATED: //lwsl_notice("LWS_CALLBACK_CGI_TERMINATED\n"); /* because we sent on openended http, close the connection */ return -1; case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */ lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA\n"); pss->args = *((struct lws_cgi_args *)in); pss->args.data[pss->args.len] = '\0'; //lwsl_err("(stdin fd = %d) %s\n", lws_get_socket_fd(pss->args.stdwsi[LWS_STDIN]), pss->args.data); n = write(lws_get_socket_fd(pss->args.stdwsi[LWS_STDIN]), pss->args.data, pss->args.len); //lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: write says %d", n); if (n < pss->args.len) lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: sent %d only %d went", n, pss->args.len); return n; #endif /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: test_server_lock(len); break; case LWS_CALLBACK_UNLOCK_POLL: test_server_unlock(len); break; case LWS_CALLBACK_GET_THREAD_ID: /* return pthread_getthreadid_np(); */ break; default: break; } return 0; /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */ try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; } |
Added undroid/libwebsockets/lwsws/lejp.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * Lightweight Embedded JSON Parser * * Copyright (C) 2013 Andy Green <andy@warmcat.com> * This code is licensed under LGPL 2.1 * http://www.gnu.org/licenses/lgpl-2.1.html */ #include <string.h> #include "lejp.h" #include <stdio.h> /** * lejp_construct - prepare a struct lejp_ctx for use * * @ctx: pointer to your struct lejp_ctx * @callback: your user callback which will received parsed tokens * @user: optional user data pointer untouched by lejp * @paths: your array of name elements you are interested in * @count_paths: ARRAY_SIZE() of @paths * * Prepares your context struct for use with lejp */ void lejp_construct(struct lejp_ctx *ctx, char (*callback)(struct lejp_ctx *ctx, char reason), void *user, const char * const *paths, unsigned char count_paths) { ctx->st[0].s = 0; ctx->st[0].p = 0; ctx->st[0].i = 0; ctx->st[0].b = 0; ctx->sp = 0; ctx->ipos = 0; ctx->ppos = 0; ctx->path_match = 0; ctx->path[0] = '\0'; ctx->callback = callback; ctx->user = user; ctx->paths = paths; ctx->count_paths = count_paths; ctx->line = 1; ctx->callback(ctx, LEJPCB_CONSTRUCTED); } /** * lejp_destruct - retire a previously constructed struct lejp_ctx * * @ctx: pointer to your struct lejp_ctx * * lejp does not perform any allocations, but since your user code might, this * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where * you can clean up in your callback. */ void lejp_destruct(struct lejp_ctx *ctx) { /* no allocations... just let callback know what it happening */ ctx->callback(ctx, LEJPCB_DESTRUCTED); } /** * lejp_change_callback - switch to a different callback from now on * * @ctx: pointer to your struct lejp_ctx * @callback: your user callback which will received parsed tokens * * This tells the old callback it was destroyed, in case you want to take any * action because that callback "lost focus", then changes to the new * callback and tells it first that it was constructed, and then started. * * Changing callback is a cheap and powerful trick to split out handlers * according to information earlier in the parse. For example you may have * a JSON pair "schema" whose value defines what can be expected for the rest * of the JSON. Rather than having one huge callback for all cases, you can * have an initial one looking for "schema" which then calls * lejp_change_callback() to a handler specific for the schema. * * Notice that afterwards, you need to construct the context again anyway to * parse another JSON object, and the callback is reset then to the main, * schema-interpreting one. The construction action is very lightweight. */ void lejp_change_callback(struct lejp_ctx *ctx, char (*callback)(struct lejp_ctx *ctx, char reason)) { ctx->callback(ctx, LEJPCB_DESTRUCTED); ctx->callback = callback; ctx->callback(ctx, LEJPCB_CONSTRUCTED); ctx->callback(ctx, LEJPCB_START); } static void lejp_check_path_match(struct lejp_ctx *ctx) { const char *p, *q; int n; /* we only need to check if a match is not active */ for (n = 0; !ctx->path_match && n < ctx->count_paths; n++) { ctx->wildcount = 0; p = ctx->path; q = ctx->paths[n]; while (*p && *q) { if (*q != '*') { if (*p != *q) break; p++; q++; continue; } ctx->wild[ctx->wildcount++] = p - ctx->path; q++; /* * if * has something after it, match to . * if ends with *, eat everything. * This implies match sequences must be ordered like * x.*.* * x.* * if both options are possible */ while (*p && (*p != '.' || !*q)) p++; } if (*p || *q) continue; ctx->path_match = n + 1; ctx->path_match_len = ctx->ppos; return; } if (!ctx->path_match) ctx->wildcount = 0; } int lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len) { int n; if (wildcard >= ctx->wildcount || !len) return 0; n = ctx->wild[wildcard]; while (--len && n < ctx->ppos && (n == ctx->wild[wildcard] || ctx->path[n] != '.')) *dest++ = ctx->path[n++]; *dest = '\0'; n++; return n - ctx->wild[wildcard]; } /** * lejp_parse - interpret some more incoming data incrementally * * @ctx: previously constructed parsing context * @json: char buffer with the new data to interpret * @len: amount of data in the buffer * * Because lejp is a stream parser, it incrementally parses as new data * becomes available, maintaining all state in the context struct. So an * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE * return, signalling there's no error but to call again with more data when * it comes to complete the parsing. Successful parsing completes with a * 0 or positive integer indicating how much of the last input buffer was * unused. */ int lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len) { unsigned char c, n, s, ret = LEJP_REJECT_UNKNOWN; static const char esc_char[] = "\"\\/bfnrt"; static const char esc_tran[] = "\"\\/\b\f\n\r\t"; static const char tokens[] = "rue alse ull "; if (!ctx->sp && !ctx->ppos) ctx->callback(ctx, LEJPCB_START); while (len--) { c = *json++; s = ctx->st[ctx->sp].s; /* skip whitespace unless we should care */ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') { if (c == '\n') { ctx->line++; ctx->st[ctx->sp].s &= ~LEJP_FLAG_WS_COMMENTLINE; } if (!(s & LEJP_FLAG_WS_KEEP)) { if (c == '#') ctx->st[ctx->sp].s |= LEJP_FLAG_WS_COMMENTLINE; continue; } } if (ctx->st[ctx->sp].s & LEJP_FLAG_WS_COMMENTLINE) continue; switch (s) { case LEJP_IDLE: if (c != '{') { ret = LEJP_REJECT_IDLE_NO_BRACE; goto reject; } ctx->callback(ctx, LEJPCB_OBJECT_START); ctx->st[ctx->sp].s = LEJP_MEMBERS; break; case LEJP_MEMBERS: if (c == '}') { ctx->st[ctx->sp].s = LEJP_IDLE; ret = LEJP_REJECT_MEMBERS_NO_CLOSE; goto reject; } ctx->st[ctx->sp].s = LEJP_M_P; goto redo_character; case LEJP_M_P: if (c != '\"') { ret = LEJP_REJECT_MP_NO_OPEN_QUOTE; goto reject; } /* push */ ctx->st[ctx->sp].s = LEJP_MP_DELIM; c = LEJP_MP_STRING; goto add_stack_level; case LEJP_MP_STRING: if (c == '\"') { if (!ctx->sp) { ret = LEJP_REJECT_MP_STRING_UNDERRUN; goto reject; } if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) { ctx->buf[ctx->npos] = '\0'; if (ctx->callback(ctx, LEJPCB_VAL_STR_END) < 0) { ret = LEJP_REJECT_CALLBACK; goto reject; } } /* pop */ ctx->sp--; break; } if (c == '\\') { ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC; break; } if (c < ' ') {/* "control characters" not allowed */ ret = LEJP_REJECT_MP_ILLEGAL_CTRL; goto reject; } goto emit_string_char; case LEJP_MP_STRING_ESC: if (c == 'u') { ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC_U1; ctx->uni = 0; break; } for (n = 0; n < sizeof(esc_char); n++) { if (c != esc_char[n]) continue; /* found it */ c = esc_tran[n]; ctx->st[ctx->sp].s = LEJP_MP_STRING; goto emit_string_char; } ret = LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC; /* illegal escape char */ goto reject; case LEJP_MP_STRING_ESC_U1: case LEJP_MP_STRING_ESC_U2: case LEJP_MP_STRING_ESC_U3: case LEJP_MP_STRING_ESC_U4: ctx->uni <<= 4; if (c >= '0' && c <= '9') ctx->uni |= c - '0'; else if (c >= 'a' && c <= 'f') ctx->uni = c - 'a' + 10; else if (c >= 'A' && c <= 'F') ctx->uni = c - 'A' + 10; else { ret = LEJP_REJECT_ILLEGAL_HEX; goto reject; } ctx->st[ctx->sp].s++; switch (s) { case LEJP_MP_STRING_ESC_U2: if (ctx->uni < 0x08) break; /* * 0x08-0xff (0x0800 - 0xffff) * emit 3-byte UTF-8 */ c = 0xe0 | ((ctx->uni >> 4) & 0xf); goto emit_string_char; case LEJP_MP_STRING_ESC_U3: if (ctx->uni >= 0x080) { /* * 0x080 - 0xfff (0x0800 - 0xffff) * middle 3-byte seq * send ....XXXXXX.. */ c = 0x80 | ((ctx->uni >> 2) & 0x3f); goto emit_string_char; } if (ctx->uni < 0x008) break; /* * 0x008 - 0x7f (0x0080 - 0x07ff) * start 2-byte seq */ c = 0xc0 | (ctx->uni >> 2); goto emit_string_char; case LEJP_MP_STRING_ESC_U4: if (ctx->uni >= 0x0080) /* end of 2 or 3-byte seq */ c = 0x80 | (ctx->uni & 0x3f); else /* literal */ c = (unsigned char)ctx->uni; ctx->st[ctx->sp].s = LEJP_MP_STRING; goto emit_string_char; default: break; } break; case LEJP_MP_DELIM: if (c != ':') { ret = LEJP_REJECT_MP_DELIM_MISSING_COLON; goto reject; } ctx->st[ctx->sp].s = LEJP_MP_VALUE; ctx->path[ctx->ppos] = '\0'; lejp_check_path_match(ctx); ctx->callback(ctx, LEJPCB_PAIR_NAME); break; case LEJP_MP_VALUE: if (c >= '0' && c <= '9') { ctx->npos = 0; ctx->dcount = 0; ctx->f = 0; ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT; goto redo_character; } switch (c) { case'\"': /* push */ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; c = LEJP_MP_STRING; ctx->npos = 0; ctx->buf[0] = '\0'; ctx->callback(ctx, LEJPCB_VAL_STR_START); goto add_stack_level; case '{': /* push */ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; c = LEJP_MEMBERS; lejp_check_path_match(ctx); ctx->callback(ctx, LEJPCB_OBJECT_START); ctx->path_match = 0; goto add_stack_level; case '[': /* push */ ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END; c = LEJP_MP_VALUE; ctx->path[ctx->ppos++] = '['; ctx->path[ctx->ppos++] = ']'; ctx->path[ctx->ppos] = '\0'; ctx->callback(ctx, LEJPCB_ARRAY_START); ctx->i[ctx->ipos++] = 0; if (ctx->ipos > ARRAY_SIZE(ctx->i)) { ret = LEJP_REJECT_MP_DELIM_ISTACK; goto reject; } goto add_stack_level; case 't': /* true */ ctx->uni = 0; ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK; break; case 'f': ctx->uni = 4; ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK; break; case 'n': ctx->uni = 4 + 5; ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK; break; default: ret = LEJP_REJECT_MP_DELIM_BAD_VALUE_START; goto reject; } break; case LEJP_MP_VALUE_NUM_INT: if (!ctx->npos && c == '-') { ctx->f |= LEJP_SEEN_MINUS; goto append_npos; } if (ctx->dcount < 10 && c >= '0' && c <= '9') { if (ctx->f & LEJP_SEEN_POINT) ctx->f |= LEJP_SEEN_POST_POINT; ctx->dcount++; goto append_npos; } if (c == '.') { if (ctx->dcount || (ctx->f & LEJP_SEEN_POINT)) { ret = LEJP_REJECT_MP_VAL_NUM_FORMAT; goto reject; } ctx->f |= LEJP_SEEN_POINT; goto append_npos; } /* * before exponent, if we had . we must have had at * least one more digit */ if ((ctx->f & (LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) == LEJP_SEEN_POINT) { ret = LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC; goto reject; } if (c == 'e' || c == 'E') { if (ctx->f & LEJP_SEEN_EXP) { ret = LEJP_REJECT_MP_VAL_NUM_FORMAT; goto reject; } ctx->f |= LEJP_SEEN_EXP; ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_EXP; goto append_npos; } /* if none of the above, did we even have a number? */ if (!ctx->dcount) { ret = LEJP_REJECT_MP_VAL_NUM_FORMAT; goto reject; } ctx->buf[ctx->npos] = '\0'; if (ctx->f & LEJP_SEEN_POINT) ctx->callback(ctx, LEJPCB_VAL_NUM_FLOAT); else ctx->callback(ctx, LEJPCB_VAL_NUM_INT); /* then this is the post-number character, loop */ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; goto redo_character; case LEJP_MP_VALUE_NUM_EXP: ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT; if (c >= '0' && c <= '9') goto redo_character; if (c == '+' || c == '-') goto append_npos; ret = LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP; goto reject; case LEJP_MP_VALUE_TOK: /* true, false, null */ if (c != tokens[ctx->uni]) { ret = LEJP_REJECT_MP_VAL_TOK_UNKNOWN; goto reject; } ctx->uni++; if (tokens[ctx->uni] != ' ') break; switch (ctx->uni) { case 3: ctx->buf[0] = '1'; ctx->buf[1] = '\0'; ctx->callback(ctx, LEJPCB_VAL_TRUE); break; case 8: ctx->buf[0] = '0'; ctx->buf[1] = '\0'; ctx->callback(ctx, LEJPCB_VAL_FALSE); break; case 12: ctx->buf[0] = '\0'; ctx->callback(ctx, LEJPCB_VAL_NULL); break; } ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; break; case LEJP_MP_COMMA_OR_END: ctx->path[ctx->ppos] = '\0'; if (c == ',') { /* increment this stack level's index */ ctx->st[ctx->sp].s = LEJP_M_P; if (!ctx->sp) { ctx->ppos = 0; /* * since we came back to root level, * no path can still match */ ctx->path_match = 0; break; } ctx->ppos = ctx->st[ctx->sp - 1].p; ctx->path[ctx->ppos] = '\0'; if (ctx->path_match && ctx->ppos <= ctx->path_match_len) /* * we shrank the path to be * smaller than the matching point */ ctx->path_match = 0; if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END) break; /* top level is definitely an array... */ if (ctx->ipos) ctx->i[ctx->ipos - 1]++; ctx->st[ctx->sp].s = LEJP_MP_VALUE; break; } if (c == ']') { if (!ctx->sp) { ret = LEJP_REJECT_MP_C_OR_E_UNDERF; goto reject; } /* pop */ ctx->sp--; if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) { ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY; goto reject; } /* drop the path [n] bit */ ctx->ppos = ctx->st[ctx->sp - 1].p; ctx->ipos = ctx->st[ctx->sp - 1].i; ctx->path[ctx->ppos] = '\0'; if (ctx->path_match && ctx->ppos <= ctx->path_match_len) /* * we shrank the path to be * smaller than the matching point */ ctx->path_match = 0; /* do LEJP_MP_ARRAY_END processing */ goto redo_character; } if (c == '}') { if (ctx->sp == 0) { lejp_check_path_match(ctx); ctx->callback(ctx, LEJPCB_OBJECT_END); ctx->callback(ctx, LEJPCB_COMPLETE); /* done, return unused amount */ return len; } /* pop */ ctx->sp--; ctx->ppos = ctx->st[ctx->sp - 1].p; ctx->ipos = ctx->st[ctx->sp - 1].i; ctx->path[ctx->ppos] = '\0'; if (ctx->path_match && ctx->ppos <= ctx->path_match_len) /* * we shrank the path to be * smaller than the matching point */ ctx->path_match = 0; lejp_check_path_match(ctx); ctx->callback(ctx, LEJPCB_OBJECT_END); break; } ret = LEJP_REJECT_MP_C_OR_E_NEITHER; goto reject; case LEJP_MP_ARRAY_END: ctx->path[ctx->ppos] = '\0'; if (c == ',') { /* increment this stack level's index */ if (ctx->ipos) ctx->i[ctx->ipos - 1]++; ctx->st[ctx->sp].s = LEJP_MP_VALUE; if (ctx->sp) ctx->ppos = ctx->st[ctx->sp - 1].p; ctx->path[ctx->ppos] = '\0'; break; } if (c != ']') { ret = LEJP_REJECT_MP_ARRAY_END_MISSING; goto reject; } ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; ctx->callback(ctx, LEJPCB_ARRAY_END); break; } continue; emit_string_char: if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) { /* assemble the string value into chunks */ ctx->buf[ctx->npos++] = c; if (ctx->npos == sizeof(ctx->buf) - 1) { ctx->callback(ctx, LEJPCB_VAL_STR_CHUNK); ctx->npos = 0; } continue; } /* name part of name:value pair */ ctx->path[ctx->ppos++] = c; continue; add_stack_level: /* push on to the object stack */ if (ctx->ppos && ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END && ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) ctx->path[ctx->ppos++] = '.'; ctx->st[ctx->sp].p = ctx->ppos; ctx->st[ctx->sp].i = ctx->ipos; if (++ctx->sp == ARRAY_SIZE(ctx->st)) { ret = LEJP_REJECT_STACK_OVERFLOW; goto reject; } ctx->path[ctx->ppos] = '\0'; ctx->st[ctx->sp].s = c; ctx->st[ctx->sp].b = 0; continue; append_npos: if (ctx->npos >= sizeof(ctx->buf)) { ret = LEJP_REJECT_NUM_TOO_LONG; goto reject; } ctx->buf[ctx->npos++] = c; continue; redo_character: json--; len++; } return LEJP_CONTINUE; reject: ctx->callback(ctx, LEJPCB_FAILED); return ret; } |
Added undroid/libwebsockets/lwsws/lejp.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include "../lib/libwebsockets.h" struct lejp_ctx; #ifndef ARRAY_SIZE #define ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0])) #endif #define LEJP_FLAG_WS_KEEP 64 #define LEJP_FLAG_WS_COMMENTLINE 32 enum lejp_states { LEJP_IDLE = 0, LEJP_MEMBERS = 1, LEJP_M_P = 2, LEJP_MP_STRING = LEJP_FLAG_WS_KEEP | 3, LEJP_MP_STRING_ESC = LEJP_FLAG_WS_KEEP | 4, LEJP_MP_STRING_ESC_U1 = LEJP_FLAG_WS_KEEP | 5, LEJP_MP_STRING_ESC_U2 = LEJP_FLAG_WS_KEEP | 6, LEJP_MP_STRING_ESC_U3 = LEJP_FLAG_WS_KEEP | 7, LEJP_MP_STRING_ESC_U4 = LEJP_FLAG_WS_KEEP | 8, LEJP_MP_DELIM = 9, LEJP_MP_VALUE = 10, LEJP_MP_VALUE_NUM_INT = LEJP_FLAG_WS_KEEP | 11, LEJP_MP_VALUE_NUM_EXP = LEJP_FLAG_WS_KEEP | 12, LEJP_MP_VALUE_TOK = LEJP_FLAG_WS_KEEP | 13, LEJP_MP_COMMA_OR_END = 14, LEJP_MP_ARRAY_END = 15, }; enum lejp_reasons { LEJP_CONTINUE = -1, LEJP_REJECT_IDLE_NO_BRACE = -2, LEJP_REJECT_MEMBERS_NO_CLOSE = -3, LEJP_REJECT_MP_NO_OPEN_QUOTE = -4, LEJP_REJECT_MP_STRING_UNDERRUN = -5, LEJP_REJECT_MP_ILLEGAL_CTRL = -6, LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC = -7, LEJP_REJECT_ILLEGAL_HEX = -8, LEJP_REJECT_MP_DELIM_MISSING_COLON = -9, LEJP_REJECT_MP_DELIM_BAD_VALUE_START = -10, LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC = -11, LEJP_REJECT_MP_VAL_NUM_FORMAT = -12, LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP = -13, LEJP_REJECT_MP_VAL_TOK_UNKNOWN = -14, LEJP_REJECT_MP_C_OR_E_UNDERF = -15, LEJP_REJECT_MP_C_OR_E_NOTARRAY = -16, LEJP_REJECT_MP_ARRAY_END_MISSING = -17, LEJP_REJECT_STACK_OVERFLOW = -18, LEJP_REJECT_MP_DELIM_ISTACK = -19, LEJP_REJECT_NUM_TOO_LONG = -20, LEJP_REJECT_MP_C_OR_E_NEITHER = -21, LEJP_REJECT_UNKNOWN = -22, LEJP_REJECT_CALLBACK = -23 }; #define LEJP_FLAG_CB_IS_VALUE 64 enum lejp_callbacks { LEJPCB_CONSTRUCTED = 0, LEJPCB_DESTRUCTED = 1, LEJPCB_START = 2, LEJPCB_COMPLETE = 3, LEJPCB_FAILED = 4, LEJPCB_PAIR_NAME = 5, LEJPCB_VAL_TRUE = LEJP_FLAG_CB_IS_VALUE | 6, LEJPCB_VAL_FALSE = LEJP_FLAG_CB_IS_VALUE | 7, LEJPCB_VAL_NULL = LEJP_FLAG_CB_IS_VALUE | 8, LEJPCB_VAL_NUM_INT = LEJP_FLAG_CB_IS_VALUE | 9, LEJPCB_VAL_NUM_FLOAT = LEJP_FLAG_CB_IS_VALUE | 10, LEJPCB_VAL_STR_START = 11, /* notice handle separately */ LEJPCB_VAL_STR_CHUNK = LEJP_FLAG_CB_IS_VALUE | 12, LEJPCB_VAL_STR_END = LEJP_FLAG_CB_IS_VALUE | 13, LEJPCB_ARRAY_START = 14, LEJPCB_ARRAY_END = 15, LEJPCB_OBJECT_START = 16, LEJPCB_OBJECT_END = 17 }; /** * _lejp_callback() - User parser actions * @ctx: LEJP context * @reason: Callback reason * * Your user callback is associated with the context at construction time, * and receives calls as the parsing progresses. * * All of the callbacks may be ignored and just return 0. * * The reasons it might get called, found in @reason, are: * * LEJPCB_CONSTRUCTED: The context was just constructed... you might want to * perform one-time allocation for the life of the context. * * LEJPCB_DESTRUCTED: The context is being destructed... if you made any * allocations at construction-time, you can free them now * * LEJPCB_START: Parsing is beginning at the first byte of input * * LEJPCB_COMPLETE: Parsing has completed successfully. You'll get a 0 or * positive return code from lejp_parse indicating the * amount of unused bytes left in the input buffer * * LEJPCB_FAILED: Parsing failed. You'll get a negative error code * returned from lejp_parse * * LEJPCB_PAIR_NAME: When a "name":"value" pair has had the name parsed, * this callback occurs. You can find the new name at * the end of ctx->path[] * * LEJPCB_VAL_TRUE: The "true" value appeared * * LEJPCB_VAL_FALSE: The "false" value appeared * * LEJPCB_VAL_NULL: The "null" value appeared * * LEJPCB_VAL_NUM_INT: A string representing an integer is in ctx->buf * * LEJPCB_VAL_NUM_FLOAT: A string representing a float is in ctx->buf * * LEJPCB_VAL_STR_START: We are starting to parse a string, no data yet * * LEJPCB_VAL_STR_CHUNK: We parsed LEJP_STRING_CHUNK -1 bytes of string data in * ctx->buf, which is as much as we can buffer, so we are * spilling it. If all your strings are less than * LEJP_STRING_CHUNK - 1 bytes, you will never see this * callback. * * LEJPCB_VAL_STR_END: String parsing has completed, the last chunk of the * string is in ctx->buf. * * LEJPCB_ARRAY_START: An array started * * LEJPCB_ARRAY_END: An array ended * * LEJPCB_OBJECT_START: An object started * * LEJPCB_OBJECT_END: An object ended */ LWS_EXTERN char _lejp_callback(struct lejp_ctx *ctx, char reason); typedef char (*lejp_callback)(struct lejp_ctx *ctx, char reason); #ifndef LEJP_MAX_DEPTH #define LEJP_MAX_DEPTH 12 #endif #ifndef LEJP_MAX_INDEX_DEPTH #define LEJP_MAX_INDEX_DEPTH 5 #endif #ifndef LEJP_MAX_PATH #define LEJP_MAX_PATH 128 #endif #ifndef LEJP_STRING_CHUNK /* must be >= 30 to assemble floats */ #define LEJP_STRING_CHUNK 128 #endif enum num_flags { LEJP_SEEN_MINUS = (1 << 0), LEJP_SEEN_POINT = (1 << 1), LEJP_SEEN_POST_POINT = (1 << 2), LEJP_SEEN_EXP = (1 << 3) }; struct _lejp_stack { char s; /* lejp_state stack*/ char p; /* path length */ char i; /* index array length */ char b; /* user bitfield */ }; struct lejp_ctx { /* sorted by type for most compact alignment * * pointers */ char (*callback)(struct lejp_ctx *ctx, char reason); void *user; const char * const *paths; /* arrays */ struct _lejp_stack st[LEJP_MAX_DEPTH]; unsigned short i[LEJP_MAX_INDEX_DEPTH]; /* index array */ unsigned short wild[LEJP_MAX_INDEX_DEPTH]; /* index array */ char path[LEJP_MAX_PATH]; char buf[LEJP_STRING_CHUNK]; /* int */ unsigned int line; /* short */ unsigned short uni; /* char */ unsigned char npos; unsigned char dcount; unsigned char f; unsigned char sp; /* stack head */ unsigned char ipos; /* index stack depth */ unsigned char ppos; unsigned char count_paths; unsigned char path_match; unsigned char path_match_len; unsigned char wildcount; }; LWS_EXTERN void lejp_construct(struct lejp_ctx *ctx, char (*callback)(struct lejp_ctx *ctx, char reason), void *user, const char * const *paths, unsigned char paths_count); LWS_EXTERN void lejp_destruct(struct lejp_ctx *ctx); LWS_EXTERN int lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len); LWS_EXTERN void lejp_change_callback(struct lejp_ctx *ctx, char (*callback)(struct lejp_ctx *ctx, char reason)); LWS_EXTERN int lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len); |
Added undroid/libwebsockets/lwsws/lwsws.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #if defined(_WIN32) && defined(EXTERNAL_POLL) #define WINVER 0x0600 #define _WIN32_WINNT 0x0600 #define poll(fdArray, fds, timeout) WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout)) #endif #include "lws_config.h" #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <signal.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #ifndef _WIN32 #include <dirent.h> #endif #include "../lib/libwebsockets.h" #include "lejp.h" #ifdef _WIN32 #include <io.h> #include "gettimeofday.h" #else #include <syslog.h> #include <sys/time.h> #include <unistd.h> #endif extern void test_server_lock(int care); extern void test_server_unlock(int care); #ifndef __func__ #define __func__ __FUNCTION__ #endif struct per_session_data__http { lws_filefd_type fd; #ifdef LWS_WITH_CGI struct lws_cgi_args args; #endif #if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT) int reason_bf; #endif char post_string[256]; unsigned int client_finished:1; }; extern int lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d, char **config_strings, int *len); extern int lwsws_get_config_vhosts(struct lws_context *context, struct lws_context_creation_info *info, const char *d, char **config_strings, int *len); extern int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); |
Added undroid/libwebsockets/lwsws/main.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets web server application * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "lwsws.h" int debug_level = 7; volatile int force_exit = 0; struct lws_context *context; static char *config_dir = "/etc/lwsws/conf.d"; /* * strings and objects from the config file parsing are created here */ #define LWSWS_CONFIG_STRING_SIZE (32 * 1024) char config_strings[LWSWS_CONFIG_STRING_SIZE]; /* singlethreaded version --> no locks */ void test_server_lock(int care) { } void test_server_unlock(int care) { } enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, /* always last */ DEMO_PROTOCOL_COUNT }; /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http, /* callback */ sizeof (struct per_session_data__http), /* per_session_data_size */ 0, /* max frame size / rx buffer */ }, { NULL, NULL, 0, 0 } }; void sighandler(int sig) { force_exit = 1; lws_cancel_service(context); } static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate" }, { NULL, NULL, NULL /* terminator */ } }; static const char * const plugin_dirs[] = { INSTALL_DATADIR"/libwebsockets-test-server/plugins/", NULL }; static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "configdir", required_argument, NULL, 'c' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { NULL, 0, 0, 0 } }; #ifdef LWS_USE_LIBUV void signal_cb(uv_signal_t *watcher, int signum) { lwsl_err("Signal %d caught, exiting...\n", watcher->signum); switch (watcher->signum) { case SIGTERM: case SIGINT: break; default: signal(SIGABRT, SIG_DFL); abort(); break; } lws_libuv_stop(context); } #endif int main(int argc, char **argv) { struct lws_context_creation_info info; char *cs = config_strings; int opts = 0, cs_len = sizeof(config_strings) - 1; int n = 0; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif memset(&info, 0, sizeof info); while (n >= 0) { n = getopt_long(argc, argv, "hd:c:D", options, NULL); if (n < 0) continue; switch (n) { #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif printf("Daemonizing...\n"); break; #endif case 'd': debug_level = atoi(optarg); break; case 'c': strncpy(config_dir, optarg, sizeof(config_dir) - 1); config_dir[sizeof(config_dir) - 1] = '\0'; break; case 'h': fprintf(stderr, "Usage: lwsws [-c <config dir>] " "[-d <log bitfield>] [-D] [--help]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 10; } if (daemonize) lwsl_notice("Daemonized\n"); #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsws", syslog_options, LOG_DAEMON); #endif lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("lwsws libwebsockets web server - license GPL2.1\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); memset(&info, 0, sizeof(info)); info.max_http_header_pool = 16; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS | LWS_SERVER_OPTION_LIBUV; info.plugin_dirs = plugin_dirs; lwsl_notice("Using config dir: \"%s\"\n", config_dir); /* * first go through the config for creating the outer context */ if (lwsws_get_config_globals(&info, config_dir, &cs, &cs_len)) goto bail; context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } /* * then create the vhosts... * * protocols and extensions are the global list of possible * protocols and extensions offered serverwide. The vhosts * in the config files enable the ones they want to offer * per vhost. * * The first protocol is always included for http support. */ info.protocols = protocols; info.extensions = exts; if (lwsws_get_config_vhosts(context, &info, config_dir, &cs, &cs_len)) goto bail; lws_uv_sigint_cfg(context, 1, signal_cb); lws_uv_initloop(context, NULL, 0); lws_libuv_run(context, 0); bail: lws_context_destroy(context); fprintf(stderr, "lwsws exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/lwsws/usr-lib-systemd-system-lwsws.service.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | [Unit] Description=Libwebsockets Web Server After=syslog.target [Service] ExecStart=/usr/local/bin/lwsws StandardError=null [Install] WantedBy=multi-user.target |
Added undroid/libwebsockets/module.json.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "name": "websockets", "version": "1.6.0", "description": "Libwebsockets", "keywords": [ "lws", "libwebsockets", "websockets", "ws" ], "author": "Andy Green <andy@warmcat.com>", "homepage": "https://libwebsockets.org", "license": "LGPL2.1-SLE", "extraIncludes": [ "build/frdm-k64f-gcc/generated/include" ], "dependencies": { "mbed-drivers": "", "sal-stack-lwip": "", "sockets": "" } } |
Added undroid/libwebsockets/plugin-standalone/CMakeLists.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | cmake_minimum_required(VERSION 2.8) if(NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") endif() # This shows one way to build a standalone plugin # outside of lws itself project(lws-protocol-plugin-example C) set(PACKAGE "lws-protocol-plugin-example") set(CPACK_PACKAGE_NAME "${PACKAGE}") set(CPACK_PACKAGE_VERSION "0.1") set(CPACK_PACKAGE_VENDOR "andy@warmcat.com") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}") set(SOVERSION "1") set(VERSION "0.1") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'") # Try to find the current Git hash. find_package(Git) if(GIT_EXECUTABLE) execute_process( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "${GIT_EXECUTABLE}" describe OUTPUT_VARIABLE GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "whoami" OUTPUT_VARIABLE GIT_USER OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMAND "hostname" OUTPUT_VARIABLE GIT_HOST OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX REPLACE "([^\\])[\\]([^\\])" "\\1\\\\\\\\\\2" GIT_USER ${GIT_USER}) set(LWS_BUILD_HASH ${GIT_USER}@${GIT_HOST}-${GIT_HASH}) message("Git commit hash: ${LWS_BUILD_HASH}") endif() set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") macro(create_plugin PLUGIN_NAME MAIN_SRC) set(PLUGIN_SRCS ${MAIN_SRC}) source_group("Headers Private" FILES ${PLUGIN_HDR}) source_group("Sources" FILES ${PLUGIN_SRCS}) add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR}) target_link_libraries(${PLUGIN_NAME} -lwebsockets) # Set test app specific defines. set_property(TARGET ${PLUGIN_NAME} PROPERTY COMPILE_DEFINITIONS INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/plugins" ) list(APPEND PLUGINS_LIST ${PLUGIN_NAME}) endmacro() create_plugin(protocol_example_standalone "protocol_example_standalone.c") install(TARGETS ${PLUGINS_LIST} PERMISSIONS OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ DESTINATION share/libwebsockets-test-server/plugins COMPONENT plugins) |
Added undroid/libwebsockets/plugin-standalone/protocol_example_standalone.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * ws protocol handler plugin for "dumb increment" * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * These test plugins are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. * * This is a copy of dumb_increment adapted slightly to serve as the * "example-standalone-protocol", to show how to build protocol plugins * outside the library easily. */ #include "../lib/libwebsockets.h" #include <string.h> struct per_vhost_data__dumb_increment { uv_timer_t timeout_watcher; struct lws_context *context; struct lws_vhost *vhost; const struct lws_protocols *protocol; }; struct per_session_data__dumb_increment { int number; }; static void uv_timeout_cb_dumb_increment(uv_timer_t *w #if UV_VERSION_MAJOR == 0 , int status #endif ) { struct per_vhost_data__dumb_increment *vhd = lws_container_of(w, struct per_vhost_data__dumb_increment, timeout_watcher); lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol); } static int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user; struct per_vhost_data__dumb_increment *vhd = (struct per_vhost_data__dumb_increment *) lws_protocol_vh_priv_get(lws_vhost_get(wsi), lws_protocol_get(wsi)); unsigned char buf[LWS_PRE + 512]; unsigned char *p = &buf[LWS_PRE]; int n, m; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi), lws_protocol_get(wsi), sizeof(struct per_vhost_data__dumb_increment)); vhd->context = lws_get_context(wsi); vhd->protocol = lws_protocol_get(wsi); vhd->vhost = lws_vhost_get(wsi); uv_timer_init(lws_uv_getloop(vhd->context, 0), &vhd->timeout_watcher); uv_timer_start(&vhd->timeout_watcher, uv_timeout_cb_dumb_increment, 50, 50); break; case LWS_CALLBACK_PROTOCOL_DESTROY: if (!vhd) break; uv_timer_stop(&vhd->timeout_watcher); break; case LWS_CALLBACK_ESTABLISHED: pss->number = 0; break; case LWS_CALLBACK_SERVER_WRITEABLE: n = sprintf((char *)p, "%d", pss->number++); m = lws_write(wsi, p, n, LWS_WRITE_TEXT); if (m < n) { lwsl_err("ERROR %d writing to di socket\n", n); return -1; } break; case LWS_CALLBACK_RECEIVE: if (len < 6) break; if (strcmp((const char *)in, "reset\n") == 0) pss->number = 0; if (strcmp((const char *)in, "closeme\n") == 0) { lwsl_notice("dumb_inc: closing as requested\n"); lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY, (unsigned char *)"seeya", 5); return -1; } break; default: break; } return 0; } static const struct lws_protocols protocols[] = { { "example-standalone-protocol", callback_dumb_increment, sizeof(struct per_session_data__dumb_increment), 10, /* rx buf size must be >= permessage-deflate rx size */ }, }; LWS_VISIBLE int init_protocol_example_standalone(struct lws_context *context, struct lws_plugin_capability *c) { if (c->api_magic != LWS_PLUGIN_API_MAGIC) { lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, c->api_magic); return 1; } c->protocols = protocols; c->count_protocols = ARRAY_SIZE(protocols); c->extensions = NULL; c->count_extensions = 0; return 0; } LWS_VISIBLE int destroy_protocol_example_standalone(struct lws_context *context) { return 0; } |
Added undroid/libwebsockets/plugins/lwsws-logo.png.
cannot compute difference between binary files
Added undroid/libwebsockets/plugins/protocol_dumb_increment.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * ws protocol handler plugin for "dumb increment" * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * These test plugins are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "../lib/libwebsockets.h" #include <string.h> struct per_vhost_data__dumb_increment { uv_timer_t timeout_watcher; struct lws_context *context; struct lws_vhost *vhost; const struct lws_protocols *protocol; }; struct per_session_data__dumb_increment { int number; }; static void uv_timeout_cb_dumb_increment(uv_timer_t *w #if UV_VERSION_MAJOR == 0 , int status #endif ) { struct per_vhost_data__dumb_increment *vhd = lws_container_of(w, struct per_vhost_data__dumb_increment, timeout_watcher); lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol); } static int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user; struct per_vhost_data__dumb_increment *vhd = (struct per_vhost_data__dumb_increment *) lws_protocol_vh_priv_get(lws_vhost_get(wsi), lws_protocol_get(wsi)); unsigned char buf[LWS_PRE + 512]; unsigned char *p = &buf[LWS_PRE]; int n, m; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi), lws_protocol_get(wsi), sizeof(struct per_vhost_data__dumb_increment)); vhd->context = lws_get_context(wsi); vhd->protocol = lws_protocol_get(wsi); vhd->vhost = lws_vhost_get(wsi); uv_timer_init(lws_uv_getloop(vhd->context, 0), &vhd->timeout_watcher); uv_timer_start(&vhd->timeout_watcher, uv_timeout_cb_dumb_increment, 50, 50); break; case LWS_CALLBACK_PROTOCOL_DESTROY: if (!vhd) break; uv_timer_stop(&vhd->timeout_watcher); break; case LWS_CALLBACK_ESTABLISHED: pss->number = 0; break; case LWS_CALLBACK_SERVER_WRITEABLE: n = sprintf((char *)p, "%d", pss->number++); m = lws_write(wsi, p, n, LWS_WRITE_TEXT); if (m < n) { lwsl_err("ERROR %d writing to di socket\n", n); return -1; } break; case LWS_CALLBACK_RECEIVE: if (len < 6) break; if (strcmp((const char *)in, "reset\n") == 0) pss->number = 0; if (strcmp((const char *)in, "closeme\n") == 0) { lwsl_notice("dumb_inc: closing as requested\n"); lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY, (unsigned char *)"seeya", 5); return -1; } break; default: break; } return 0; } static const struct lws_protocols protocols[] = { { "dumb-increment-protocol", callback_dumb_increment, sizeof(struct per_session_data__dumb_increment), 10, /* rx buf size must be >= permessage-deflate rx size */ }, }; LWS_VISIBLE int init_protocol_dumb_increment(struct lws_context *context, struct lws_plugin_capability *c) { if (c->api_magic != LWS_PLUGIN_API_MAGIC) { lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, c->api_magic); return 1; } c->protocols = protocols; c->count_protocols = ARRAY_SIZE(protocols); c->extensions = NULL; c->count_extensions = 0; return 0; } LWS_VISIBLE int destroy_protocol_dumb_increment(struct lws_context *context) { return 0; } |
Added undroid/libwebsockets/plugins/protocol_lws_mirror.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "../lib/libwebsockets.h" #include <string.h> #include <stdlib.h> /* lws-mirror_protocol */ #define MAX_MESSAGE_QUEUE 512 struct per_session_data__lws_mirror { struct lws *wsi; int ringbuffer_tail; }; struct a_message { void *payload; size_t len; }; struct per_vhost_data__lws_mirror { struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; int ringbuffer_head; }; static int callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; struct per_vhost_data__lws_mirror *v = (struct per_vhost_data__lws_mirror *) lws_protocol_vh_priv_get(lws_vhost_get(wsi), lws_protocol_get(wsi)); int n, m; switch (reason) { case LWS_CALLBACK_ESTABLISHED: lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); pss->ringbuffer_tail = v->ringbuffer_head; pss->wsi = wsi; break; case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi), lws_protocol_get(wsi), sizeof(struct per_vhost_data__lws_mirror)); break; case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ if (!v) break; lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v); for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++) if (v->ringbuffer[n].payload) { free(v->ringbuffer[n].payload); v->ringbuffer[n].payload = NULL; } break; case LWS_CALLBACK_SERVER_WRITEABLE: while (pss->ringbuffer_tail != v->ringbuffer_head) { m = v->ringbuffer[pss->ringbuffer_tail].len; n = lws_write(wsi, (unsigned char *) v->ringbuffer[pss->ringbuffer_tail].payload + LWS_PRE, m, LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to mirror socket\n", n); return -1; } if (n < m) lwsl_err("mirror partial write %d vs %d\n", n, m); if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) pss->ringbuffer_tail = 0; else pss->ringbuffer_tail++; if (((v->ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15)) lws_rx_flow_allow_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); if (lws_send_pipe_choked(wsi)) { lws_callback_on_writable(wsi); break; } } break; case LWS_CALLBACK_RECEIVE: if (((v->ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) { lwsl_err("dropping!\n"); goto choke; } if (v->ringbuffer[v->ringbuffer_head].payload) free(v->ringbuffer[v->ringbuffer_head].payload); v->ringbuffer[v->ringbuffer_head].payload = malloc(LWS_PRE + len); v->ringbuffer[v->ringbuffer_head].len = len; memcpy((char *)v->ringbuffer[v->ringbuffer_head].payload + LWS_PRE, in, len); if (v->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) v->ringbuffer_head = 0; else v->ringbuffer_head++; if (((v->ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2)) goto done; choke: lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi); lws_rx_flow_control(wsi, 0); done: lws_callback_on_writable_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); break; default: break; } return 0; } static const struct lws_protocols protocols[] = { { "lws-mirror-protocol", callback_lws_mirror, sizeof(struct per_session_data__lws_mirror), 128, /* rx buf size must be >= permessage-deflate rx size */ }, }; LWS_VISIBLE int init_protocol_lws_mirror(struct lws_context *context, struct lws_plugin_capability *c) { if (c->api_magic != LWS_PLUGIN_API_MAGIC) { lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, c->api_magic); return 1; } c->protocols = protocols; c->count_protocols = ARRAY_SIZE(protocols); c->extensions = NULL; c->count_extensions = 0; return 0; } LWS_VISIBLE int destroy_protocol_lws_mirror(struct lws_context *context) { return 0; } |
Added undroid/libwebsockets/plugins/protocol_lws_server_status.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "../lib/libwebsockets.h" #include <string.h> #include <stdlib.h> #define LWS_SS_VERSIONS 3 struct lws_ss_dumps { char buf[32768]; int length; }; static struct lws_ss_dumps d[LWS_SS_VERSIONS]; static int last_dump; static uv_timer_t timeout_watcher; static struct lws_context *context; static int tow_flag; struct per_session_data__server_status { int ver; int pos; }; static const struct lws_protocols protocols[1]; static void uv_timeout_cb_server_status(uv_timer_t *w #if UV_VERSION_MAJOR == 0 , int status #endif ) { int n; last_dump = (last_dump + 1) % LWS_SS_VERSIONS; n = lws_json_dump_context(context, d[last_dump].buf + LWS_PRE, sizeof(d[0].buf) - LWS_PRE); d[last_dump].length = n; lws_callback_on_writable_all_protocol(context, &protocols[0]); } static int callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { const struct lws_protocol_vhost_options *pvo = (const struct lws_protocol_vhost_options *)in; int m, period = 1000; switch (reason) { case LWS_CALLBACK_ESTABLISHED: lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); lws_callback_on_writable(wsi); break; case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ if (tow_flag) break; while (pvo) { if (!strcmp(pvo->name, "update-ms")) period = atoi(pvo->value); pvo = pvo->next; } context = lws_get_context(wsi); uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher); uv_timer_start(&timeout_watcher, uv_timeout_cb_server_status, 2000, period); tow_flag = 1; break; case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ if (!tow_flag) break; uv_timer_stop(&timeout_watcher); tow_flag = 0; break; case LWS_CALLBACK_SERVER_WRITEABLE: m = lws_write(wsi, (unsigned char *) d[last_dump].buf + LWS_PRE, d[last_dump].length, LWS_WRITE_TEXT); if (m < 0) return -1; break; case LWS_CALLBACK_RECEIVE: break; default: break; } return 0; } static const struct lws_protocols protocols[] = { { "lws-server-status", callback_lws_server_status, sizeof(struct per_session_data__server_status), 1024, }, }; LWS_VISIBLE int init_protocol_lws_server_status(struct lws_context *context, struct lws_plugin_capability *c) { if (c->api_magic != LWS_PLUGIN_API_MAGIC) { lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, c->api_magic); return 1; } c->protocols = protocols; c->count_protocols = ARRAY_SIZE(protocols); c->extensions = NULL; c->count_extensions = 0; return 0; } LWS_VISIBLE int destroy_protocol_lws_server_status(struct lws_context *context) { return 0; } |
Added undroid/libwebsockets/plugins/protocol_lws_status.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "../lib/libwebsockets.h" #include <time.h> #include <string.h> #ifdef WIN32 #include <gettimeofday.h> #endif struct per_session_data__lws_status { struct per_session_data__lws_status *list; struct timeval tv_established; int last; char ip[270]; char user_agent[512]; const char *pos; int len; }; static unsigned char server_info[1024]; static int server_info_len; static int current; static char cache[16384]; static int cache_len; static struct per_session_data__lws_status *list; static int live_wsi; static void update_status(struct lws *wsi, struct per_session_data__lws_status *pss) { struct per_session_data__lws_status **pp = &list; int subsequent = 0; char *p = cache + LWS_PRE, *start = p; char date[128]; time_t t; struct tm *ptm; #ifndef WIN32 struct tm tm; #endif p += lws_snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[", server_info, live_wsi); /* render the list */ while (*pp) { t = (*pp)->tv_established.tv_sec; #ifdef WIN32 ptm = localtime(&t); if (!ptm) #else ptm = &tm; if (!localtime_r(&t, &tm)) #endif strcpy(date, "unknown"); else strftime(date, sizeof(date), "%F %H:%M %Z", ptm); if ((p - start) > (sizeof(cache) - 512)) break; if (subsequent) *p++ = ','; subsequent = 1; p += lws_snprintf(p, sizeof(cache) - (p - start) - 1, "{\"peer\":\"%s\",\"time\":\"%s\"," "\"ua\":\"%s\"}", (*pp)->ip, date, (*pp)->user_agent); pp = &((*pp)->list); } p += sprintf(p, "]}"); cache_len = p - start; lwsl_err("cache_len %d\n", cache_len); *p = '\0'; /* since we changed the list, increment the 'version' */ current++; /* update everyone */ lws_callback_on_writable_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); } /* lws-status protocol */ int callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_status *pss = (struct per_session_data__lws_status *)user, **pp; char name[128], rip[128]; int m; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: /* * Prepare the static server info */ server_info_len = sprintf((char *)server_info, "\"version\":\"%s\"," " \"hostname\":\"%s\"", lws_get_library_version(), lws_canonical_hostname( lws_get_context(wsi))); break; case LWS_CALLBACK_ESTABLISHED: /* * we keep a linked list of live pss, so we can walk it */ pss->last = 0; pss->list = list; list = pss; live_wsi++; lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip)); sprintf(pss->ip, "%s (%s)", name, rip); gettimeofday(&pss->tv_established, NULL); strcpy(pss->user_agent, "unknown"); lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent), WSI_TOKEN_HTTP_USER_AGENT); update_status(wsi, pss); break; case LWS_CALLBACK_SERVER_WRITEABLE: m = lws_write(wsi, (unsigned char *)cache + LWS_PRE, cache_len, LWS_WRITE_TEXT); if (m < server_info_len) { lwsl_err("ERROR %d writing to di socket\n", m); return -1; } break; case LWS_CALLBACK_CLOSED: pp = &list; while (*pp) { if (*pp == pss) { *pp = pss->list; pss->list = NULL; live_wsi--; break; } pp = &((*pp)->list); } update_status(wsi, pss); break; default: break; } return 0; } static const struct lws_protocols protocols[] = { { "lws-status", callback_lws_status, sizeof(struct per_session_data__lws_status), 128, /* rx buf size must be >= permessage-deflate rx size */ }, }; LWS_VISIBLE int init_protocol_lws_status(struct lws_context *context, struct lws_plugin_capability *c) { if (c->api_magic != LWS_PLUGIN_API_MAGIC) { lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC, c->api_magic); return 1; } c->protocols = protocols; c->count_protocols = ARRAY_SIZE(protocols); c->extensions = NULL; c->count_extensions = 0; return 0; } LWS_VISIBLE int destroy_protocol_lws_status(struct lws_context *context) { return 0; } |
Added undroid/libwebsockets/plugins/server-status.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <!DOCTYPE html> <html lang="en"> <head> <meta charset=utf-8 http-equiv="Content-Language" content="en"/> <title>LWS Server Status</title> <style type="text/css"> span.title { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#000000; } span.mount { font-size:10pt; font: Arial; font-weight:normal; text-align:center; color:#000000; } span.mountname { font-size:14pt; font: Arial; font-weight:bold; text-align:center; color:#404010; } span.n { font-size:12pt; font: Arial; font-weight:normal; text-align:center; color:#808020; } span.v { font-size:12pt; font: Arial; font-weight:bold; text-align:center; color:#202020; } span.m1 { font-size:12pt; font: Arial; font-weight:bold; text-align:center; color:#202020; } span.m2 { font-size:12pt; font: Arial; font-weight:normal; text-align:center; color:#202020; } .browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;} .group2 { vertical-align:middle; text-align:center; background:#f0f0e0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } .explain { vertical-align:middle; text-align:center; background:#f0f0c0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; color:#404000; } td.wsstatus { vertical-align:middle; width:200px; height:50px; text-align:center; background:#f0f0c0; padding:6px; -webkit-border-radius:8px; -moz-border-radius:8px; border-radius:8px; color:#404000; } td.l { vertical-align:middle; text-align:center; background:#d0d0b0; padding:3px; -webkit-border-radius:3px; -moz-border-radius:3px; border-radius:3px; } td.c { vertical-align:middle; text-align:center; background:#c0c0a0; padding:3px; -webkit-border-radius:3px; -moz-border-radius:3px; border-radius:3px; } td.t { vertical-align:middle; text-align:center; background:#e0e0c0; padding:3px; -webkit-border-radius:3px; -moz-border-radius:3px; border-radius:3px; } .content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } .canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } .tabs { position: relative; min-height: 750px; /* This part sucks */ clear: both; margin: 25px 0; } .tab { float: left; } .tab label { background: #eee; padding: 10px; border: 1px solid #ccc; margin-left: -1px; position: relative; left: 1px; } .tab [type=radio] { display: none; } .content { position: absolute; top: 28px; left: 0; background: white; right: 0; bottom: 0; padding: 20px; border: 1px solid #ccc; } [type=radio]:checked ~ label { background: white; border-bottom: 1px solid white; z-index: 2; } [type=radio]:checked ~ label ~ .content { z-index: 1; } </style> </head> <body> <header></header> <article> <table> <tr><td><img src="./lwsws-logo.png"></td><td><span id=title class=title>Server status</span></td></tr> <tr><td align=center colspan=2> <div id="conninfo">...</div> </td></tr> </table> </article> <script> /* * We display untrusted stuff in html context... reject anything * that has HTML stuff in it */ function san(s) { if (s.search("<") != -1) return "invalid string"; return s; } function humanize(s) { i = parseInt(s); if (i > 1000000000) return (i / 1000000000).toFixed(3) + "G"; if (i > 1000000) return (i / 1000000).toFixed(3) + "M"; if (i > 1000) return (i / 1000).toFixed(3) + "K"; return s; } var pos = 0; function get_appropriate_ws_url() { var pcol; var u = document.URL; /* * We open the websocket encrypted if this page came on an * https:// url itself, otherwise unencrypted */ if (u.substring(0, 5) == "https") { pcol = "wss://"; u = u.substr(8); } else { pcol = "ws://"; if (u.substring(0, 4) == "http") u = u.substr(7); } u = u.split('/'); /* + "/xxx" bit is for IE10 workaround */ return pcol + u[0] + "/xxx"; } var socket_status, jso, s; if (typeof MozWebSocket != "undefined") { socket_status = new MozWebSocket(get_appropriate_ws_url(), "lws-server-status"); } else { socket_status = new WebSocket(get_appropriate_ws_url(), "lws-server-status"); } try { socket_status.onopen = function() { document.getElementById("title").innerHTML = "Server Status (Active)"; } socket_status.onmessage =function got_packet(msg) { var u; //document.getElementById("conninfo").innerHTML = "<pre>"+msg.data+"</pre>"; jso = JSON.parse(msg.data); u = parseInt(san(jso.uptime)); s = "<table><tr><td class=\"c\">" + "Context</td><td>" + "<span class=n>Version:</span> <span class=v>" + san(jso.version) + "</span><br>" + "<span class=n>Uptime:</span> <span class=v>" + ((u / (24 * 3600)) | 0) + "d " + (((u % (24 * 3600)) / 3600) | 0) + "h " + (((u % 3600) / 60) | 0) + "m</span>"; if (jso.l1) s = s + ", <span class=n>Load:</span> <span class=v>" + san(jso.l1) + " "; if (jso.l2) s = s + san(jso.l2) + " "; if (jso.l3) s = s + san(jso.l3); if (jso.l1) s =s + "<span>"; s = s + "<br>" + "<span class=n>Listening wsi:</span> <span class=v>" + san(jso.listen_wsi) + "</span>, " + "<span class=n>Current wsi alive:</span> <span class=v>" + (parseInt(san(jso.wsi_alive)) - parseInt(san(jso.listen_wsi))) + "</span><br>" + "<span class=n>Current cgi alive:</span> <span class=v>" + san(jso.cgi_alive) + "</span>, " + "<span class=n>Total CGI spawned:</span> <span class=v>" + san(jso.cgi_spawned) + "</span></td></tr>"; var n; for (n = 0; n < jso.pt.length; n++) { s = s + "<tr><td class=\"l\">service thread " + (n + 1) + "</td><td>" + "<span class=n>fds:</span> <span class=v>" + san(jso.pt[n].fds_count) + " / " + san(jso.pt_fd_max) + "</span>, "; s = s + "<span class=n>ah pool:</span> <span class=v>" + san(jso.pt[n].ah_pool_inuse) + " / " + san(jso.ah_pool_max) + "</span>, " + "<span class=n>ah waiting list:</span> <span class=v>" + san(jso.pt[n].ah_wait_list); s = s + "</span></td></tr>"; } for (n = 0; n < jso.vhosts.length; n++) { s = s + "<tr><td class=\"l\">vhost " + (n + 1) + "</td><td><span class=\"mountname\">"; if (jso.vhosts[n].use_ssl == '1') s = s + "https://"; else s = s + "http://"; s = s + san(jso.vhosts[n].name) + ":" + san(jso.vhosts[n].port) + "</span>"; if (jso.vhosts[n].sts == '1') s = s + " (STS)"; s = s +"<br>" + "<span class=n>rx:</span> <span class=v>" + humanize(san(jso.vhosts[n].rx)) + "B</span>, " + "<span class=n>tx</span> <span class=v>" + humanize(san(jso.vhosts[n].tx)) + "B</span><br>" + "<span class=n>total connections</span> <span class=v>" + san(jso.vhosts[n].conn) + "</span>, " + "<span class=n>total http transactions</span> <span class=v>" + san(jso.vhosts[n].trans) + "</span><br>" + "<span class=n>Upgrades to ws:</span> <span class=v>" + san(jso.vhosts[n].ws_upg) + "</span>, " + "<span class=n>to http/2:</span> <span class=v>" + san(jso.vhosts[n].http2_upg) + "</span><br>" + "<table style=\"margin-left:16px\"><tr><td class=t>Mountpoint</td><td class=t>Origin</td><td class=t>Cache Policy</td></tr>"; var m; for (m = 0; m < jso.vhosts[n].mounts.length; m++) { s = s + "<tr><td>"; s = s + "<span class=\"m1\">" + san(jso.vhosts[n].mounts[m].mountpoint) + "</span></td><td><span class=\"m2\">" + san(jso.vhosts[n].mounts[m].origin) + "</span></td><td>"; if (parseInt(san(jso.vhosts[n].mounts[m].cache_max_age))) s = s + "<span class=n>max-age:</span> <span class=v>" + san(jso.vhosts[n].mounts[m].cache_max_age) + "</span>, <span class=n>reuse:</span> <span class=v>" + san(jso.vhosts[n].mounts[m].cache_reuse) + "</span>, <span class=n>reval:</span> <span class=v>" + san(jso.vhosts[n].mounts[m].cache_revalidate) + "</span>, <span class=n>inter:</span> <span class=v>" + san(jso.vhosts[n].mounts[m].cache_intermediaries); s = s + "</span></td></tr>" } s = s + "</table>"; s = s + "</td></tr>"; } s = s + "</table>"; document.getElementById("conninfo").innerHTML = s; } socket_status.onclose = function(){ document.getElementById("title").innerHTML = "Server Status (Disconnected)"; } } catch(exception) { alert('<p>Error' + exception); } </script> </body> </html> |
Added undroid/libwebsockets/release-checklist.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Release Checklist ----------------- 0) QA a) ab $ ab -n 100000 -c 200 http://localhost:7681/ b) coverity $ ../make-coverity-tarball.sh https://scan.coverity.com/projects/warmcat-libwebsockets c) test servers + client + browser d) valgrind test servers + client + browser e) attack.sh $ ./test-server/attack.sh f) Autobahn $ wstest -m fuzzingserver & $ ./autobahn-test.sh Force update by browser using agent "libwebsockets" http://localhost:8080/test_browser.html scp -rp ./reports to libwebsockets.org 1) api $ cp build/doc/* . 2) soname bump? a) We need one if we added / changed / removed apis CMakeLists.txt set(SOVERSION "6") libwebsockets.spec -/%{_libdir}/libwebsockets.so.6 +/%{_libdir}/libwebsockets.so.7 3) changelog a) Add next version tag header. b) Classify as - MINOR bug fixes - MAJOR bug fixes - SECURITY fixes 4) main version bump CMakeLists.txt set(CPACK_PACKAGE_VERSION_MAJOR "1") set(CPACK_PACKAGE_VERSION_MINOR "6") set(CPACK_PACKAGE_VERSION_PATCH "0") 5) specfile a) rpm version bump to match CMake one libwebsockets.spec Version: 1.6.0 b) Summarize changelog libwebsockets.spec %changelog * Sun Jan 17 2016 Andrew Cooks <acooks@linux.com> 1.6.4-1 - Bump version to 1.6.4 - MINOR fix xyz 6) update api docs $ cmake .. $ cp doc/* .. 7) signed tag git tag -s vX.Y[.Z] 8) git a) push b) final CI check, if fail delete tag, kill pushed tags, restart flow 8) website a) update latest tag for release branch |
Added undroid/libwebsockets/scripts/FindLibWebSockets.cmake.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # This module tries to find libWebsockets library and include files # # LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h # LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so # LIBWEBSOCKETS_LIBRARIES, the library to link against # LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets # # This currently works probably only for Linux FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h /usr/local/include /usr/include ) FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets /usr/local/lib /usr/lib ) GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH ) SET ( LIBWEBSOCKETS_FOUND "NO" ) IF ( LIBWEBSOCKETS_INCLUDE_DIR ) IF ( LIBWEBSOCKETS_LIBRARIES ) SET ( LIBWEBSOCKETS_FOUND "YES" ) ENDIF ( LIBWEBSOCKETS_LIBRARIES ) ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR ) MARK_AS_ADVANCED( LIBWEBSOCKETS_LIBRARY_DIR LIBWEBSOCKETS_INCLUDE_DIR LIBWEBSOCKETS_LIBRARIES ) |
Added undroid/libwebsockets/scripts/kernel-doc.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 | #!/usr/bin/perl -w use strict; ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ## ## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ## ## Copyright (C) 2001 Simon Huggins ## ## Copyright (C) 2005-2009 Randy Dunlap ## ## ## ## #define enhancements by Armin Kuster <akuster@mvista.com> ## ## Copyright (c) 2000 MontaVista Software, Inc. ## ## ## ## This software falls under the GNU General Public License. ## ## Please read the COPYING file for more information ## # w.o. 03-11-2000: added the '-filelist' option. # 18/01/2001 - Cleanups # Functions prototyped as foo(void) same as foo() # Stop eval'ing where we don't need to. # -- huggie@earth.li # 27/06/2001 - Allowed whitespace after initial "/**" and # allowed comments before function declarations. # -- Christian Kreibich <ck@whoop.org> # Still to do: # - add perldoc documentation # - Look more closely at some of the scarier bits :) # 26/05/2001 - Support for separate source and object trees. # Return error code. # Keith Owens <kaos@ocs.com.au> # 23/09/2001 - Added support for typedefs, structs, enums and unions # Support for Context section; can be terminated using empty line # Small fixes (like spaces vs. \s in regex) # -- Tim Jansen <tim@tjansen.de> # # This will read a 'c' file and scan for embedded comments in the # style of gnome comments (+minor extensions - see below). # # Note: This only supports 'c'. # usage: # kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ] # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile # or # [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile # # Set output format using one of -docbook -html -text or -man. Default is man. # # -no-doc-sections # Do not output DOC: sections # # -function funcname # If set, then only generate documentation for the given function(s) or # DOC: section titles. All other functions and DOC: sections are ignored. # # -nofunction funcname # If set, then only generate documentation for the other function(s)/DOC: # sections. Cannot be used together with -function (yes, that's a bug -- # perl hackers can fix it 8)) # # c files - list of 'c' files to process # # All output goes to stdout, with errors to stderr. # # format of comments. # In the following table, (...)? signifies optional structure. # (...)* signifies 0 or more structure elements # /** # * function_name(:)? (- short description)? # (* @parameterx: (description of parameter x)?)* # (* a blank line)? # * (Description:)? (Description of function)? # * (section header: (section description)? )* # (*)?*/ # # So .. the trivial example would be: # # /** # * my_function # */ # # If the Description: header tag is omitted, then there must be a blank line # after the last parameter specification. # e.g. # /** # * my_function - does my stuff # * @my_arg: its mine damnit # * # * Does my stuff explained. # */ # # or, could also use: # /** # * my_function - does my stuff # * @my_arg: its mine damnit # * Description: Does my stuff explained. # */ # etc. # # Besides functions you can also write documentation for structs, unions, # enums and typedefs. Instead of the function name you must write the name # of the declaration; the struct/union/enum/typedef must always precede # the name. Nesting of declarations is not supported. # Use the argument mechanism to document members or constants. # e.g. # /** # * struct my_struct - short description # * @a: first member # * @b: second member # * # * Longer description # */ # struct my_struct { # int a; # int b; # /* private: */ # int c; # }; # # All descriptions can be multiline, except the short function description. # # You can also add additional sections. When documenting kernel functions you # should document the "Context:" of the function, e.g. whether the functions # can be called form interrupts. Unlike other sections you can end it with an # empty line. # Example-sections should contain the string EXAMPLE so that they are marked # appropriately in DocBook. # # Example: # /** # * user_function - function that can only be called in user context # * @a: some argument # * Context: !in_interrupt() # * # * Some description # * Example: # * user_function(22); # */ # ... # # # All descriptive text is further processed, scanning for the following special # patterns, which are highlighted appropriately. # # 'funcname()' - function # '$ENVVAR' - environmental variable # '&struct_name' - name of a structure (up to two words including 'struct') # '@parameter' - name of a parameter # '%CONST' - name of a constant. my $errors = 0; my $warnings = 0; my $anon_struct_union = 0; # match expressions used to find embedded type information my $type_constant = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; my $type_param = '\@(\w+)'; my $type_struct = '\&((struct\s*)*[_\w]+)'; my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; # Output conversion substitutions. # One for each output format # these work fairly well my %highlights_html = ( $type_constant, "<i>\$1</i>", $type_func, "<b>\$1</b>", $type_struct_xml, "<i>\$1</i>", $type_env, "<b><i>\$1</i></b>", $type_param, "<tt><b>\$1</b></tt>" ); my $local_lt = "\\\\\\\\lt:"; my $local_gt = "\\\\\\\\gt:"; my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" # XML, docbook format my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>", $type_constant, "<constant>\$1</constant>", $type_func, "<function>\$1</function>", $type_struct_xml, "<structname>\$1</structname>", $type_env, "<envar>\$1</envar>", $type_param, "<parameter>\$1</parameter>" ); my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; # gnome, docbook format my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>", $type_func, "<function>\$1</function>", $type_struct, "<structname>\$1</structname>", $type_env, "<envar>\$1</envar>", $type_param, "<parameter>\$1</parameter>" ); my $blankline_gnome = "</para><para>\n"; # these are pretty rough my %highlights_man = ( $type_constant, "\$1", $type_func, "\\\\fB\$1\\\\fP", $type_struct, "\\\\fI\$1\\\\fP", $type_param, "\\\\fI\$1\\\\fP" ); my $blankline_man = ""; # text-mode my %highlights_text = ( $type_constant, "\$1", $type_func, "\$1", $type_struct, "\$1", $type_param, "\$1" ); my $blankline_text = ""; sub usage { print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ] [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; print " c source file(s) > outputfile\n"; print " -v : verbose output, more warnings & other info listed\n"; exit 1; } # read arguments if ($#ARGV == -1) { usage(); } my $verbose = 0; my $output_mode = "man"; my $no_doc_sections = 0; my %highlights = %highlights_man; my $blankline = $blankline_man; my $modulename = "Kernel API"; my $function_only = 0; my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')[(localtime)[4]] . " " . ((localtime)[5]+1900); # Essentially these are globals # They probably want to be tidied up, made more localised or something. # CAVEAT EMPTOR! Some of the others I localised may not want to be, which # could cause "use of undefined value" or other bugs. my ($function, %function_table, %parametertypes, $declaration_purpose); my ($type, $declaration_name, $return_type); my ($newsection, $newcontents, $prototype, $filelist, $brcount, %source_map); if (defined($ENV{'KBUILD_VERBOSE'})) { $verbose = "$ENV{'KBUILD_VERBOSE'}"; } # Generated docbook code is inserted in a template at a point where # docbook v3.1 requires a non-zero sequence of RefEntry's; see: # http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html # We keep track of number of generated entries and generate a dummy # if needs be to ensure the expanded template can be postprocessed # into html. my $section_counter = 0; my $lineprefix=""; # states # 0 - normal code # 1 - looking for function name # 2 - scanning field start. # 3 - scanning prototype. # 4 - documentation block my $state; my $in_doc_sect; #declaration types: can be # 'function', 'struct', 'union', 'enum', 'typedef' my $decl_type; my $doc_special = "\@\%\$\&"; my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; my $doc_decl = $doc_com . '(\w+)'; my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; my $doc_content = $doc_com . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; my %constants; my %parameterdescs; my @parameterlist; my %sections; my @sectionlist; my $sectcheck; my $struct_actual; my $contents = ""; my $section_default = "Description"; # default section my $section_intro = "Introduction"; my $section = $section_default; my $section_context = "Context"; my $undescribed = "-- undescribed --"; reset_state(); while ($ARGV[0] =~ m/^-(.*)/) { my $cmd = shift @ARGV; if ($cmd eq "-html") { $output_mode = "html"; %highlights = %highlights_html; $blankline = $blankline_html; } elsif ($cmd eq "-man") { $output_mode = "man"; %highlights = %highlights_man; $blankline = $blankline_man; } elsif ($cmd eq "-text") { $output_mode = "text"; %highlights = %highlights_text; $blankline = $blankline_text; } elsif ($cmd eq "-docbook") { $output_mode = "xml"; %highlights = %highlights_xml; $blankline = $blankline_xml; } elsif ($cmd eq "-gnome") { $output_mode = "gnome"; %highlights = %highlights_gnome; $blankline = $blankline_gnome; } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document $modulename = shift @ARGV; } elsif ($cmd eq "-function") { # to only output specific functions $function_only = 1; $function = shift @ARGV; $function_table{$function} = 1; } elsif ($cmd eq "-nofunction") { # to only output specific functions $function_only = 2; $function = shift @ARGV; $function_table{$function} = 1; } elsif ($cmd eq "-v") { $verbose = 1; } elsif (($cmd eq "-h") || ($cmd eq "--help")) { usage(); } elsif ($cmd eq '-filelist') { $filelist = shift @ARGV; } elsif ($cmd eq '-no-doc-sections') { $no_doc_sections = 1; } } # get kernel version from env sub get_kernel_version() { my $version = 'unknown kernel version'; if (defined($ENV{'KERNELVERSION'})) { $version = $ENV{'KERNELVERSION'}; } return $version; } my $kernelversion = get_kernel_version(); # generate a sequence of code that will splice in highlighting information # using the s// operator. my $dohighlight = ""; foreach my $pattern (keys %highlights) { # print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; } ## # dumps section contents to arrays/hashes intended for that purpose. # sub dump_section { my $file = shift; my $name = shift; my $contents = join "\n", @_; if ($name =~ m/$type_constant/) { $name = $1; # print STDERR "constant section '$1' = '$contents'\n"; $constants{$name} = $contents; } elsif ($name =~ m/$type_param/) { # print STDERR "parameter def '$1' = '$contents'\n"; $name = $1; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; } elsif ($name eq "@\.\.\.") { # print STDERR "parameter def '...' = '$contents'\n"; $name = "..."; $parameterdescs{$name} = $contents; $sectcheck = $sectcheck . $name . " "; } else { # print STDERR "other section '$name' = '$contents'\n"; if (defined($sections{$name}) && ($sections{$name} ne "")) { print STDERR "Error(${file}:$.): duplicate section name '$name'\n"; ++$errors; } $sections{$name} = $contents; push @sectionlist, $name; } } ## # dump DOC: section after checking that it should go out # sub dump_doc_section { my $file = shift; my $name = shift; my $contents = join "\n", @_; if ($no_doc_sections) { return; } if (($function_only == 0) || ( $function_only == 1 && defined($function_table{$name})) || ( $function_only == 2 && !defined($function_table{$name}))) { dump_section($file, $name, $contents); output_blockhead({'sectionlist' => \@sectionlist, 'sections' => \%sections, 'module' => $modulename, 'content-only' => ($function_only != 0), }); } } ## # output function # # parameterdescs, a hash. # function => "function name" # parameterlist => @list of parameters # parameterdescs => %parameter descriptions # sectionlist => @list of sections # sections => %section descriptions # sub output_highlight { my $contents = join "\n",@_; my $line; # DEBUG # if (!defined $contents) { # use Carp; # confess "output_highlight got called with no args?\n"; # } if ($output_mode eq "html" || $output_mode eq "xml") { $contents = local_unescape($contents); # convert data read & converted thru xml_escape() into &xyz; format: $contents =~ s/\\\\\\/&/g; } # print STDERR "contents b4:$contents\n"; eval $dohighlight; die $@ if $@; # print STDERR "contents af:$contents\n"; foreach $line (split "\n", $contents) { if ($line eq ""){ print $lineprefix, local_unescape($blankline); } else { $line =~ s/\\\\\\/\&/g; if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { print "\\&$line"; } else { print $lineprefix, $line; } } print "\n"; } } #output sections in html sub output_section_html(%) { my %args = %{$_[0]}; my $section; foreach $section (@{$args{'sectionlist'}}) { print "<h3>$section</h3>\n"; print "<blockquote>\n"; output_highlight($args{'sections'}{$section}); print "</blockquote>\n"; } } # output enum in html sub output_enum_html(%) { my %args = %{$_[0]}; my ($parameter); my $count; print "<h2>enum " . $args{'enum'} . "</h2>\n"; print "<b>enum " . $args{'enum'} . "</b> {<br>\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { print " <b>" . $parameter . "</b>"; if ($count != $#{$args{'parameterlist'}}) { $count++; print ",\n"; } print "<br>"; } print "};<br>\n"; print "<h3>Constants</h3>\n"; print "<dl>\n"; foreach $parameter (@{$args{'parameterlist'}}) { print "<dt><b>" . $parameter . "</b>\n"; print "<dd>"; output_highlight($args{'parameterdescs'}{$parameter}); } print "</dl>\n"; output_section_html(@_); print "<hr>\n"; } # output typedef in html sub output_typedef_html(%) { my %args = %{$_[0]}; my ($parameter); my $count; print "<h2>typedef " . $args{'typedef'} . "</h2>\n"; print "<b>typedef " . $args{'typedef'} . "</b>\n"; output_section_html(@_); print "<hr>\n"; } # output struct in html sub output_struct_html(%) { my %args = %{$_[0]}; my ($parameter); print "<h2>" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "</h2>\n"; print "<b>" . $args{'type'} . " " . $args{'struct'} . "</b> {<br>\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print "$parameter<br>\n"; next; } my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print " <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { # bitfield print " <i>$1</i> <b>$parameter</b>$2;<br>\n"; } else { print " <i>$type</i> <b>$parameter</b>;<br>\n"; } } print "};<br>\n"; print "<h3>Members</h3>\n"; print "<dl>\n"; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "<dt><b>" . $parameter . "</b>\n"; print "<dd>"; output_highlight($args{'parameterdescs'}{$parameter_name}); } print "</dl>\n"; output_section_html(@_); print "<hr>\n"; } # output function in html sub output_function_html(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; print "<h2>" . $args{'function'} . " - " . $args{'purpose'} . "</h2>\n"; print "<i>" . $args{'functiontype'} . "</i>\n"; print "<b>" . $args{'function'} . "</b>\n"; print "("; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print "<i>$1</i><b>$parameter</b>) <i>($2)</i>"; } else { print "<i>" . $type . "</i> <b>" . $parameter . "</b>"; } if ($count != $#{$args{'parameterlist'}}) { $count++; print ",\n"; } } print ")\n"; print "<h3>Arguments</h3>\n"; print "<dl>\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "<dt><b>" . $parameter . "</b>\n"; print "<dd>"; output_highlight($args{'parameterdescs'}{$parameter_name}); } print "</dl>\n"; output_section_html(@_); print "<hr>\n"; } # output DOC: block header in html sub output_blockhead_html(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; foreach $section (@{$args{'sectionlist'}}) { print "<h3>$section</h3>\n"; print "<ul>\n"; output_highlight($args{'sections'}{$section}); print "</ul>\n"; } print "<hr>\n"; } sub output_section_xml(%) { my %args = %{$_[0]}; my $section; # print out each section $lineprefix=" "; foreach $section (@{$args{'sectionlist'}}) { print "<refsect1>\n"; print "<title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<informalexample><programlisting>\n"; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); if ($section =~ m/EXAMPLE/i) { print "</programlisting></informalexample>\n"; } else { print "</para>\n"; } print "</refsect1>\n"; } } # output function in XML DocBook sub output_function_xml(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; my $id; $id = "API-" . $args{'function'}; $id =~ s/[^A-Za-z0-9]/-/g; print "<refentry id=\"$id\">\n"; print "<refentryinfo>\n"; print " <title>LINUX</title>\n"; print " <productname>Kernel Hackers Manual</productname>\n"; print " <date>$man_date</date>\n"; print "</refentryinfo>\n"; print "<refmeta>\n"; print " <refentrytitle><phrase>" . $args{'function'} . "</phrase></refentrytitle>\n"; print " <manvolnum>9</manvolnum>\n"; print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n"; print "</refmeta>\n"; print "<refnamediv>\n"; print " <refname>" . $args{'function'} . "</refname>\n"; print " <refpurpose>\n"; print " "; output_highlight ($args{'purpose'}); print " </refpurpose>\n"; print "</refnamediv>\n"; print "<refsynopsisdiv>\n"; print " <title>Synopsis</title>\n"; print " <funcsynopsis><funcprototype>\n"; print " <funcdef>" . $args{'functiontype'} . " "; print "<function>" . $args{'function'} . " </function></funcdef>\n"; $count = 0; if ($#{$args{'parameterlist'}} >= 0) { foreach $parameter (@{$args{'parameterlist'}}) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print " <paramdef>$1<parameter>$parameter</parameter>)\n"; print " <funcparams>$2</funcparams></paramdef>\n"; } else { print " <paramdef>" . $type; print " <parameter>$parameter</parameter></paramdef>\n"; } } } else { print " <void/>\n"; } print " </funcprototype></funcsynopsis>\n"; print "</refsynopsisdiv>\n"; # print parameters print "<refsect1>\n <title>Arguments</title>\n"; if ($#{$args{'parameterlist'}} >= 0) { print " <variablelist>\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; print " <varlistentry>\n <term><parameter>$parameter</parameter></term>\n"; print " <listitem>\n <para>\n"; $lineprefix=" "; output_highlight($args{'parameterdescs'}{$parameter_name}); print " </para>\n </listitem>\n </varlistentry>\n"; } print " </variablelist>\n"; } else { print " <para>\n None\n </para>\n"; } print "</refsect1>\n"; output_section_xml(@_); print "</refentry>\n\n"; } # output struct in XML DocBook sub output_struct_xml(%) { my %args = %{$_[0]}; my ($parameter, $section); my $id; $id = "API-struct-" . $args{'struct'}; $id =~ s/[^A-Za-z0-9]/-/g; print "<refentry id=\"$id\">\n"; print "<refentryinfo>\n"; print " <title>LINUX</title>\n"; print " <productname>Kernel Hackers Manual</productname>\n"; print " <date>$man_date</date>\n"; print "</refentryinfo>\n"; print "<refmeta>\n"; print " <refentrytitle><phrase>" . $args{'type'} . " " . $args{'struct'} . "</phrase></refentrytitle>\n"; print " <manvolnum>9</manvolnum>\n"; print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n"; print "</refmeta>\n"; print "<refnamediv>\n"; print " <refname>" . $args{'type'} . " " . $args{'struct'} . "</refname>\n"; print " <refpurpose>\n"; print " "; output_highlight ($args{'purpose'}); print " </refpurpose>\n"; print "</refnamediv>\n"; print "<refsynopsisdiv>\n"; print " <title>Synopsis</title>\n"; print " <programlisting>\n"; print $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print "$parameter\n"; next; } my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; defined($args{'parameterdescs'}{$parameter_name}) || next; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print " $1 $parameter) ($2);\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { # bitfield print " $1 $parameter$2;\n"; } else { print " " . $type . " " . $parameter . ";\n"; } } print "};"; print " </programlisting>\n"; print "</refsynopsisdiv>\n"; print " <refsect1>\n"; print " <title>Members</title>\n"; if ($#{$args{'parameterlist'}} >= 0) { print " <variablelist>\n"; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; defined($args{'parameterdescs'}{$parameter_name}) || next; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print " <varlistentry>"; print " <term>$parameter</term>\n"; print " <listitem><para>\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); print " </para></listitem>\n"; print " </varlistentry>\n"; } print " </variablelist>\n"; } else { print " <para>\n None\n </para>\n"; } print " </refsect1>\n"; output_section_xml(@_); print "</refentry>\n\n"; } # output enum in XML DocBook sub output_enum_xml(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; my $id; $id = "API-enum-" . $args{'enum'}; $id =~ s/[^A-Za-z0-9]/-/g; print "<refentry id=\"$id\">\n"; print "<refentryinfo>\n"; print " <title>LINUX</title>\n"; print " <productname>Kernel Hackers Manual</productname>\n"; print " <date>$man_date</date>\n"; print "</refentryinfo>\n"; print "<refmeta>\n"; print " <refentrytitle><phrase>enum " . $args{'enum'} . "</phrase></refentrytitle>\n"; print " <manvolnum>9</manvolnum>\n"; print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n"; print "</refmeta>\n"; print "<refnamediv>\n"; print " <refname>enum " . $args{'enum'} . "</refname>\n"; print " <refpurpose>\n"; print " "; output_highlight ($args{'purpose'}); print " </refpurpose>\n"; print "</refnamediv>\n"; print "<refsynopsisdiv>\n"; print " <title>Synopsis</title>\n"; print " <programlisting>\n"; print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { print " $parameter"; if ($count != $#{$args{'parameterlist'}}) { $count++; print ","; } print "\n"; } print "};"; print " </programlisting>\n"; print "</refsynopsisdiv>\n"; print "<refsect1>\n"; print " <title>Constants</title>\n"; print " <variablelist>\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; print " <varlistentry>"; print " <term>$parameter</term>\n"; print " <listitem><para>\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); print " </para></listitem>\n"; print " </varlistentry>\n"; } print " </variablelist>\n"; print "</refsect1>\n"; output_section_xml(@_); print "</refentry>\n\n"; } # output typedef in XML DocBook sub output_typedef_xml(%) { my %args = %{$_[0]}; my ($parameter, $section); my $id; $id = "API-typedef-" . $args{'typedef'}; $id =~ s/[^A-Za-z0-9]/-/g; print "<refentry id=\"$id\">\n"; print "<refentryinfo>\n"; print " <title>LINUX</title>\n"; print " <productname>Kernel Hackers Manual</productname>\n"; print " <date>$man_date</date>\n"; print "</refentryinfo>\n"; print "<refmeta>\n"; print " <refentrytitle><phrase>typedef " . $args{'typedef'} . "</phrase></refentrytitle>\n"; print " <manvolnum>9</manvolnum>\n"; print "</refmeta>\n"; print "<refnamediv>\n"; print " <refname>typedef " . $args{'typedef'} . "</refname>\n"; print " <refpurpose>\n"; print " "; output_highlight ($args{'purpose'}); print " </refpurpose>\n"; print "</refnamediv>\n"; print "<refsynopsisdiv>\n"; print " <title>Synopsis</title>\n"; print " <synopsis>typedef " . $args{'typedef'} . ";</synopsis>\n"; print "</refsynopsisdiv>\n"; output_section_xml(@_); print "</refentry>\n\n"; } # output in XML DocBook sub output_blockhead_xml(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; my $id = $args{'module'}; $id =~ s/[^A-Za-z0-9]/-/g; # print out each section $lineprefix=" "; foreach $section (@{$args{'sectionlist'}}) { if (!$args{'content-only'}) { print "<refsect1>\n <title>$section</title>\n"; } if ($section =~ m/EXAMPLE/i) { print "<example><para>\n"; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); if ($section =~ m/EXAMPLE/i) { print "</para></example>\n"; } else { print "</para>"; } if (!$args{'content-only'}) { print "\n</refsect1>\n"; } } print "\n\n"; } # output in XML DocBook sub output_function_gnome { my %args = %{$_[0]}; my ($parameter, $section); my $count; my $id; $id = $args{'module'} . "-" . $args{'function'}; $id =~ s/[^A-Za-z0-9]/-/g; print "<sect2>\n"; print " <title id=\"$id\">" . $args{'function'} . "</title>\n"; print " <funcsynopsis>\n"; print " <funcdef>" . $args{'functiontype'} . " "; print "<function>" . $args{'function'} . " "; print "</function></funcdef>\n"; $count = 0; if ($#{$args{'parameterlist'}} >= 0) { foreach $parameter (@{$args{'parameterlist'}}) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print " <paramdef>$1 <parameter>$parameter</parameter>)\n"; print " <funcparams>$2</funcparams></paramdef>\n"; } else { print " <paramdef>" . $type; print " <parameter>$parameter</parameter></paramdef>\n"; } } } else { print " <void>\n"; } print " </funcsynopsis>\n"; if ($#{$args{'parameterlist'}} >= 0) { print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n"; print "<tgroup cols=\"2\">\n"; print "<colspec colwidth=\"2*\">\n"; print "<colspec colwidth=\"8*\">\n"; print "<tbody>\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; print " <row><entry align=\"right\"><parameter>$parameter</parameter></entry>\n"; print " <entry>\n"; $lineprefix=" "; output_highlight($args{'parameterdescs'}{$parameter_name}); print " </entry></row>\n"; } print " </tbody></tgroup></informaltable>\n"; } else { print " <para>\n None\n </para>\n"; } # print out each section $lineprefix=" "; foreach $section (@{$args{'sectionlist'}}) { print "<simplesect>\n <title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<example><programlisting>\n"; } else { } print "<para>\n"; output_highlight($args{'sections'}{$section}); print "</para>\n"; if ($section =~ m/EXAMPLE/i) { print "</programlisting></example>\n"; } else { } print " </simplesect>\n"; } print "</sect2>\n\n"; } ## # output function in man sub output_function_man(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; print ".SH NAME\n"; print $args{'function'} . " \\- " . $args{'purpose'} . "\n"; print ".SH SYNOPSIS\n"; if ($args{'functiontype'} ne "") { print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; } else { print ".B \"" . $args{'function'} . "\n"; } $count = 0; my $parenth = "("; my $post = ","; foreach my $parameter (@{$args{'parameterlist'}}) { if ($count == $#{$args{'parameterlist'}}) { $post = ");"; } $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n"; } else { $type =~ s/([^\*])$/$1 /; print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n"; } $count++; $parenth = ""; } print ".SH ARGUMENTS\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; print ".IP \"" . $parameter . "\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { print ".SH \"", uc $section, "\"\n"; output_highlight($args{'sections'}{$section}); } } ## # output enum in man sub output_enum_man(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n"; print ".SH SYNOPSIS\n"; print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { print ".br\n.BI \" $parameter\"\n"; if ($count == $#{$args{'parameterlist'}}) { print "\n};\n"; last; } else { print ", \n.br\n"; } $count++; } print ".SH Constants\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; print ".IP \"" . $parameter . "\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { print ".SH \"$section\"\n"; output_highlight($args{'sections'}{$section}); } } ## # output struct in man sub output_struct_man(%) { my %args = %{$_[0]}; my ($parameter, $section); print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n"; print ".SH SYNOPSIS\n"; print $args{'type'} . " " . $args{'struct'} . " {\n.br\n"; foreach my $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print ".BI \"$parameter\"\n.br\n"; next; } my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { # bitfield print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n"; } else { $type =~ s/([^\*])$/$1 /; print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n"; } print "\n.br\n"; } print "};\n.br\n"; print ".SH Members\n"; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print ".IP \"" . $parameter . "\" 12\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { print ".SH \"$section\"\n"; output_highlight($args{'sections'}{$section}); } } ## # output typedef in man sub output_typedef_man(%) { my %args = %{$_[0]}; my ($parameter, $section); print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n"; print ".SH NAME\n"; print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; foreach $section (@{$args{'sectionlist'}}) { print ".SH \"$section\"\n"; output_highlight($args{'sections'}{$section}); } } sub output_blockhead_man(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n"; foreach $section (@{$args{'sectionlist'}}) { print ".SH \"$section\"\n"; output_highlight($args{'sections'}{$section}); } } ## # output in text sub output_function_text(%) { my %args = %{$_[0]}; my ($parameter, $section); my $start; print "Name:\n\n"; print $args{'function'} . " - " . $args{'purpose'} . "\n"; print "\nSynopsis:\n\n"; if ($args{'functiontype'} ne "") { $start = $args{'functiontype'} . " " . $args{'function'} . " ("; } else { $start = $args{'function'} . " ("; } print $start; my $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print $1 . $parameter . ") (" . $2; } else { print $type . " " . $parameter; } if ($count != $#{$args{'parameterlist'}}) { $count++; print ",\n"; print " " x length($start); } else { print ");\n\n"; } } print "Arguments:\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n"; } output_section_text(@_); } #output sections in text sub output_section_text(%) { my %args = %{$_[0]}; my $section; print "\n"; foreach $section (@{$args{'sectionlist'}}) { print "$section:\n\n"; output_highlight($args{'sections'}{$section}); } print "\n\n"; } # output enum in text sub output_enum_text(%) { my %args = %{$_[0]}; my ($parameter); my $count; print "Enum:\n\n"; print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n"; print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach $parameter (@{$args{'parameterlist'}}) { print "\t$parameter"; if ($count != $#{$args{'parameterlist'}}) { $count++; print ","; } print "\n"; } print "};\n\n"; print "Constants:\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { print "$parameter\n\t"; print $args{'parameterdescs'}{$parameter} . "\n"; } output_section_text(@_); } # output typedef in text sub output_typedef_text(%) { my %args = %{$_[0]}; my ($parameter); my $count; print "Typedef:\n\n"; print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n"; output_section_text(@_); } # output struct as text sub output_struct_text(%) { my %args = %{$_[0]}; my ($parameter); print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n"; print $args{'type'} . " " . $args{'struct'} . " {\n"; foreach $parameter (@{$args{'parameterlist'}}) { if ($parameter =~ /^#/) { print "$parameter\n"; next; } my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; $type = $args{'parametertypes'}{$parameter}; if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { # pointer-to-function print "\t$1 $parameter) ($2);\n"; } elsif ($type =~ m/^(.*?)\s*(:.*)/) { # bitfield print "\t$1 $parameter$2;\n"; } else { print "\t" . $type . " " . $parameter . ";\n"; } } print "};\n\n"; print "Members:\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { ($parameter =~ /^#/) && next; my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; print "$parameter\n\t"; print $args{'parameterdescs'}{$parameter_name} . "\n"; } print "\n"; output_section_text(@_); } sub output_blockhead_text(%) { my %args = %{$_[0]}; my ($parameter, $section); foreach $section (@{$args{'sectionlist'}}) { print " $section:\n"; print " -> "; output_highlight($args{'sections'}{$section}); } } ## # generic output function for all types (function, struct/union, typedef, enum); # calls the generated, variable output_ function name based on # functype and output_mode sub output_declaration { no strict 'refs'; my $name = shift; my $functype = shift; my $func = "output_${functype}_$output_mode"; if (($function_only==0) || ( $function_only == 1 && defined($function_table{$name})) || ( $function_only == 2 && !defined($function_table{$name}))) { &$func(@_); $section_counter++; } } ## # generic output function - calls the right one based on current output mode. sub output_blockhead { no strict 'refs'; my $func = "output_blockhead_" . $output_mode; &$func(@_); $section_counter++; } ## # takes a declaration (struct, union, enum, typedef) and # invokes the right handler. NOT called for functions. sub dump_declaration($$) { no strict 'refs'; my ($prototype, $file) = @_; my $func = "dump_" . $decl_type; &$func(@_); } sub dump_union($$) { dump_struct(@_); } sub dump_struct($$) { my $x = shift; my $file = shift; my $nested; if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { #my $decl_type = $1; $declaration_name = $2; my $members = $3; # ignore embedded structs or unions $members =~ s/({.*})//g; $nested = $1; # ignore members marked private: $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gos; $members =~ s/\/\*\s*private:.*//gos; # strip comments: $members =~ s/\/\*.*?\*\///gos; $nested =~ s/\/\*.*?\*\///gos; # strip kmemcheck_bitfield_{begin,end}.*; $members =~ s/kmemcheck_bitfield_.*?;//gos; create_parameterlist($members, ';', $file); check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested); output_declaration($declaration_name, 'struct', {'struct' => $declaration_name, 'module' => $modulename, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'parametertypes' => \%parametertypes, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose, 'type' => $decl_type }); } else { print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; ++$errors; } } sub dump_enum($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { $declaration_name = $1; my $members = $2; foreach my $arg (split ',', $members) { $arg =~ s/^\s*(\w+).*/$1/; push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; print STDERR "Warning(${file}:$.): Enum value '$arg' ". "not described in enum '$declaration_name'\n"; } } output_declaration($declaration_name, 'enum', {'enum' => $declaration_name, 'module' => $modulename, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } else { print STDERR "Error(${file}:$.): Cannot parse enum!\n"; ++$errors; } } sub dump_typedef($$) { my $x = shift; my $file = shift; $x =~ s@/\*.*?\*/@@gos; # strip comments. while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { $x =~ s/\(*.\)\s*;$/;/; $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { $declaration_name = $1; output_declaration($declaration_name, 'typedef', {'typedef' => $declaration_name, 'module' => $modulename, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } else { print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; ++$errors; } } sub save_struct_actual($) { my $actual = shift; # strip all spaces from the actual param so that it looks like one string item $actual =~ s/\s*//g; $struct_actual = $struct_actual . $actual . " "; } sub create_parameterlist($$$) { my $args = shift; my $splitter = shift; my $file = shift; my $type; my $param; # temporarily replace commas inside function pointer definition while ($args =~ /(\([^\),]+),/) { $args =~ s/(\([^\),]+),/$1#/g; } foreach my $arg (split($splitter, $args)) { # strip comments $arg =~ s/\/\*.*\*\///; # strip leading/trailing spaces $arg =~ s/^\s*//; $arg =~ s/\s*$//; $arg =~ s/\s+/ /; if ($arg =~ /^#/) { # Treat preprocessor directive as a typeless variable just to fill # corresponding data structures "correctly". Catch it later in # output_* subs. push_parameter($arg, "", $file); } elsif ($arg =~ m/\(.+\)\s*\(/) { # pointer-to-function $arg =~ tr/#/,/; $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/; $param = $1; $type = $arg; $type =~ s/([^\(]+\(\*?)\s*$param/$1/; save_struct_actual($param); push_parameter($param, $type, $file); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; $arg =~ s/\s*\[/\[/g; my @args = split('\s*,\s*', $arg); if ($args[0] =~ m/\*/) { $args[0] =~ s/(\*+)\s*/ $1/; } my @first_arg; if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { shift @args; push(@first_arg, split('\s+', $1)); push(@first_arg, $2); } else { @first_arg = split('\s+', shift @args); } unshift(@args, pop @first_arg); $type = join " ", @first_arg; foreach $param (@args) { if ($param =~ m/^(\*+)\s*(.*)/) { save_struct_actual($2); push_parameter($2, "$type $1", $file); } elsif ($param =~ m/(.*?):(\d+)/) { if ($type ne "") { # skip unnamed bit-fields save_struct_actual($1); push_parameter($1, "$type:$2", $file) } } else { save_struct_actual($param); push_parameter($param, $type, $file); } } } } } sub push_parameter($$$) { my $param = shift; my $type = shift; my $file = shift; if (($anon_struct_union == 1) && ($type eq "") && ($param eq "}")) { return; # ignore the ending }; from anon. struct/union } $anon_struct_union = 0; my $param_name = $param; $param_name =~ s/\[.*//; if ($type eq "" && $param =~ /\.\.\.$/) { if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { $parameterdescs{$param} = "variable arguments"; } } elsif ($type eq "" && ($param eq "" or $param eq "void")) { $param="void"; $parameterdescs{void} = "no arguments"; } elsif ($type eq "" && ($param eq "struct" or $param eq "union")) # handle unnamed (anonymous) union or struct: { $type = $param; $param = "{unnamed_" . $param . "}"; $parameterdescs{$param} = "anonymous\n"; $anon_struct_union = 1; } # warn if parameter has no description # (but ignore ones starting with # as these are not parameters # but inline preprocessor statements); # also ignore unnamed structs/unions; if (!$anon_struct_union) { if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { $parameterdescs{$param_name} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { print STDERR "Warning(${file}:$.): Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } print STDERR "Warning(${file}:$.):" . " No description found for parameter '$param'\n"; ++$warnings; } } # strip spaces from $param so that it is one continous string # on @parameterlist; # this fixes a problem where check_sections() cannot find # a parameter like "addr[6 + 2]" because it actually appears # as "addr[6", "+", "2]" on the parameter list; # but it's better to maintain the param string unchanged for output, # so just weaken the string compare in check_sections() to ignore # "[blah" in a parameter string; ###$param =~ s/\s*//g; push @parameterlist, $param; $parametertypes{$param} = $type; } sub check_sections($$$$$$) { my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_; my @sects = split ' ', $sectcheck; my @prms = split ' ', $prmscheck; my $err; my ($px, $sx); my $prm_clean; # strip trailing "[array size]" and/or beginning "*" foreach $sx (0 .. $#sects) { $err = 1; foreach $px (0 .. $#prms) { $prm_clean = $prms[$px]; $prm_clean =~ s/\[.*\]//; $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//; # ignore array size in a parameter string; # however, the original param string may contain # spaces, e.g.: addr[6 + 2] # and this appears in @prms as "addr[6" since the # parameter list is split at spaces; # hence just ignore "[..." for the sections check; $prm_clean =~ s/\[.*//; ##$prm_clean =~ s/^\**//; if ($prm_clean eq $sects[$sx]) { $err = 0; last; } } if ($err) { if ($decl_type eq "function") { print STDERR "Warning(${file}:$.): " . "Excess function parameter " . "'$sects[$sx]' " . "description in '$decl_name'\n"; ++$warnings; } else { if ($nested !~ m/\Q$sects[$sx]\E/) { print STDERR "Warning(${file}:$.): " . "Excess struct/union/enum/typedef member " . "'$sects[$sx]' " . "description in '$decl_name'\n"; ++$warnings; } } } } } ## # takes a function prototype and the name of the current file being # processed and spits out all the details stored in the global # arrays/hashes. sub dump_function($$) { my $prototype = shift; my $file = shift; $prototype =~ s/LWS_VISIBLE +//; $prototype =~ s/^static +//; $prototype =~ s/^extern +//; $prototype =~ s/^asmlinkage +//; $prototype =~ s/^inline +//; $prototype =~ s/^__inline__ +//; $prototype =~ s/^__inline +//; $prototype =~ s/^__always_inline +//; $prototype =~ s/^noinline +//; $prototype =~ s/__devinit +//; $prototype =~ s/__init +//; $prototype =~ s/^#\s*define\s+//; #ak added $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; # Yes, this truly is vile. We are looking for: # 1. Return type (may be nothing if we're looking at a macro) # 2. Function name # 3. Function parameters. # # All the while we have to watch out for function pointer parameters # (which IIRC is what the two sections are for), C types (these # regexps don't even start to express all the possibilities), and # so on. # # If you mess with these regexps, it's a good idea to check that # the following functions' documentation still comes out right: # - parport_register_device (function pointer parameters) # - atomic_set (macro) # - pci_match_device, __copy_to_user (long return type) if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { $return_type = $1; $declaration_name = $2; my $args = $3; create_parameterlist($args, ',', $file); } else { print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n"; ++$errors; return; } my $prms = join " ", @parameterlist; check_sections($file, $declaration_name, "function", $sectcheck, $prms, ""); output_declaration($declaration_name, 'function', {'function' => $declaration_name, 'module' => $modulename, 'functiontype' => $return_type, 'parameterlist' => \@parameterlist, 'parameterdescs' => \%parameterdescs, 'parametertypes' => \%parametertypes, 'sectionlist' => \@sectionlist, 'sections' => \%sections, 'purpose' => $declaration_purpose }); } sub process_file($); # Read the file that maps relative names to absolute names for # separate source and object directories and for shadow trees. if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { my ($relname, $absname); while(<SOURCE_MAP>) { chop(); ($relname, $absname) = (split())[0..1]; $relname =~ s:^/+::; $source_map{$relname} = $absname; } close(SOURCE_MAP); } if ($filelist) { open(FLIST,"<$filelist") or die "Can't open file list $filelist"; while(<FLIST>) { chop; process_file($_); } } foreach (@ARGV) { chomp; process_file($_); } if ($verbose && $errors) { print STDERR "$errors errors\n"; } if ($verbose && $warnings) { print STDERR "$warnings warnings\n"; } exit($errors); sub reset_state { $function = ""; %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $sectcheck = ""; $struct_actual = ""; $prototype = ""; $state = 0; } sub tracepoint_munge($) { my $file = shift; my $tracepointname = 0; my $tracepointargs = 0; if ($prototype =~ m/TRACE_EVENT\((.*?),/) { $tracepointname = $1; } if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { $tracepointname = $1; } if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { $tracepointname = $2; } $tracepointname =~ s/^\s+//; #strip leading whitespace if ($prototype =~ m/TP_PROTO\((.*?)\)/) { $tracepointargs = $1; } if (($tracepointname eq 0) || ($tracepointargs eq 0)) { print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n". "$prototype\n"; } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; } } sub syscall_munge() { my $void = 0; $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs ## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { if ($prototype =~ m/SYSCALL_DEFINE0/) { $void = 1; ## $prototype = "long sys_$1(void)"; } $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name if ($prototype =~ m/long (sys_.*?),/) { $prototype =~ s/,/\(/; } elsif ($void) { $prototype =~ s/\)/\(void\)/; } # now delete all of the odd-number commas in $prototype # so that arg types & arg names don't have a comma between them my $count = 0; my $len = length($prototype); if ($void) { $len = 0; # skip the for-loop } for (my $ix = 0; $ix < $len; $ix++) { if (substr($prototype, $ix, 1) eq ',') { $count++; if ($count % 2 == 1) { substr($prototype, $ix, 1) = ' '; } } } } sub process_state3_function($$) { my $x = shift; my $file = shift; $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) { # do nothing } elsif ($x =~ /([^\{]*)/) { $prototype .= $1; } if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { $prototype =~ s@/\*.*?\*/@@gos; # strip comments. $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. $prototype =~ s@^\s+@@gos; # strip leading spaces if ($prototype =~ /SYSCALL_DEFINE/) { syscall_munge(); } if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || $prototype =~ /DEFINE_SINGLE_EVENT/) { tracepoint_munge($file); } dump_function($prototype, $file); reset_state(); } } sub process_state3_type($$) { my $x = shift; my $file = shift; $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's. $x =~ s@^\s+@@gos; # strip leading spaces $x =~ s@\s+$@@gos; # strip trailing spaces $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line if ($x =~ /^#/) { # To distinguish preprocessor directive from regular declaration later. $x .= ";"; } while (1) { if ( $x =~ /([^{};]*)([{};])(.*)/ ) { $prototype .= $1 . $2; ($2 eq '{') && $brcount++; ($2 eq '}') && $brcount--; if (($2 eq ';') && ($brcount == 0)) { dump_declaration($prototype, $file); reset_state(); last; } $x = $3; } else { $prototype .= $x; last; } } } # xml_escape: replace <, >, and & in the text stream; # # however, formatting controls that are generated internally/locally in the # kernel-doc script are not escaped here; instead, they begin life like # $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings # are converted to their mnemonic-expected output, without the 4 * '\' & ':', # just before actual output; (this is done by local_unescape()) sub xml_escape($) { my $text = shift; if (($output_mode eq "text") || ($output_mode eq "man")) { return $text; } $text =~ s/\&/\\\\\\amp;/g; $text =~ s/\</\\\\\\lt;/g; $text =~ s/\>/\\\\\\gt;/g; return $text; } # convert local escape strings to html # local escape strings look like: '\\\\menmonic:' (that's 4 backslashes) sub local_unescape($) { my $text = shift; if (($output_mode eq "text") || ($output_mode eq "man")) { return $text; } $text =~ s/\\\\\\\\lt:/</g; $text =~ s/\\\\\\\\gt:/>/g; return $text; } sub process_file($) { my $file; my $identifier; my $func; my $descr; my $in_purpose = 0; my $initial_section_counter = $section_counter; if (defined($ENV{'SRCTREE'})) { $file = "$ENV{'SRCTREE'}" . "/" . "@_"; } else { $file = "@_"; } if (defined($source_map{$file})) { $file = $source_map{$file}; } if (!open(IN,"<$file")) { print STDERR "Error: Cannot open file $file\n"; ++$errors; return; } $section_counter = 0; while (<IN>) { if ($state == 0) { if (/$doc_start/o) { $state = 1; # next line is always the function name $in_doc_sect = 0; } } elsif ($state == 1) { # this line is the function name (always) if (/$doc_block/o) { $state = 4; $contents = ""; if ( $1 eq "" ) { $section = $section_intro; } else { $section = $1; } } elsif (/$doc_decl/o) { $identifier = $1; if (/\s*([\w\s]+?)\s*-/) { $identifier = $1; } $state = 2; if (/-(.*)/) { # strip leading/trailing/multiple spaces $descr= $1; $descr =~ s/^\s*//; $descr =~ s/\s*$//; $descr =~ s/\s+/ /; $declaration_purpose = xml_escape($descr); $in_purpose = 1; } else { $declaration_purpose = ""; } if (($declaration_purpose eq "") && $verbose) { print STDERR "Warning(${file}:$.): missing initial short description on line:\n"; print STDERR $_; ++$warnings; } if ($identifier =~ m/^struct/) { $decl_type = 'struct'; } elsif ($identifier =~ m/^union/) { $decl_type = 'union'; } elsif ($identifier =~ m/^enum/) { $decl_type = 'enum'; } elsif ($identifier =~ m/^typedef/) { $decl_type = 'typedef'; } else { $decl_type = 'function'; } if ($verbose) { print STDERR "Info(${file}:$.): Scanning doc for $identifier\n"; } } else { print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.", " - I thought it was a doc line\n"; ++$warnings; $state = 0; } } elsif ($state == 2) { # look for head: lines, and include content if (/$doc_sect/o) { $newsection = $1; $newcontents = $2; if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { print STDERR "Warning(${file}:$.): contents before sections\n"; ++$warnings; } dump_section($file, $section, xml_escape($contents)); $section = $section_default; } $in_doc_sect = 1; $in_purpose = 0; $contents = $newcontents; if ($contents ne "") { while ((substr($contents, 0, 1) eq " ") || substr($contents, 0, 1) eq "\t") { $contents = substr($contents, 1); } $contents .= "\n"; } $section = $newsection; } elsif (/$doc_end/) { if ($contents ne "") { dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; } # look for doc_com + <text> + doc_end: if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { print STDERR "Warning(${file}:$.): suspicious ending line: $_"; ++$warnings; } $prototype = ""; $state = 3; $brcount = 0; # print STDERR "end of doc comment, looking for prototype\n"; } elsif (/$doc_content/) { # miguel-style comment kludge, look for blank lines after # @parameter line to signify start of description if ($1 eq "") { if ($section =~ m/^@/ || $section eq $section_context) { dump_section($file, $section, xml_escape($contents)); $section = $section_default; $contents = ""; } else { $contents .= "\n"; } $in_purpose = 0; } elsif ($in_purpose == 1) { # Continued declaration purpose chomp($declaration_purpose); $declaration_purpose .= " " . xml_escape($1); } else { $contents .= $1 . "\n"; } } else { # i dont know - bad line? ignore. print STDERR "Warning(${file}:$.): bad line: $_"; ++$warnings; } } elsif ($state == 3) { # scanning for function '{' (end of prototype) if ($decl_type eq 'function') { process_state3_function($_, $file); } else { process_state3_type($_, $file); } } elsif ($state == 4) { # Documentation block if (/$doc_block/) { dump_doc_section($file, $section, xml_escape($contents)); $contents = ""; $function = ""; %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $prototype = ""; if ( $1 eq "" ) { $section = $section_intro; } else { $section = $1; } } elsif (/$doc_end/) { dump_doc_section($file, $section, xml_escape($contents)); $contents = ""; $function = ""; %constants = (); %parameterdescs = (); %parametertypes = (); @parameterlist = (); %sections = (); @sectionlist = (); $prototype = ""; $state = 0; } elsif (/$doc_content/) { if ( $1 eq "" ) { $contents .= $blankline; } else { $contents .= $1 . "\n"; } } } } if ($initial_section_counter == $section_counter) { print STDERR "Warning(${file}): no structured comments found\n"; if ($output_mode eq "xml") { # The template wants at least one RefEntry here; make one. print "<refentry>\n"; print " <refnamediv>\n"; print " <refname>\n"; print " ${file}\n"; print " </refname>\n"; print " <refpurpose>\n"; print " Document generation inconsistency\n"; print " </refpurpose>\n"; print " </refnamediv>\n"; print " <refsect1>\n"; print " <title>\n"; print " Oops\n"; print " </title>\n"; print " <warning>\n"; print " <para>\n"; print " The template for this document tried to insert\n"; print " the structured comment from the file\n"; print " <filename>${file}</filename> at this point,\n"; print " but none was found.\n"; print " This dummy section is inserted to allow\n"; print " generation to continue.\n"; print " </para>\n"; print " </warning>\n"; print " </refsect1>\n"; print "</refentry>\n"; } } } |
Added undroid/libwebsockets/test-server/attack.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/bash # # attack the test server and try to make it fall over # SERVER=127.0.0.1 PORT=7681 LOG=/tmp/lwslog A=`which libwebsockets-test-server` INSTALLED=`dirname $A` CPID= LEN=0 function check { kill -0 $CPID if [ $? -ne 0 ] ; then echo "(killed it) *******" exit 1 fi dd if=$LOG bs=1 skip=$LEN 2>/dev/null if [ "$1" = "default" ] ; then diff /tmp/lwscap $INSTALLED/../share/libwebsockets-test-server/test.html > /dev/null if [ $? -ne 0 ] ; then echo "FAIL: got something other than test.html back" exit 1 fi fi if [ "$1" = "forbidden" ] ; then if [ -z "`grep '<h1>403</h1>' /tmp/lwscap`" ] ; then echo "FAIL: should have told forbidden (test server has no dirs)" exit 1 fi fi if [ "$1" = "rejected" ] ; then if [ -z "`grep '<h1>406</h1>' /tmp/lwscap`" ] ; then echo "FAIL: should have told forbidden (test server has no dirs)" exit 1 fi fi if [ "$1" = "media" ] ; then if [ -z "`grep '<h1>415</h1>' /tmp/lwscap`" ] ; then echo "FAIL: should have told unknown media type" exit 1 fi fi if [ "$1" == "0" ] ; then a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep "get\ \ =" | tr -s ' ' | cut -d' ' -f4-`" if [ "$a" != "$2" ] ; then echo "URL path '$a' not $2" exit 1 fi fi if [ "$1" == "1" ] ; then a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep URI\ Arg\ 1\: | tr -s ' ' | cut -d' ' -f5-`" if [ "$a" != "$2" ] ; then echo "Arg 1 '$a' not $2" exit 1 fi fi if [ "$1" == "2" ] ; then a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep URI\ Arg\ 2\: | tr -s ' ' | cut -d' ' -f5-`" if [ "$a" != "$2" ] ; then echo "Arg 2 '$a' not $2" exit 1 fi fi if [ "$1" == "3" ] ; then a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep URI\ Arg\ 3\: | tr -s ' ' | cut -d' ' -f5-`" if [ "$a" != "$2" ] ; then echo "Arg 3 '$a' not $2" exit 1 fi fi if [ -z "$1" ] ; then LEN=`stat $LOG -c %s` fi } rm -rf $LOG killall libwebsockets-test-server 2>/dev/null libwebsockets-test-server -d15 2>> $LOG & CPID=$! while [ -z "`grep Listening $LOG`" ] ; do sleep 0.5s done check echo echo "---- /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F" rm -f /tmp/lwscap echo -e "GET /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check 1 "UPDATE_SETTINGS=1" check 2 "Root_Channels_1_Channel_name_http_post=?" check 3 "Root_Channels_1_Channel_location_http_post=?" check echo echo "---- ? processing (/cgi-bin/settings.js?key1=value1)" rm -f /tmp/lwscap echo -e "GET /cgi-bin/settings.js?key1=value1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check 1 "key1=value1" check echo echo "---- ? processing (/t%3dest?key1%3d2=value1)" rm -f /tmp/lwscap echo -e "GET /t%3dest?key1%3d2=value1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check 0 "/t=est" check 1 "key1_2=value1" check echo echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=1)" rm -f /tmp/lwscap echo -e "GET %2f%2e%2e%2f%2e./test.html?arg=1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check 1 "arg=1" check echo echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=/../.)" rm -f /tmp/lwscap echo -e "GET %2f%2e%2e%2f%2e./test.html?arg=/../. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check 1 "arg=/../." check echo echo "---- spam enough crap to not be GET" echo "not GET" | nc $SERVER $PORT check echo echo "---- spam more than the name buffer of crap" dd if=/dev/urandom bs=1 count=80 2>/dev/null | nc -i1s $SERVER $PORT check echo echo "---- spam 10MB of crap" dd if=/dev/urandom bs=1 count=655360 | nc -i1s $SERVER $PORT check echo echo "---- malformed URI" echo "GET nonsense................................................................................................................" \ | nc -i1s $SERVER $PORT check echo echo "---- missing URI" echo -e "GET HTTP/1.1\x0d\x0a\x0d\x0a" | nc -i1s $SERVER $PORT >/tmp/lwscap check echo echo "---- repeated method" echo -e "GET blah HTTP/1.1\x0d\x0aGET blah HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT >/tmp/lwscap check echo echo "---- crazy header name part" echo -e "GET blah HTTP/1.1\x0d\x0a................................................................................................................" \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ | nc -i1s $SERVER $PORT check echo echo "---- excessive uri content" echo -e "GET ................................................................................................................" \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ | nc -i1s $SERVER $PORT check echo echo "---- good request but http payload coming too (should be ignored and test.html served)" echo -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ "......................................................................................................................." \ | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check default check echo echo "---- nonexistant file" rm -f /tmp/lwscap echo -e "GET /nope HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check media check echo echo "---- relative uri path" rm -f /tmp/lwscap echo -e "GET nope HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check forbidden check echo echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)" rm -f /tmp/lwscap echo -e "GET /../../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check rejected check echo echo "---- directory attack 2 (/../ should be /)" rm -f /tmp/lwscap echo -e "GET /../ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check default check echo echo "---- directory attack 3 (/./ should be /)" rm -f /tmp/lwscap echo -e "GET /./ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check default check echo echo "---- directory attack 4 (/blah/.. should be /)" rm -f /tmp/lwscap echo -e "GET /blah/.. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check default check echo echo "---- directory attack 5 (/blah/../ should be /)" rm -f /tmp/lwscap echo -e "GET /blah/../ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check default check echo echo "---- directory attack 6 (/blah/../. should be /)" rm -f /tmp/lwscap echo -e "GET /blah/../. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check default check echo echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)" rm -f /tmp/lwscap echo -e "GET /%2e%2e%2f../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check rejected check echo echo "---- directory attack 8 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)" rm -f /tmp/lwscap echo -e "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap check rejected check echo echo "---- http/1.1 pipelining" rm -f /tmp/lwscap wget -O/tmp/lwsdump http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html http://localhost:7681/test.html 2>&1 | grep "Downloaded: 8 files" > /tmp/lwscap good=`cat $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html $INSTALLED/../share/libwebsockets-test-server/test.html | md5sum | cut -d' ' -f1` if [ "$good" != "`md5sum /tmp/lwsdump | cut -d' ' -f 1`" ] ; then echo "FAIL: mismatched content good=$good received=`md5sum /tmp/lwsdump`" exit 1 fi echo echo "---- mass testing uri variations" rm -f /tmp/results for i in \ /..../ \ /.../. \ /...// \ /.../a \ /.../w \ /.../? \ /.../% \ /../.. \ /.././ \ /../.a \ /../.w \ /../.. \ /../.% \ /..//. \ /../// \ /..//a \ /..//w \ /..//? \ /..//% \ /../a. \ /../a/ \ /../aa \ /../aw \ /../a? \ /../a% \ /../w. \ /../w/ \ /../wa \ /../ww \ /../w? \ /../w% \ /../?. \ /../?/ \ /../?a \ /../?w \ /../?? \ /../?% \ /../%. \ /../%/ \ /../%a \ /../%w \ /../%? \ /../%% \ /./... \ /./../ \ /./..a \ /./..w \ /./..? \ /./..% \ /.//.. \ /.a../ \ /.a/.. \ /.w../ \ /.w/.. \ /.?../ \ /../.. \ /.%../ \ /.%/.. \ //.... \ //.../ \ //...a \ //...w \ //...? \ //...% \ //../. \ //..// \ //../a \ //../w \ //../? \ //../% \ //..a. \ //..a/ \ //..aa \ //..aw \ //..a? \ //..a% \ //..w. \ //..w/ \ //..wa \ //..ww \ //..w? \ //..w% \ //..?. \ //..?/ \ //..?a \ //..?w \ //..?? \ //..?% \ //..%. \ //..%/ \ //..%a \ //..%w \ //..%? \ //..%% \ //./.. \ ///... \ ///../ \ ///..a \ ///..w \ ///..? \ ///..% \ ////.. \ //a../ \ //a/.. \ //w../ \ //w/.. \ //?../ \ //?/.. \ //%../ \ //%/.. \ /a.../ \ /a../. \ /a..// \ /a../a \ /a../w \ /a../? \ /a../% \ /a./.. \ /a/... \ /a/../ \ /a/..a \ /a/..w \ /a/..? \ /a/..% \ /a//.. \ /aa../ \ /aa/.. \ /aw../ \ /aw/.. \ /a?../ \ /a?/.. \ /a%../ \ /a%/.. \ /w.../ \ /w../. \ /w..// \ /w../a \ /w../w \ /w../? \ /w../% \ /w./.. \ /w/... \ /w/../ \ /w/..a \ /w/..w \ /w/..? \ /w/..% \ /w//.. \ /wa../ \ /wa/.. \ /ww../ \ /ww/.. \ /w?../ \ /w?/.. \ /w%../ \ /w%/.. \ /?.../ \ /?../. \ /?..// \ /?../a \ /?../w \ /?../? \ /?../% \ /?./.. \ /?/... \ /?/../ \ /?/..a \ /?/..w \ /?/..? \ /?/..% \ /?//.. \ /?a../ \ /?a/.. \ /?w../ \ /?w/.. \ /??../ \ /??/.. \ /?%../ \ /?%/.. \ /%.../ \ /%../. \ /%..// \ /%../a \ /%../w \ /%../? \ /%../% \ /%./.. \ /%/... \ /%/../ \ /%/..a \ /%/..w \ /%/..? \ /%/..% \ /%//.. \ /%a../ \ /%a/.. \ /%w../ \ /%w/.. \ /%?../ \ /%?/.. \ /%%../ \ /%%/.. \ /a/w/../a \ /path/to/dir/../other/dir \ ; do R=`rm -f /tmp/lwscap ; echo -n -e "GET $i HTTP/1.0\r\n\r\n" | nc localhost 7681 2>/dev/null >/tmp/lwscap; head -n1 /tmp/lwscap| cut -d' ' -f2` cat /tmp/lwscap | head -n1 echo ==== $R if [ "$R" != "403" ]; then U=`cat $LOG | grep lws_http_serve | tail -n 1 | cut -d':' -f3 | cut -d' ' -f2` echo $U echo "- \"$i\" -> $R \"$U\"" >>/tmp/results else echo "- \"$i\" -> $R" >>/tmp/results fi done cat <<EOF >/tmp/lwsresult1 - "/..../" -> 406 "/..../" - "/.../." -> 406 "/.../" - "/...//" -> 406 "/.../" - "/.../a" -> 406 "/.../a" - "/.../w" -> 406 "/.../w" - "/.../?" -> 406 "/.../" - "/.../%" -> 403 - "/../.." -> 200 "/" - "/.././" -> 200 "/" - "/../.a" -> 415 "/.a" - "/../.w" -> 415 "/.w" - "/../.." -> 200 "/" - "/../.%" -> 403 - "/..//." -> 200 "/" - "/..///" -> 200 "/" - "/..//a" -> 415 "/a" - "/..//w" -> 415 "/w" - "/..//?" -> 200 "/" - "/..//%" -> 403 - "/../a." -> 415 "/a." - "/../a/" -> 406 "/a/" - "/../aa" -> 415 "/aa" - "/../aw" -> 415 "/aw" - "/../a?" -> 415 "/a" - "/../a%" -> 403 - "/../w." -> 415 "/w." - "/../w/" -> 406 "/w/" - "/../wa" -> 415 "/wa" - "/../ww" -> 415 "/ww" - "/../w?" -> 415 "/w" - "/../w%" -> 403 - "/../?." -> 200 "/" - "/../?/" -> 200 "/" - "/../?a" -> 200 "/" - "/../?w" -> 200 "/" - "/../??" -> 200 "/" - "/../?%" -> 403 - "/../%." -> 403 - "/../%/" -> 403 - "/../%a" -> 403 - "/../%w" -> 403 - "/../%?" -> 403 - "/../%%" -> 403 - "/./..." -> 415 "/..." - "/./../" -> 200 "/" - "/./..a" -> 415 "/..a" - "/./..w" -> 415 "/..w" - "/./..?" -> 200 "/" - "/./..%" -> 403 - "/.//.." -> 200 "/" - "/.a../" -> 406 "/.a../" - "/.a/.." -> 200 "/" - "/.w../" -> 406 "/.w../" - "/.w/.." -> 200 "/" - "/.?../" -> 415 "/." - "/../.." -> 200 "/" - "/.%../" -> 403 - "/.%/.." -> 403 - "//...." -> 415 "/...." - "//.../" -> 406 "/.../" - "//...a" -> 415 "/...a" - "//...w" -> 415 "/...w" - "//...?" -> 415 "/..." - "//...%" -> 403 - "//../." -> 200 "/" - "//..//" -> 200 "/" - "//../a" -> 415 "/a" - "//../w" -> 415 "/w" - "//../?" -> 200 "/" - "//../%" -> 403 - "//..a." -> 415 "/..a." - "//..a/" -> 406 "/..a/" - "//..aa" -> 415 "/..aa" - "//..aw" -> 415 "/..aw" - "//..a?" -> 415 "/..a" - "//..a%" -> 403 - "//..w." -> 415 "/..w." - "//..w/" -> 406 "/..w/" - "//..wa" -> 415 "/..wa" - "//..ww" -> 415 "/..ww" - "//..w?" -> 415 "/..w" - "//..w%" -> 403 - "//..?." -> 200 "/" - "//..?/" -> 200 "/" - "//..?a" -> 415 "/a" - "//..?w" -> 415 "/w" - "//..??" -> 200 "/" - "//..?%" -> 403 - "//..%." -> 403 - "//..%/" -> 403 - "//..%a" -> 403 - "//..%w" -> 403 - "//..%?" -> 403 - "//..%%" -> 403 - "//./.." -> 200 "/" - "///..." -> 415 "/..." - "///../" -> 200 "/" - "///..a" -> 415 "/..a" - "///..w" -> 415 "/..w" - "///..?" -> 200 "/" - "///..%" -> 403 - "////.." -> 200 "/" - "//a../" -> 406 "/a../" - "//a/.." -> 200 "/" - "//w../" -> 406 "/w../" - "//w/.." -> 200 "/" - "//?../" -> 200 "/" - "//?/.." -> 200 "/" - "//%../" -> 403 - "//%/.." -> 403 - "/a.../" -> 406 "/a.../" - "/a../." -> 406 "/a../" - "/a..//" -> 406 "/a../" - "/a../a" -> 406 "/a../a" - "/a../w" -> 406 "/a../w" - "/a../?" -> 406 "/a../" - "/a../%" -> 403 - "/a./.." -> 200 "/" - "/a/..." -> 406 "/a/..." - "/a/../" -> 200 "/" - "/a/..a" -> 406 "/a/..a" - "/a/..w" -> 406 "/a/..w" - "/a/..?" -> 200 "/" - "/a/..%" -> 403 - "/a//.." -> 200 "/" - "/aa../" -> 406 "/aa../" - "/aa/.." -> 200 "/" - "/aw../" -> 406 "/aw../" - "/aw/.." -> 200 "/" - "/a?../" -> 415 "/a" - "/a?/.." -> 415 "/a" - "/a%../" -> 403 - "/a%/.." -> 403 - "/w.../" -> 406 "/w.../" - "/w../." -> 406 "/w../" - "/w..//" -> 406 "/w../" - "/w../a" -> 406 "/w../a" - "/w../w" -> 406 "/w../w" - "/w../?" -> 406 "/w../" - "/w../%" -> 403 - "/w./.." -> 200 "/" - "/w/..." -> 406 "/w/..." - "/w/../" -> 200 "/" - "/w/..a" -> 406 "/w/..a" - "/w/..w" -> 406 "/w/..w" - "/w/..?" -> 200 "/" - "/w/..%" -> 403 - "/w//.." -> 200 "/" - "/wa../" -> 406 "/wa../" - "/wa/.." -> 200 "/" - "/ww../" -> 406 "/ww../" - "/ww/.." -> 200 "/" - "/w?../" -> 415 "/w" - "/w?/.." -> 415 "/w" - "/w%../" -> 403 - "/w%/.." -> 403 - "/?.../" -> 200 "/" - "/?../." -> 200 "/" - "/?..//" -> 200 "/" - "/?../a" -> 200 "/" - "/?../w" -> 200 "/" - "/?../?" -> 200 "/" - "/?../%" -> 403 - "/?./.." -> 200 "/" - "/?/..." -> 200 "/" - "/?/../" -> 200 "/" - "/?/..a" -> 200 "/" - "/?/..w" -> 200 "/" - "/?/..?" -> 200 "/" - "/?/..%" -> 403 - "/?//.." -> 200 "/" - "/?a../" -> 200 "/" - "/?a/.." -> 200 "/" - "/?w../" -> 200 "/" - "/?w/.." -> 200 "/" - "/??../" -> 200 "/" - "/??/.." -> 200 "/" - "/?%../" -> 403 - "/?%/.." -> 403 - "/%.../" -> 403 - "/%../." -> 403 - "/%..//" -> 403 - "/%../a" -> 403 - "/%../w" -> 403 - "/%../?" -> 403 - "/%../%" -> 403 - "/%./.." -> 403 - "/%/..." -> 403 - "/%/../" -> 403 - "/%/..a" -> 403 - "/%/..w" -> 403 - "/%/..?" -> 403 - "/%/..%" -> 403 - "/%//.." -> 403 - "/%a../" -> 403 - "/%a/.." -> 403 - "/%w../" -> 403 - "/%w/.." -> 403 - "/%?../" -> 403 - "/%?/.." -> 403 - "/%%../" -> 403 - "/%%/.." -> 403 - "/a/w/../a" -> 406 "/a/a" - "/path/to/dir/../other/dir" -> 406 "/path/to/other/dir" EOF if [ "`md5sum /tmp/results | cut -d' ' -f 1`" != "`md5sum /tmp/lwsresult1 | cut -d' ' -f1`" ] ; then echo "Differences..." diff -urN /tmp/results /tmp/lwsresult1 exit 1 else echo "OK" fi echo echo "--- survived OK ---" kill -2 $CPID exit 0 |
Added undroid/libwebsockets/test-server/favicon.ico.
cannot compute difference between binary files
Added undroid/libwebsockets/test-server/fuzxy.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * fuzzing proxy - network-level fuzzing injection proxy * * Copyright (C) 2016 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * * * fuzxy is designed to go on the client path * * [ client <-> fuzxy ] <-> server * * you can arrange that with, eg, * * http_proxy=localhost:8880 * * env var before starting the client. * * Even though he is on the client side, he is able to see and change traffic * in both directions, and so fuzz both the client and the server. */ #if defined(_WIN32) && defined(EXTERNAL_POLL) #define WINVER 0x0600 #define _WIN32_WINNT 0x0600 #define poll(fdArray, fds, timeout) WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout)) #endif #include "lws_config.h" #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <signal.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #include <errno.h> #include "../lib/libwebsockets.h" #ifdef _WIN32 #include <io.h> #include "gettimeofday.h" #else #include <syslog.h> #include <sys/time.h> #include <unistd.h> #include <sys/socket.h> #endif #if defined(__NetBSD__) #include <netinet/in.h> #endif #define MAX_FUZZ_BUF (1024 * 1024) enum types { FZY_S_DEAD = 0, FZY_S_LISTENING = 1, FZY_S_ACCEPTED = 2, FZY_S_PROXIED = 3, FZY_S_ONWARD = 4, }; enum proxy_parser_states { FZY_PP_CONNECT = 0, FZY_PP_ADDRESS = 1, FZY_PP_PORT = 2, FZY_PP_CRLFS = 3, }; enum fuzzer_parser_states { FZY_FP_SEARCH = 0, FZY_FP_SEARCH2 = 1, FZY_FP_INJECT_PREPARE = 2, FZY_FP_INJECT = 3, FZY_FP_PENDING = 4, }; struct ring { char buf[4096]; int head; int tail; }; struct state { enum types type; enum proxy_parser_states pp; int ppc; struct ring in; char address[256]; int port; enum fuzzer_parser_states fp; int fuzc; int pending; int twin; /* must be fixed up when arrays lose guys */ unsigned int outbound:1; /* from local -> remote */ unsigned int is_pending:1; unsigned char buf[MAX_FUZZ_BUF]; unsigned int inject_len; }; struct test { const char *s[3]; int len[2]; unsigned int swallow:1; }; int force_exit = 0; int which = 5; static const struct test tests[] = { { { NULL, "\x0d\x0a\x0d\x0a", "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (248){ 0x89, 0xd2 }, 0x0d, 0x0a }," }, { 0, 4 }, 1 }, { { NULL, "\x0d\x0a\x0d\x0a", "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (1373){ 0x89, 0xd2 }, 0x0d, 0x0a }," }, { 0, 4 }, 1 }, { { NULL, "\x0d\x0a\x0d\x0a", "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (16967){ 0x89, 0xd2 }, (87){ 0xe2, 0x82, 0xac }, 0x0d, 0x0a }," }, { 0, 4 }, 1 }, { { NULL, "\x0d\x0a\x0d\x0a", "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " "0xef, 0xbb, 0xbf, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, " "0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, " "0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, " "0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, " "0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x0d, 0x0a, " }, { 0, 4 }, 1 }, { { NULL, "\x0d\x0a\x0d\x0a", "(20){0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " "0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, " "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, " "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, " "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, " "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, " "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, " "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, " "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, " "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, " "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, " "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, " "0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, " "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, " "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, " "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, " "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, " "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, " "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, " "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, " "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, " "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, " "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, " "0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, " "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, " "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, " "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, " "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, " "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, " "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, " "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, " "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, " "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, " "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, " "0x0a, 0xc0, 0x80, 0xef, 0xb7, 0x90, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, " "0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, " "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, " "0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, " "0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, " "0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, " "0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, " "0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, " "0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, " "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, " "0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, " "0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, " "0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, " "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, " "0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, " "0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, " "0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, " "0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, " "0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, " "0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, " "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, " "0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, " "0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, " "0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, " "0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, " "0x61, 0x64, 0x0d, 0x0a, }" }, { 0, 4 }, 1 }, { { NULL, "\x0d\x0a\x0d\x0a", "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " "0xef, 0xbb, 0xbf, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, " "0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, " "0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, " "0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, " "0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x0d, 0x0a, (2048){ 0x0d, 0x0a}" }, { 0, 4 }, 1 }, }; static const int ring_size(struct ring *r) { return sizeof(r->buf); } static const int ring_used(struct ring *r) { return (r->head - r->tail) & (ring_size(r) - 1); } static const int ring_free(struct ring *r) { return (ring_size(r) - 1) - ring_used(r); } static const int ring_get_one(struct ring *r) { int n = r->buf[r->tail] & 255; if (r->tail == r->head) return -1; r->tail++; if (r->tail == ring_size(r)) r->tail = 0; return n; } static int hex(char c) { if (c >= '0' && c <= '9') return c -'0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >='A' && c <= 'F') return c - 'A' + 10; return -1; } static int fuzxy_tok(const char **src, unsigned char **buf, int *len) { unsigned char *start; unsigned int count, rlen; while (**src) { if (**src == ' ' || **src == ',' || **src == '\n') { (*src)++; continue; } if ((*src)[0] == '}') { (*src)++; return 0; } if ((*src)[0] == '0' && (*src)[1] == 'x') { if (!len) { lwsl_err("out of space\n"); return -1; } ((*buf)++)[0] = (hex((*src)[2]) << 4) | hex((*src)[3]); *src += 4; (*len)--; } if (*src[0] == '(') { start = *buf; (*src)++; count = atoi(*src) - 1; lwsl_err("count %d\n", count); while (**src && **src != ')') (*src)++; if (!(*src)[0]) { lwsl_err("unexpected end in (\n"); return -1; } (*src)++; while (**src == ' ') (*src)++; if (**src != '{') { lwsl_err("missing {\n"); return -1; } (*src)++; if (fuzxy_tok(src, buf, len)) return -1; rlen = *buf - start; while (count--) { if (*len < rlen) { lwsl_err("out of space\n"); return -1; } memcpy(*buf, start, rlen); *buf += rlen; *len -= rlen; } } } return 0; } static int fuzxy_create_pattern(const char *src, unsigned char *buf, int len) { unsigned char *old = buf; int n; while (*src && (*src == '{' || *src == ' ')) src++; if (!*src) return -1; n = fuzxy_tok(&src, &buf, &len); if (n) return -1; return buf - old; } void sighandler(int sig) { force_exit = 1; } static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, { "libev", no_argument, NULL, 'e' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, { NULL, 0, 0, 0 } }; static struct pollfd pfd[128]; static struct state state[128]; static int pfds = 0; static void close_and_remove_fd(int index) { int n; lwsl_notice("%s: closing index %d\n", __func__, index); close(pfd[index].fd); pfd[index].fd = -1; n = state[index].twin; if (n) { assert(state[n].twin == index); } state[index].type = FZY_S_DEAD; if (index == pfds - 1) { if (state[index].twin) state[state[index].twin].twin = 0; state[index].twin = 0; goto bail; } /* swap the end guy into the deleted guy and trim back one */ if (state[pfds - 1].twin) { state[state[pfds - 1].twin].twin = index; if (n && n == pfds - 1) n = index; } /* swap the last guy into dead guy's place and trim by one */ pfd[index] = pfd[pfds - 1]; state[index] = state[pfds - 1]; if (n) { pfds--; state[n].twin = 0; close_and_remove_fd(n); return; } bail: pfds--; } static void construct_state(int n, enum types s, int flags) { memset(&state[n], 0, sizeof state[n]); state[n].type = s; pfd[n].events = flags | POLLHUP; } static int fuzxy_listen(const char *interface_name, int port, int *sockfd) { struct sockaddr_in serv_addr4; socklen_t len = sizeof(struct sockaddr); struct sockaddr_in sin; int n, opt = 1; *sockfd = socket(AF_INET, SOCK_STREAM, 0); if (*sockfd == -1) { lwsl_err("ERROR opening socket\n"); goto bail1; } if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) < 0) { lwsl_err("unable to set listen socket options\n"); goto bail2; } bzero((char *) &serv_addr4, sizeof(serv_addr4)); serv_addr4.sin_addr.s_addr = INADDR_ANY; serv_addr4.sin_family = AF_INET; if (interface_name[0] && lws_interface_to_sa(0, interface_name, (struct sockaddr_in *) (struct sockaddr *)&serv_addr4, sizeof(serv_addr4)) < 0) { lwsl_err("Unable to find interface %s\n", interface_name); goto bail2; } serv_addr4.sin_port = htons(port); n = bind(*sockfd, (struct sockaddr *)&serv_addr4, sizeof(serv_addr4)); if (n < 0) { lwsl_err("ERROR on binding to port %d (%d %d)\n", port, n, errno); goto bail2; } if (getsockname(*sockfd, (struct sockaddr *)&sin, &len) == -1) lwsl_warn("getsockname: %s\n", strerror(errno)); else port = ntohs(sin.sin_port); listen(*sockfd, SOMAXCONN); return 0; bail2: close(*sockfd); bail1: return -1; } static int fuzz(int n, char *out, int len) { struct state *s = &state[n]; const struct test *t = &tests[which]; int m = 0; int c; while (m < len) { switch (s->fp) { case FZY_FP_SEARCH: if (t->s[0] == NULL) { s->fuzc = 0; s->is_pending = 0; s->fp = FZY_FP_SEARCH2; goto search2; } c = ring_get_one(&state[s->twin].in); if (c < 0) return m; if (c == tests[which].s[0][s->fuzc++]) { if (s->fuzc == t->len[0]) { s->fuzc = 0; s->fp = FZY_FP_SEARCH2; } } else s->fuzc = 0; out[m++] = c; break; case FZY_FP_SEARCH2: search2: if (tests[which].s[1] == NULL) { s->fuzc = 0; s->is_pending = 0; s->fp = FZY_FP_INJECT_PREPARE; goto inject; } c = ring_get_one(&state[s->twin].in); if (c < 0) return m; if (c == tests[which].s[1][s->fuzc++]) { if (s->fuzc == tests[which].len[1]) { lwsl_notice("+++++++fuzzer hit...\n"); s->fuzc = 0; s->fp = FZY_FP_INJECT_PREPARE; s->is_pending = !t->swallow; s->pending = c; goto inject; } } else s->fuzc = 0; if (!t->swallow) out[m++] = c; break; case FZY_FP_INJECT_PREPARE: inject: s->inject_len = fuzxy_create_pattern(t->s[2], s->buf, sizeof(s->buf)); if (s->inject_len == (unsigned int) -1) return -1; s->fp = FZY_FP_INJECT; /* fallthru */ case FZY_FP_INJECT: out[m++] = s->buf[s->fuzc++]; if (s->fuzc == s->inject_len) s->fp = FZY_FP_PENDING; break; case FZY_FP_PENDING: if (s->is_pending) out[m++] = s->pending; s->fp = FZY_FP_SEARCH; s->fuzc = 0; break; } } return m; } static int handle_accept(int n) { struct addrinfo ai, *res, *result; struct sockaddr_in serv_addr4; struct state *s = &state[n]; void *p = NULL; int m, sockfd; while (1) { m = ring_get_one(&s->in); if (m < 0) return 0; switch (s->pp) { case FZY_PP_CONNECT: if (m != "CONNECT "[s->ppc++]) { lwsl_notice("failed CONNECT match\n"); return 1; } if (s->ppc == 8) { s->pp = FZY_PP_ADDRESS; s->ppc = 0; } break; case FZY_PP_ADDRESS: if (m == ':') { s->address[s->ppc++] = '\0'; s->pp = FZY_PP_PORT; s->ppc = 0; break; } if (m == ' ') { s->address[s->ppc++] = '\0'; s->pp = FZY_PP_CRLFS; s->ppc = 0; break; } s->address[s->ppc++] = m; if (s->ppc == sizeof(s->address)) { lwsl_notice("Failed on address length\n"); return 1; } break; case FZY_PP_PORT: if (m == ' ') { s->pp = FZY_PP_CRLFS; s->ppc = 0; break; } if (m >= '0' && m <= '9') { s->port *= 10; s->port += m - '0'; break; } return 1; case FZY_PP_CRLFS: if (m != "\x0d\x0a\x0d\x0a"[s->ppc++]) s->ppc = 0; if (s->ppc != 4) break; s->type = FZY_S_PROXIED; memset (&ai, 0, sizeof ai); ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; ai.ai_flags = AI_CANONNAME; if (getaddrinfo(s->address, NULL, &ai, &result)) { lwsl_notice("failed to lookup %s\n", s->address); return 1; } res = result; while (!p && res) { switch (res->ai_family) { case AF_INET: p = &((struct sockaddr_in *)res-> ai_addr)->sin_addr; break; } res = res->ai_next; } if (!p) { lwsl_notice("Failed to get address result %s\n", s->address); freeaddrinfo(result); return 1; } serv_addr4.sin_family = AF_INET; serv_addr4.sin_addr = *((struct in_addr *)p); serv_addr4.sin_port = htons(s->port); bzero(&serv_addr4.sin_zero, 8); freeaddrinfo(result); lwsl_err("Conn %d req '%s' port %d\n", n, s->address, s->port); /* we need to open the associated onward connection */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { lwsl_err("Could not get socket\n"); return -1; } if (connect(sockfd, (struct sockaddr *)&serv_addr4, sizeof(struct sockaddr)) == -1 || errno == EISCONN) { close(sockfd); lwsl_err("proxied onward connection failed\n"); return 1; } s->twin = pfds; construct_state(pfds, FZY_S_ONWARD, POLLOUT | POLLIN | POLLERR); state[pfds].twin = n; lwsl_notice("binding conns %d and %d\n", n, pfds); state[pfds].outbound = s->outbound; state[pfds].ppc = 0; pfd[pfds++].fd = sockfd; lwsl_notice("onward connection in progress\n"); if (ring_used(&s->in)) pfd[s->twin].events |= POLLOUT; if (write(pfd[n].fd, "HTTP/1.0 200 \x0d\x0a\x0d\x0a", 17) < 17) return 1; } } return 0; } static void sigpipe_handler(int x) { } int main(int argc, char **argv) { char interface_name[128] = "", interface_name_local[128] = "lo"; int port_local = 8880, accept_fd; struct sockaddr_in cli_addr; int debug_level = 7; socklen_t clilen; struct state *s; char out[4096]; int opts = 0; int n = 0, m; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif signal(SIGPIPE, sigpipe_handler); while (n >= 0) { n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL); if (n < 0) continue; switch (n) { case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif case 'd': debug_level = atoi(optarg); break; case 'p': port_local = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; break; case 'h': fprintf(stderr, "Usage: libwebsockets-test-fuzxy " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 1; } #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("fuzxy", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets fuzzing proxy - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2016 Andy Green <andy@warmcat.com>\n"); /* listen on local side */ if (fuzxy_listen(interface_name, port_local, &pfd[pfds].fd)) { lwsl_err("Failed to listen on local side\n"); goto bail1; } construct_state(pfds, FZY_S_LISTENING, POLLIN | POLLERR); pfds++; lwsl_notice("Local side listening on %s:%u\n", interface_name_local, port_local); while (!force_exit) { m = poll(pfd, pfds, 50); if (m < 0) continue; for (n = 0; n < pfds; n++) { s = &state[n]; if (s->type == FZY_S_LISTENING && (pfd[n].revents & POLLIN)) { /* first do the accept entry */ clilen = sizeof(cli_addr); accept_fd = accept(pfd[0].fd, (struct sockaddr *)&cli_addr, &clilen); if (accept_fd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; lwsl_warn("ERROR on accept: %s\n", strerror(errno)); continue; } construct_state(pfds, FZY_S_ACCEPTED, POLLIN | POLLERR); state[pfds].outbound = n == 0; state[pfds].pp = FZY_PP_CONNECT; state[pfds].ppc = 0; pfd[pfds++].fd = accept_fd; lwsl_notice("new connect accepted\n"); continue; } if (pfd[n].revents & POLLIN) { assert(ring_free(&s->in)); m = (ring_size(&s->in) - 1) - s->in.head; if (s->in.head == ring_size(&s->in) - 1 && s->in.tail) m = 1; m = read(pfd[n].fd, s->in.buf + s->in.head, m); // lwsl_notice("read %d\n", m); if (m <= 0) { lwsl_err("Error on read\n"); goto drop; } s->in.head += m; if (s->in.head == ring_size(&s->in)) s->in.head = 0; switch (s->type) { case FZY_S_ACCEPTED: /* parse proxy CONNECT */ if (handle_accept(n)) goto drop; break; case FZY_S_PROXIED: case FZY_S_ONWARD: if (ring_used(&s->in)) pfd[s->twin].events |= POLLOUT; break; default: assert(0); break; } if (s->in.head == s->in.tail) { s->in.head = s->in.tail = 0; pfd[n].events |= POLLIN; } if (!ring_free(&s->in)) pfd[n].events &= ~POLLIN; } if (pfd[n].revents & POLLOUT) { switch (s->type) { case FZY_S_PROXIED: case FZY_S_ONWARD: /* * draw down enough of the partner's * in ring to either exhaust it * or fill an output buffer */ m = fuzz(n, out, sizeof(out)); if (m < 0) { lwsl_err("Error on fuzz\n"); goto drop; } lwsl_notice("got block %d\n", m); if (m) { m = write(pfd[n].fd, out, m); if (m <= 0) { lwsl_err("Error on write\n"); goto drop; } else pfd[s->twin].events &= ~POLLIN; } else { pfd[n].events &= ~POLLOUT; if (ring_free(&state[s->twin].in)) pfd[s->twin].events |= POLLIN; } break; default: break; } } continue; drop: close_and_remove_fd(n); n--; /* redo this slot */ } } bail1: lwsl_notice("%s exited cleanly\n", argv[0]); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/test-server/leaf.jpg.
cannot compute difference between binary files
Added undroid/libwebsockets/test-server/libwebsockets-test-server.service.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | [Unit] Description=Libwebsockets test server After=syslog.target [Service] ExecStart=/usr/local/bin/libwebsockets-test-server --ssl -C /etc/pki/tls/certs/libwebsockets.org.crt -K /etc/pki/tls/private/libwebsockets.org.key -A /etc/pki/tls/certs/libwebsockets.org.cer --port 7681 -u 99 -g 99 --daemonize Type=forking PIDFile=/tmp/.lwsts-lock [Install] WantedBy=multi-user.target |
Added undroid/libwebsockets/test-server/libwebsockets.org-logo.png.
cannot compute difference between binary files
Added undroid/libwebsockets/test-server/lws-cgi-test.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/sh echo -e -n "Content-type: text/html\x0d\x0a" echo -e -n "\x0d\x0a" echo "<html><body>" echo "<h1>lwstest script stdout</h1>" >&2 echo "lwstest script stderr: $REQUEST_METHOD" echo "<h2>REQUEST_METHOD=$REQUEST_METHOD</h2>" if [ "$REQUEST_METHOD" = "POST" ] ; then >&2 echo "lwstest script stderr: doing read" echo "CONTENT_LENGTH=$CONTENT_LENGTH" read -n $CONTENT_LENGTH line >&2 echo "lwstest script stderr: done read" echo "read=\"$line\"" else echo "<table>" echo "<tr><td colspan=\"2\" style=\"font-size:120%;text-align:center\">/proc/meminfo</td></tr>" cat /proc/meminfo | while read line ; do A=`echo "$line" | cut -d: -f1` B=`echo "$line" | tr -s ' ' | cut -d' ' -f2-` echo -e "<tr><td style=\"background-color:#f0e8c0\">$A</td>" echo -e "<td style=\"text-align:right\">$B</td></tr>" done echo "</table>" fi echo "<br/>done" echo "</body></html>" exit 0 |
Added undroid/libwebsockets/test-server/test-client.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-client - libwebsockets test implementation * * Copyright (C) 2011-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "lws_config.h" #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <string.h> #include <signal.h> #ifdef _WIN32 #define random rand #include "gettimeofday.h" #else #include <syslog.h> #include <sys/time.h> #include <unistd.h> #endif #include "../lib/libwebsockets.h" static int deny_deflate, deny_mux, longlived, mirror_lifetime; static struct lws *wsi_dumb, *wsi_mirror; static volatile int force_exit; static unsigned int opts; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) char crl_path[1024] = ""; #endif #endif #endif /* * This demo shows how to connect multiple websockets simultaneously to a * websocket server (there is no restriction on their having to be the same * server just it simplifies the demo). * * dumb-increment-protocol: we connect to the server and print the number * we are given * * lws-mirror-protocol: draws random circles, which are mirrored on to every * client (see them being drawn in every browser * session also using the test server) */ enum demo_protocols { PROTOCOL_DUMB_INCREMENT, PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; /* * dumb_increment protocol * * since this also happens to be protocols[0], some callbacks that are not * bound to a specific protocol also turn up here. */ static int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { switch (reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: lwsl_info("dumb: LWS_CALLBACK_CLIENT_ESTABLISHED\n"); break; case LWS_CALLBACK_CLOSED: lwsl_notice("dumb: LWS_CALLBACK_CLOSED\n"); wsi_dumb = NULL; break; case LWS_CALLBACK_CLIENT_RECEIVE: ((char *)in)[len] = '\0'; lwsl_info("rx %d '%s'\n", (int)len, (char *)in); break; /* because we are protocols[0] ... */ case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: if (wsi == wsi_dumb) { lwsl_err("dumb: LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n"); wsi_dumb = NULL; } if (wsi == wsi_mirror) { lwsl_err("mirror: LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n"); wsi_mirror = NULL; } break; case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: if ((strcmp(in, "deflate-stream") == 0) && deny_deflate) { lwsl_notice("denied deflate-stream extension\n"); return 1; } if ((strcmp(in, "x-webkit-deflate-frame") == 0)) return 1; if ((strcmp(in, "deflate-frame") == 0)) return 1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: { char buffer[1024 + LWS_PRE]; char *px = buffer + LWS_PRE; int lenx = sizeof(buffer) - LWS_PRE; lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n"); /* * Often you need to flow control this by something * else being writable. In that case call the api * to get a callback when writable here, and do the * pending client read in the writeable callback of * the output. */ if (lws_http_client_read(wsi, &px, &lenx) < 0) return -1; while (lenx--) putchar(*px++); } break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: wsi_dumb = NULL; force_exit = 1; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if (crl_path[0]) { /* Enable CRL checking of the server certificate */ X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); SSL_CTX_set1_param((SSL_CTX*)user, param); X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); int n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); X509_VERIFY_PARAM_free(param); if (n != 1) { char errbuf[256]; n = ERR_get_error(); lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); return 1; } } break; #endif #endif #endif default: break; } return 0; } /* lws-mirror_protocol */ static int callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { unsigned char buf[LWS_PRE + 4096]; unsigned int rands[4]; int l = 0; int n; switch (reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: lwsl_notice("mirror: LWS_CALLBACK_CLIENT_ESTABLISHED\n"); lws_get_random(lws_get_context(wsi), rands, sizeof(rands[0])); mirror_lifetime = 16384 + (rands[0] & 65535); /* useful to test single connection stability */ if (longlived) mirror_lifetime += 500000; lwsl_info("opened mirror connection with " "%d lifetime\n", mirror_lifetime); /* * mirror_lifetime is decremented each send, when it reaches * zero the connection is closed in the send callback. * When the close callback comes, wsi_mirror is set to NULL * so a new connection will be opened * * start the ball rolling, * LWS_CALLBACK_CLIENT_WRITEABLE will come next service */ lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLOSED: lwsl_notice("mirror: LWS_CALLBACK_CLOSED mirror_lifetime=%d\n", mirror_lifetime); wsi_mirror = NULL; break; case LWS_CALLBACK_CLIENT_WRITEABLE: for (n = 0; n < 1; n++) { lws_get_random(lws_get_context(wsi), rands, sizeof(rands)); l += sprintf((char *)&buf[LWS_PRE + l], "c #%06X %u %u %u;", rands[0] & 0xffffff, /* colour */ rands[1] & 511, /* x */ rands[2] & 255, /* y */ (rands[3] & 31) + 1); /* radius */ } n = lws_write(wsi, &buf[LWS_PRE], l, opts | LWS_WRITE_TEXT); if (n < 0) return -1; if (n < l) { lwsl_err("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n"); return -1; } mirror_lifetime--; if (!mirror_lifetime) { lwsl_info("closing mirror session\n"); return -1; } /* get notified as soon as we can write again */ lws_callback_on_writable(wsi); break; default: break; } return 0; } /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { { "dumb-increment-protocol,fake-nonexistant-protocol", callback_dumb_increment, 0, 20, }, { "fake-nonexistant-protocol,lws-mirror-protocol", callback_lws_mirror, 0, 128, }, { NULL, NULL, 0, 0 } /* end */ }; static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; void sighandler(int sig) { force_exit = 1; } static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "version", required_argument, NULL, 'v' }, { "undeflated", no_argument, NULL, 'u' }, { "nomux", no_argument, NULL, 'n' }, { "longlived", no_argument, NULL, 'l' }, { "ssl-cert", required_argument, NULL, 'C' }, { "ssl-key", required_argument, NULL, 'K' }, { "ssl-ca", required_argument, NULL, 'A' }, #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) { "ssl-crl", required_argument, NULL, 'R' }, #endif { NULL, 0, 0, 0 } }; static int ratelimit_connects(unsigned int *last, unsigned int secs) { struct timeval tv; gettimeofday(&tv, NULL); if (tv.tv_sec - (*last) < secs) return 0; *last = tv.tv_sec; return 1; } int main(int argc, char **argv) { int n = 0, ret = 0, port = 7681, use_ssl = 0, ietf_version = -1; unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1; struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; const char *prot, *p; char path[300]; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; memset(&info, 0, sizeof info); lwsl_notice("libwebsockets test client - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); if (argc < 2) goto usage; while (n >= 0) { n = getopt_long(argc, argv, "nuv:hsp:d:lC:K:A:", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 's': use_ssl = 2; /* 2 = allow selfsigned */ break; case 'p': port = atoi(optarg); break; case 'l': longlived = 1; break; case 'v': ietf_version = atoi(optarg); break; case 'u': deny_deflate = 1; break; case 'n': deny_mux = 1; break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif #endif case 'h': goto usage; } } if (optind >= argc) goto usage; signal(SIGINT, sighandler); memset(&i, 0, sizeof(i)); i.port = port; if (lws_parse_uri(argv[optind], &prot, &i.address, &i.port, &p)) goto usage; /* add back the leading / on path */ path[0] = '/'; strncpy(path + 1, p, sizeof(path) - 2); path[sizeof(path) - 1] = '\0'; i.path = path; if (!strcmp(prot, "http") || !strcmp(prot, "ws")) use_ssl = 0; if (!strcmp(prot, "https") || !strcmp(prot, "wss")) if (!use_ssl) use_ssl = 1; /* * create the websockets context. This tracks open connections and * knows how to route any traffic and which protocol version to use, * and if each connection is client or server side. * * For this client-only demo, we tell it to not listen on any port. */ info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.gid = -1; info.uid = -1; if (use_ssl) { info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; /* * If the server wants us to present a valid SSL client certificate * then we can set it up here. */ if (cert_path[0]) info.ssl_cert_filepath = cert_path; if (key_path[0]) info.ssl_private_key_filepath = key_path; /* * A CA cert and CRL can be used to validate the cert send by the server */ if (ca_path[0]) info.ssl_ca_filepath = ca_path; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) else if (crl_path[0]) lwsl_notice("WARNING, providing a CRL requires a CA cert!\n"); #endif #endif #endif if (use_ssl == 1) lwsl_notice(" Cert must validate correctly (use -s to allow selfsigned)\n"); else lwsl_notice(" Selfsigned certs allowed\n"); } context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); return 1; } i.context = context; i.ssl_connection = use_ssl; i.host = i.address; i.origin = i.address; i.ietf_version_or_minus_one = ietf_version; i.client_exts = exts; if (!strcmp(prot, "http") || !strcmp(prot, "https")) { lwsl_notice("using %s mode (non-ws)\n", prot); i.method = "GET"; do_ws = 0; } else lwsl_notice("using %s mode (ws)\n", prot); /* * sit there servicing the websocket context to handle incoming * packets, and drawing random circles on the mirror protocol websocket * * nothing happens until the client websocket connection is * asynchronously established... calling lws_client_connect() only * instantiates the connection logically, lws_service() progresses it * asynchronously. */ while (!force_exit) { if (do_ws) { if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("dumb: connecting\n"); i.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; wsi_dumb = lws_client_connect_via_info(&i); } if (!wsi_mirror && ratelimit_connects(&rl_mirror, 2u)) { lwsl_notice("mirror: connecting\n"); i.protocol = protocols[PROTOCOL_LWS_MIRROR].name; wsi_mirror = lws_client_connect_via_info(&i); } } else if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("http: connecting\n"); wsi_dumb = lws_client_connect_via_info(&i); } lws_service(context, 500); } lwsl_err("Exiting\n"); lws_context_destroy(context); return ret; usage: fprintf(stderr, "Usage: libwebsockets-test-client " "<server address> [--port=<p>] " "[--ssl] [-k] [-v <ver>] " "[-d <log bitfield>] [-l]\n"); return 1; } |
Added undroid/libwebsockets/test-server/test-echo.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-echo * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <string.h> #include <assert.h> #include <signal.h> #include "../lib/libwebsockets.h" #ifndef _WIN32 #include <syslog.h> #include <sys/time.h> #include <unistd.h> #else #include "gettimeofday.h" #include <process.h> #endif static volatile int force_exit = 0; static int versa, state; static int times = -1; #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" #define MAX_ECHO_PAYLOAD 1024 struct per_session_data__echo { size_t rx, tx; unsigned char buf[LWS_PRE + MAX_ECHO_PAYLOAD]; unsigned int len; unsigned int index; int final; int continuation; int binary; }; static int callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__echo *pss = (struct per_session_data__echo *)user; int n; switch (reason) { #ifndef LWS_NO_SERVER case LWS_CALLBACK_SERVER_WRITEABLE: do_tx: n = LWS_WRITE_CONTINUATION; if (!pss->continuation) { if (pss->binary) n = LWS_WRITE_BINARY; else n = LWS_WRITE_TEXT; pss->continuation = 1; } if (!pss->final) n |= LWS_WRITE_NO_FIN; lwsl_info("+++ test-echo: writing %d, with final %d\n", pss->len, pss->final); pss->tx += pss->len; n = lws_write(wsi, &pss->buf[LWS_PRE], pss->len, n); if (n < 0) { lwsl_err("ERROR %d writing to socket, hanging up\n", n); return 1; } if (n < (int)pss->len) { lwsl_err("Partial write\n"); return -1; } pss->len = -1; if (pss->final) pss->continuation = 0; lws_rx_flow_control(wsi, 1); break; case LWS_CALLBACK_RECEIVE: do_rx: pss->final = lws_is_final_fragment(wsi); pss->binary = lws_frame_is_binary(wsi); lwsl_info("+++ test-echo: RX len %d final %d, pss->len=%d\n", len, pss->final, (int)pss->len); memcpy(&pss->buf[LWS_PRE], in, len); assert((int)pss->len == -1); pss->len = (unsigned int)len; pss->rx += len; lws_rx_flow_control(wsi, 0); lws_callback_on_writable(wsi); break; #endif #ifndef LWS_NO_CLIENT /* when the callback is used for client operations --> */ case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: lwsl_debug("closed\n"); state = 0; break; case LWS_CALLBACK_CLIENT_ESTABLISHED: lwsl_debug("Client has connected\n"); pss->index = 0; pss->len = -1; state = 2; break; case LWS_CALLBACK_CLIENT_RECEIVE: #ifndef LWS_NO_SERVER if (versa) goto do_rx; #endif lwsl_notice("Client RX: %s", (char *)in); break; case LWS_CALLBACK_CLIENT_WRITEABLE: #ifndef LWS_NO_SERVER if (versa) { if (pss->len != (unsigned int)-1) goto do_tx; break; } #endif /* we will send our packet... */ pss->len = sprintf((char *)&pss->buf[LWS_PRE], "hello from libwebsockets-test-echo client pid %d index %d\n", getpid(), pss->index++); lwsl_notice("Client TX: %s", &pss->buf[LWS_PRE]); n = lws_write(wsi, &pss->buf[LWS_PRE], pss->len, LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to socket, hanging up\n", n); return -1; } if (n < (int)pss->len) { lwsl_err("Partial write\n"); return -1; } break; #endif case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: /* reject everything else except permessage-deflate */ if (strcmp(in, "permessage-deflate")) return 1; break; default: break; } return 0; } static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "", /* name - can be overriden with -e */ callback_echo, sizeof(struct per_session_data__echo), /* per_session_data_size */ MAX_ECHO_PAYLOAD, }, { NULL, NULL, 0 /* End of list */ } }; static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_no_context_takeover; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; void sighandler(int sig) { force_exit = 1; } static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl-cert", required_argument, NULL, 'C' }, { "ssl-key", required_argument, NULL, 'k' }, #ifndef LWS_NO_CLIENT { "client", required_argument, NULL, 'c' }, { "ratems", required_argument, NULL, 'r' }, #endif { "ssl", no_argument, NULL, 's' }, { "versa", no_argument, NULL, 'v' }, { "uri", required_argument, NULL, 'u' }, { "passphrase", required_argument, NULL, 'P' }, { "interface", required_argument, NULL, 'i' }, { "times", required_argument, NULL, 'n' }, { "echogen", no_argument, NULL, 'e' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { NULL, 0, 0, 0 } }; int main(int argc, char **argv) { int n = 0; int port = 7681; int use_ssl = 0; struct lws_context *context; int opts = 0; char interface_name[128] = ""; const char *_interface = NULL; char ssl_cert[256] = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem"; char ssl_key[256] = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem"; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif int client = 0; int listen_port = 80; struct lws_context_creation_info info; char passphrase[256]; char uri[256] = "/"; #ifndef LWS_NO_CLIENT char address[256], ads_port[256 + 30]; int rate_us = 250000; unsigned long long oldus; struct lws *wsi; int disallow_selfsigned = 0; struct timeval tv; const char *connect_protocol = NULL; struct lws_client_connect_info i; #endif int debug_level = 7; #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif memset(&info, 0, sizeof info); #ifndef LWS_NO_CLIENT lwsl_notice("Built to support client operations\n"); #endif #ifndef LWS_NO_SERVER lwsl_notice("Built to support server operations\n"); #endif while (n >= 0) { n = getopt_long(argc, argv, "i:hsp:d:DC:k:P:vu:n:e" #ifndef LWS_NO_CLIENT "c:r:" #endif , options, NULL); if (n < 0) continue; switch (n) { case 'P': strncpy(passphrase, optarg, sizeof(passphrase)); passphrase[sizeof(passphrase) - 1] = '\0'; info.ssl_private_key_password = passphrase; break; case 'C': strncpy(ssl_cert, optarg, sizeof(ssl_cert)); ssl_cert[sizeof(ssl_cert) - 1] = '\0'; disallow_selfsigned = 1; break; case 'k': strncpy(ssl_key, optarg, sizeof(ssl_key)); ssl_key[sizeof(ssl_key) - 1] = '\0'; break; case 'u': strncpy(uri, optarg, sizeof(uri)); uri[sizeof(uri) - 1] = '\0'; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif #ifndef LWS_NO_CLIENT case 'c': client = 1; strncpy(address, optarg, sizeof(address) - 1); address[sizeof(address) - 1] = '\0'; port = 80; break; case 'r': rate_us = atoi(optarg) * 1000; break; #endif case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; /* 1 = take care about cert verification, 2 = allow anything */ break; case 'p': port = atoi(optarg); break; case 'v': versa = 1; break; case 'e': protocols[0].name = "lws-echogen"; connect_protocol = protocols[0].name; lwsl_err("using lws-echogen\n"); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; _interface = interface_name; break; case 'n': times = atoi(optarg); break; case '?': case 'h': fprintf(stderr, "Usage: libwebsockets-test-echo\n" " --debug / -d <debug bitfield>\n" " --port / -p <port>\n" " --ssl-cert / -C <cert path>\n" " --ssl-key / -k <key path>\n" #ifndef LWS_NO_CLIENT " --client / -c <server IP>\n" " --ratems / -r <rate in ms>\n" #endif " --ssl / -s\n" " --passphrase / -P <passphrase>\n" " --interface / -i <interface>\n" " --uri / -u <uri path>\n" " --times / -n <-1 unlimited or times to echo>\n" #ifndef LWS_NO_DAEMONIZE " --daemonize / -D\n" #endif ); exit(1); } } #ifndef LWS_NO_DAEMONIZE /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ #if defined(WIN32) || defined(_WIN32) #else if (!client && daemonize && lws_daemonize("/tmp/.lwstecho-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 1; } #endif #endif #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server echo - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); #ifndef LWS_NO_CLIENT if (client) { lwsl_notice("Running in client mode\n"); listen_port = CONTEXT_PORT_NO_LISTEN; if (use_ssl && !disallow_selfsigned) { lwsl_info("allowing selfsigned\n"); use_ssl = 2; } else { lwsl_info("requiring server cert validation against %s\n", ssl_cert); info.ssl_ca_filepath = ssl_cert; } } else { #endif #ifndef LWS_NO_SERVER lwsl_notice("Running in server mode\n"); listen_port = port; #endif #ifndef LWS_NO_CLIENT } #endif info.port = listen_port; info.iface = _interface; info.protocols = protocols; if (use_ssl && !client) { info.ssl_cert_filepath = ssl_cert; info.ssl_private_key_filepath = ssl_key; } else if (use_ssl && client) { info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; } info.gid = -1; info.uid = -1; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8; if (use_ssl) info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; #ifndef LWS_NO_EXTENSIONS info.extensions = exts; #endif context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } signal(SIGINT, sighandler); #ifndef LWS_NO_CLIENT gettimeofday(&tv, NULL); oldus = ((unsigned long long)tv.tv_sec * 1000000) + tv.tv_usec; #endif n = 0; while (n >= 0 && !force_exit) { #ifndef LWS_NO_CLIENT if (client && !state && times) { state = 1; lwsl_notice("Client connecting to %s:%u....\n", address, port); /* we are in client mode */ address[sizeof(address) - 1] = '\0'; sprintf(ads_port, "%s:%u", address, port & 65535); if (times > 0) times--; memset(&i, 0, sizeof(i)); i.context = context; i.address = address; i.port = port; i.ssl_connection = use_ssl; i.path = uri; i.host = ads_port; i.origin = ads_port; i.protocol = connect_protocol; i.client_exts = exts; wsi = lws_client_connect_via_info(&i); if (!wsi) { lwsl_err("Client failed to connect to %s:%u\n", address, port); goto bail; } } if (client && !versa && times) { gettimeofday(&tv, NULL); if (((((unsigned long long)tv.tv_sec * 1000000) + tv.tv_usec) - oldus) > rate_us) { lws_callback_on_writable_all_protocol(context, &protocols[0]); oldus = ((unsigned long long)tv.tv_sec * 1000000) + tv.tv_usec; if (times > 0) times--; } } if (client && !state && !times) break; #endif n = lws_service(context, 10); } #ifndef LWS_NO_CLIENT bail: #endif lws_context_destroy(context); lwsl_notice("libwebsockets-test-echo exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/test-server/test-fraggle.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-fraggle - random fragmentation test * * Copyright (C) 2011-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <string.h> #include "../lib/libwebsockets.h" #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" static int client; static int terminate; enum demo_protocols { PROTOCOL_FRAGGLE, /* always last */ DEMO_PROTOCOL_COUNT }; /* fraggle protocol */ enum fraggle_states { FRAGSTATE_START_MESSAGE, FRAGSTATE_RANDOM_PAYLOAD, FRAGSTATE_POST_PAYLOAD_SUM, }; struct per_session_data__fraggle { int packets_left; int total_message; unsigned long sum; enum fraggle_states state; }; static int callback_fraggle(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { int n; unsigned char buf[LWS_PRE + 8000]; struct per_session_data__fraggle *psf = user; int chunk; int write_mode = LWS_WRITE_CONTINUATION; unsigned long sum; unsigned char *p = (unsigned char *)in; unsigned char *bp = &buf[LWS_PRE]; int ran; switch (reason) { case LWS_CALLBACK_ESTABLISHED: fprintf(stderr, "server sees client connect\n"); psf->state = FRAGSTATE_START_MESSAGE; /* start the ball rolling */ lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: fprintf(stderr, "client connects to server\n"); psf->state = FRAGSTATE_START_MESSAGE; break; case LWS_CALLBACK_CLIENT_RECEIVE: switch (psf->state) { case FRAGSTATE_START_MESSAGE: psf->state = FRAGSTATE_RANDOM_PAYLOAD; psf->sum = 0; psf->total_message = 0; psf->packets_left = 0; /* fallthru */ case FRAGSTATE_RANDOM_PAYLOAD: for (n = 0; (unsigned int)n < len; n++) psf->sum += p[n]; psf->total_message += len; psf->packets_left++; if (lws_is_final_fragment(wsi)) psf->state = FRAGSTATE_POST_PAYLOAD_SUM; break; case FRAGSTATE_POST_PAYLOAD_SUM: sum = ((unsigned int)p[0]) << 24; sum |= p[1] << 16; sum |= p[2] << 8; sum |= p[3]; if (sum == psf->sum) fprintf(stderr, "EOM received %d correctly " "from %d fragments\n", psf->total_message, psf->packets_left); else fprintf(stderr, "**** ERROR at EOM: " "length %d, rx sum = 0x%lX, " "server says it sent 0x%lX\n", psf->total_message, psf->sum, sum); psf->state = FRAGSTATE_START_MESSAGE; break; } break; case LWS_CALLBACK_SERVER_WRITEABLE: switch (psf->state) { case FRAGSTATE_START_MESSAGE: lws_get_random(lws_get_context(wsi), &ran, sizeof(ran)); psf->packets_left = (ran & 1023) + 1; fprintf(stderr, "Spamming %d random fragments\n", psf->packets_left); psf->sum = 0; psf->total_message = 0; write_mode = LWS_WRITE_BINARY; psf->state = FRAGSTATE_RANDOM_PAYLOAD; /* fallthru */ case FRAGSTATE_RANDOM_PAYLOAD: /* * note how one chunk can be 8000, but we use the * default rx buffer size of 4096, so we exercise the * code for rx spill because the rx buffer is full */ lws_get_random(lws_get_context(wsi), &ran, sizeof(ran)); chunk = (ran & 511) + 1; psf->total_message += chunk; lws_get_random(lws_get_context(wsi), bp, chunk); for (n = 0; n < chunk; n++) psf->sum += bp[n]; psf->packets_left--; if (psf->packets_left) write_mode |= LWS_WRITE_NO_FIN; else psf->state = FRAGSTATE_POST_PAYLOAD_SUM; n = lws_write(wsi, bp, chunk, write_mode); if (n < 0) return -1; if (n < chunk) { lwsl_err("Partial write\n"); return -1; } lws_callback_on_writable(wsi); break; case FRAGSTATE_POST_PAYLOAD_SUM: fprintf(stderr, "Spamming session over, " "len = %d. sum = 0x%lX\n", psf->total_message, psf->sum); bp[0] = psf->sum >> 24; bp[1] = (unsigned char)(psf->sum >> 16); bp[2] = (unsigned char)(psf->sum >> 8); bp[3] = (unsigned char)psf->sum; n = lws_write(wsi, (unsigned char *)bp, 4, LWS_WRITE_BINARY); if (n < 0) return -1; if (n < 4) { lwsl_err("Partial write\n"); return -1; } psf->state = FRAGSTATE_START_MESSAGE; lws_callback_on_writable(wsi); break; } break; case LWS_CALLBACK_CLOSED: terminate = 1; break; /* because we are protocols[0] ... */ case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: if (strcmp(in, "deflate-stream") == 0) { fprintf(stderr, "denied deflate-stream extension\n"); return 1; } break; default: break; } return 0; } /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { { "fraggle-protocol", callback_fraggle, sizeof(struct per_session_data__fraggle), }, { NULL, NULL, 0 /* End of list */ } }; static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_no_context_takeover; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "interface", required_argument, NULL, 'i' }, { "client", no_argument, NULL, 'c' }, { NULL, 0, 0, 0 } }; int main(int argc, char **argv) { int n = 0; int port = 7681; int use_ssl = 0; struct lws_context *context; int opts = 0; char interface_name[128] = "", ads_port[300]; const char *iface = NULL; struct lws *wsi; const char *address = NULL; int server_port = port; struct lws_context_creation_info info; memset(&info, 0, sizeof info); lwsl_notice("libwebsockets test server fraggle - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); while (n >= 0) { n = getopt_long(argc, argv, "ci:hsp:d:", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 's': use_ssl = 1; break; case 'p': port = atoi(optarg); server_port = port; break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'c': client = 1; fprintf(stderr, " Client mode\n"); break; case 'h': fprintf(stderr, "Usage: libwebsockets-test-fraggle " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--client]\n"); exit(1); } } if (client) { server_port = CONTEXT_PORT_NO_LISTEN; if (optind >= argc) { fprintf(stderr, "Must give address of server\n"); return 1; } } info.port = server_port; info.iface = iface; info.protocols = protocols; info.extensions = exts; if (use_ssl) { info.ssl_cert_filepath = LOCAL_RESOURCE_PATH "/libwebsockets-test-server.pem"; info.ssl_private_key_filepath = LOCAL_RESOURCE_PATH "/libwebsockets-test-server.key.pem"; } info.gid = -1; info.uid = -1; info.options = opts; if (use_ssl) info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "libwebsocket init failed\n"); return -1; } if (client) { struct lws_client_connect_info i; address = argv[optind]; lws_snprintf(ads_port, sizeof(ads_port), "%s:%u", address, port & 65535); memset(&i, 0, sizeof(i)); i.context = context; i.address = address; i.port = port; i.ssl_connection = use_ssl; i.path = "/"; i.host = ads_port; i.origin = ads_port; i.protocol = protocols[PROTOCOL_FRAGGLE].name; i.client_exts = exts; lwsl_notice("Connecting to %s:%u\n", address, port); wsi = lws_client_connect_via_info(&i); if (wsi == NULL) { fprintf(stderr, "Client connect to server failed\n"); goto bail; } } n = 0; while (!n && !terminate) n = lws_service(context, 50); fprintf(stderr, "Terminating...\n"); bail: lws_context_destroy(context); return 0; } |
Added undroid/libwebsockets/test-server/test-ping.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-ping - libwebsockets test floodping * * Copyright (C) 2011-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include "../lib/libwebsockets.h" #ifndef _WIN32 #include <netdb.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/ioctl.h> #include <poll.h> #include <unistd.h> #else #include "gettimeofday.h" #endif #ifdef __ANDROID__ #include <termiosh> #endif /* * this is specified in the 04 standard, control frames can only have small * payload length styles */ #define MAX_PING_PAYLOAD 125 #define MAX_MIRROR_PAYLOAD 4096 #define MAX_PING_CLIENTS 256 #define PING_RINGBUFFER_SIZE 256 static struct lws *ping_wsi[MAX_PING_CLIENTS]; static unsigned int interval_us = 1000000; static unsigned int size = 64; static int flood; static const char *address; static unsigned char pingbuf[LWS_PRE + MAX_MIRROR_PAYLOAD]; static char peer_name[128]; static unsigned long started; static int screen_width = 80; static int use_mirror; static unsigned int write_options; static unsigned long rtt_min = 100000000; static unsigned long rtt_max; static unsigned long rtt_avg; static unsigned long global_rx_count; static unsigned long global_tx_count; static int clients = 1; static unsigned long interrupted_time; struct ping { unsigned long issue_timestamp; unsigned long index; unsigned int seen; }; struct per_session_data__ping { unsigned long long ping_index; struct ping ringbuffer[PING_RINGBUFFER_SIZE]; int ringbuffer_head; int ringbuffer_tail; unsigned long rx_count; }; /* * uses the ping pong protocol features to provide an equivalent for the * ping utility for 04+ websockets */ enum demo_protocols { PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; static int callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__ping *psd = user; struct timeval tv; unsigned char *p; unsigned long iv; int match = 0; unsigned long long l; int shift; int n; switch (reason) { case LWS_CALLBACK_CLOSED: fprintf(stderr, "LWS_CALLBACK_CLOSED on %p\n", (void *)wsi); /* remove closed guy */ for (n = 0; n < clients; n++) if (ping_wsi[n] == wsi) { clients--; while (n < clients) { ping_wsi[n] = ping_wsi[n + 1]; n++; } } break; case LWS_CALLBACK_CLIENT_ESTABLISHED: psd->rx_count = 0; psd->ping_index = 1; psd->ringbuffer_head = 0; psd->ringbuffer_tail = 0; /* * start the ball rolling, * LWS_CALLBACK_CLIENT_WRITEABLE will come next service */ lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLIENT_RECEIVE: case LWS_CALLBACK_CLIENT_RECEIVE_PONG: gettimeofday(&tv, NULL); iv = (tv.tv_sec * 1000000) + tv.tv_usec; psd->rx_count++; shift = 56; p = in; l = 0; while (shift >= 0) { l |= ((unsigned long long)*p++) << shift; shift -= 8; } /* find it in the ringbuffer, look backwards from head */ n = psd->ringbuffer_head; while (!match) { if (psd->ringbuffer[n].index == l) { psd->ringbuffer[n].seen++; match = 1; continue; } if (n == psd->ringbuffer_tail) { match = -1; continue; } if (n == 0) n = PING_RINGBUFFER_SIZE - 1; else n--; } if (match < 1) { if (!flood) fprintf(stderr, "%d bytes from %s: req=%ld " "time=(unknown)\n", (int)len, address, (long)l); else fprintf(stderr, "\b \b"); break; } if (psd->ringbuffer[n].seen > 1) fprintf(stderr, "DUP! "); if ((iv - psd->ringbuffer[n].issue_timestamp) < rtt_min) rtt_min = iv - psd->ringbuffer[n].issue_timestamp; if ((iv - psd->ringbuffer[n].issue_timestamp) > rtt_max) rtt_max = iv - psd->ringbuffer[n].issue_timestamp; rtt_avg += iv - psd->ringbuffer[n].issue_timestamp; global_rx_count++; if (!flood) fprintf(stderr, "%d bytes from %s: req=%ld " "time=%lu.%lums\n", (int)len, address, (long)l, (iv - psd->ringbuffer[n].issue_timestamp) / 1000, ((iv - psd->ringbuffer[n].issue_timestamp) / 100) % 10); else fprintf(stderr, "\b \b"); break; case LWS_CALLBACK_CLIENT_WRITEABLE: shift = 56; p = &pingbuf[LWS_PRE]; /* 64-bit ping index in network byte order */ while (shift >= 0) { *p++ = (unsigned char)(psd->ping_index >> shift); shift -= 8; } while ((unsigned int)(p - &pingbuf[LWS_PRE]) < size) *p++ = 0; gettimeofday(&tv, NULL); psd->ringbuffer[psd->ringbuffer_head].issue_timestamp = (tv.tv_sec * 1000000) + tv.tv_usec; psd->ringbuffer[psd->ringbuffer_head].index = (unsigned long)psd->ping_index++; psd->ringbuffer[psd->ringbuffer_head].seen = 0; if (psd->ringbuffer_head == PING_RINGBUFFER_SIZE - 1) psd->ringbuffer_head = 0; else psd->ringbuffer_head++; /* snip any re-used tail so we keep to the ring length */ if (psd->ringbuffer_tail == psd->ringbuffer_head) { if (psd->ringbuffer_tail == PING_RINGBUFFER_SIZE - 1) psd->ringbuffer_tail = 0; else psd->ringbuffer_tail++; } global_tx_count++; if (use_mirror) n = lws_write(wsi, &pingbuf[LWS_PRE], size, write_options | LWS_WRITE_BINARY); else n = lws_write(wsi, &pingbuf[LWS_PRE], size, write_options | LWS_WRITE_PING); if (n < 0) return -1; if (n < (int)size) { lwsl_err("Partial write\n"); return -1; } if (flood && (psd->ping_index - psd->rx_count) < (screen_width - 1)) fprintf(stderr, "."); break; default: break; } return 0; } /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { { "lws-mirror-protocol", callback_lws_mirror, sizeof (struct per_session_data__ping), }, { NULL, NULL, 0/* end of list */ } }; static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_no_context_takeover; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 't' }, { "interval", required_argument, NULL, 'i' }, { "size", required_argument, NULL, 's' }, { "protocol", required_argument, NULL, 'n' }, { "flood", no_argument, NULL, 'f' }, { "mirror", no_argument, NULL, 'm' }, { "replicate", required_argument, NULL, 'r' }, { "killmask", no_argument, NULL, 'k' }, { "version", required_argument, NULL, 'v' }, { NULL, 0, 0, 0 } }; #ifndef _WIN32 static void signal_handler(int sig, siginfo_t *si, void *v) { struct timeval tv; gettimeofday(&tv, NULL); interrupted_time = (tv.tv_sec * 1000000) + tv.tv_usec; } #endif int main(int argc, char **argv) { int n = 0; int port = 7681; int use_ssl = 0; struct lws_context *context; char protocol_name[256], ads_port[300]; char ip[30]; #ifndef _WIN32 struct sigaction sa; struct winsize w; #endif struct timeval tv; unsigned long oldus = 0; unsigned long l; int ietf_version = -1; struct lws_context_creation_info info; struct lws_client_connect_info i; memset(&info, 0, sizeof info); if (argc < 2) goto usage; while (n >= 0) { n = getopt_long(argc, argv, "v:kr:hmfts:n:i:p:d:", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 'm': use_mirror = 1; break; case 't': use_ssl = 2; /* 2 = allow selfsigned */ break; case 'p': port = atoi(optarg); break; case 'n': strncpy(protocol_name, optarg, sizeof protocol_name); protocol_name[(sizeof protocol_name) - 1] = '\0'; protocols[PROTOCOL_LWS_MIRROR].name = protocol_name; break; case 'i': interval_us = (unsigned int)(1000000.0 * atof(optarg)); break; case 's': size = atoi(optarg); break; case 'f': flood = 1; break; case 'r': clients = atoi(optarg); if (clients > MAX_PING_CLIENTS || clients < 1) { fprintf(stderr, "Max clients supportd = %d\n", MAX_PING_CLIENTS); return 1; } break; case 'k': write_options = LWS_WRITE_CLIENT_IGNORE_XOR_MASK; break; case 'v': ietf_version = atoi(optarg); break; case 'h': goto usage; } } if (!use_mirror) { if (size > MAX_PING_PAYLOAD) { fprintf(stderr, "Max ping opcode payload size %d\n", MAX_PING_PAYLOAD); return 1; } } else { if (size > MAX_MIRROR_PAYLOAD) { fprintf(stderr, "Max mirror payload size %d\n", MAX_MIRROR_PAYLOAD); return 1; } } #ifndef _WIN32 if (isatty(STDOUT_FILENO)) if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) if (w.ws_col > 0) screen_width = w.ws_col; #endif info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.extensions = exts; info.gid = -1; info.uid = -1; if (use_ssl) info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); return 1; } /* create client websockets using dumb increment protocol */ address = argv[optind]; lws_snprintf(ads_port, sizeof(ads_port), "%s:%u", address, port & 65535); lwsl_notice("Connecting to %s...\n", ads_port); memset(&i, 0, sizeof(i)); i.context = context; i.address = address; i.port = port; i.ssl_connection = use_ssl; i.path = "/"; i.host = ads_port; i.origin = ads_port; i.protocol = protocols[PROTOCOL_LWS_MIRROR].name; i.client_exts = exts; i.ietf_version_or_minus_one = ietf_version; for (n = 0; n < clients; n++) { ping_wsi[n] = lws_client_connect_via_info(&i); if (ping_wsi[n] == NULL) { lwsl_err("client %d failed to connect\n", n); return 1; } } lws_get_peer_addresses(ping_wsi[0], lws_get_socket_fd(ping_wsi[0]), peer_name, sizeof peer_name, ip, sizeof ip); lwsl_notice("libwebsockets test server ping - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); fprintf(stderr, "Websocket PING %s (%s) %d bytes of data.\n", peer_name, ip, size); #ifndef _WIN32 /* set the ^C handler */ sa.sa_sigaction = signal_handler; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); #endif gettimeofday(&tv, NULL); started = (tv.tv_sec * 1000000) + tv.tv_usec; /* service loop */ n = 0; while (n >= 0) { gettimeofday(&tv, NULL); l = (tv.tv_sec * 1000000) + tv.tv_usec; /* servers can hang up on us */ if (clients == 0) { n = -1; continue; } if (!interrupted_time) { if ((l - oldus) > interval_us) { for (n = 0; n < clients; n++) lws_callback_on_writable(ping_wsi[n]); oldus = l; } } else /* allow time for in-flight pongs to come */ if ((l - interrupted_time) > 250000) { n = -1; continue; } if (!interval_us) n = lws_service(context, 0); else n = lws_service(context, 1); } /* stats */ fprintf(stderr, "\n--- %s websocket ping statistics " "using %d connections ---\n" "%lu packets transmitted, %lu received, " "%lu%% packet loss, time %ldms\n" "rtt min/avg/max = %0.3f/%0.3f/%0.3f ms\n" "payload bandwidth average %0.3f KiBytes/sec\n", peer_name, clients, global_tx_count, global_rx_count, ((global_tx_count - global_rx_count) * 100) / global_tx_count, (l - started) / 1000, ((double)rtt_min) / 1000.0, ((double)rtt_avg / global_rx_count) / 1000.0, ((double)rtt_max) / 1000.0, ((double)global_rx_count * (double)size) / ((double)(l - started) / 1000000.0) / 1024.0); lws_context_destroy(context); return 0; usage: fprintf(stderr, "Usage: libwebsockets-test-ping " "<server address> [--port=<p>] " "[--ssl] [--interval=<float sec>] " "[--size=<bytes>] " "[--protocol=<protocolname>] " "[--mirror] " "[--replicate=clients>] " "[--version <version>] " "[-d <log bitfield> ]" "\n"); return 1; } |
Added undroid/libwebsockets/test-server/test-server-dumb-increment.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" /* dumb_increment protocol */ int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { unsigned char buf[LWS_PRE + 512]; struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user; unsigned char *p = &buf[LWS_PRE]; int n, m; switch (reason) { case LWS_CALLBACK_ESTABLISHED: pss->number = 0; break; case LWS_CALLBACK_SERVER_WRITEABLE: n = sprintf((char *)p, "%d", pss->number++); m = lws_write(wsi, p, n, LWS_WRITE_TEXT); if (m < n) { lwsl_err("ERROR %d writing to di socket\n", n); return -1; } if (close_testing && pss->number == 50) { lwsl_info("close tesing limit, closing\n"); return -1; } break; case LWS_CALLBACK_RECEIVE: if (len < 6) break; if (strcmp((const char *)in, "reset\n") == 0) pss->number = 0; if (strcmp((const char *)in, "closeme\n") == 0) { lwsl_notice("dumb_inc: closing as requested\n"); lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY, (unsigned char *)"seeya", 5); return -1; } break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: dump_handshake_info(wsi); /* you could return non-zero here and kill the connection */ break; /* * this just demonstrates how to handle * LWS_CALLBACK_WS_PEER_INITIATED_CLOSE and extract the peer's close * code and auxiliary data. You can just not handle it if you don't * have a use for this. */ case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: lwsl_notice("LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: len %d\n", len); for (n = 0; n < (int)len; n++) lwsl_notice(" %d: 0x%02X\n", n, ((unsigned char *)in)[n]); break; default: break; } return 0; } |
Added undroid/libwebsockets/test-server/test-server-echogen.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" /* echogen protocol * * if you connect to him using his protocol, he'll send you a file chopped * up in various frame sizes repeated until he reaches a limit. */ #define TOTAL 993840 int callback_lws_echogen(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { unsigned char buf[LWS_PRE + 8192]; struct per_session_data__echogen *pss = (struct per_session_data__echogen *)user; unsigned char *p = &buf[LWS_PRE]; int n, m; switch (reason) { case LWS_CALLBACK_ESTABLISHED: pss->total = TOTAL; pss->fragsize = 2048; pss->total_rx = 0; sprintf((char *)buf, "%s/test.html", resource_path); pss->fd = open((char *)buf, LWS_O_RDONLY); if (pss->fd < 0) { lwsl_err("Failed to open %s\n", buf); return -1; } pss->wr = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN; lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLOSED: if (pss->fd >= 0) close(pss->fd); break; case LWS_CALLBACK_SERVER_WRITEABLE: // pss->fragsize += 16; // if (pss->fragsize >= 4096) // pss->fragsize = 32; lwsl_err("%s: cb writeable, total left %ld\n", __func__, (long)pss->total); m = pss->fragsize; if ((size_t)m >= pss->total) { m = (int)pss->total; pss->wr = LWS_WRITE_CONTINUATION; /* ie, FIN */ } n = read(pss->fd, p, m); if (n < 0) { lwsl_err("failed read\n"); return -1; } if (n < m) { lseek(pss->fd, 0, SEEK_SET); m = read(pss->fd, p + n, m - n); if (m < 0) return -1; } else m = 0; pss->total -= n + m; m = lws_write(wsi, p, n + m, pss->wr); if (m < n) { lwsl_err("ERROR %d writing to di socket\n", n); return -1; } if (!pss->total) { lwsl_err("Completed OK\n"); break; } pss->wr = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN; lws_callback_on_writable(wsi); break; case LWS_CALLBACK_RECEIVE: pss->total_rx += len; lwsl_err("rx %ld\n", (long)pss->total_rx); if (pss->total_rx == TOTAL) { lws_close_reason(wsi, LWS_CLOSE_STATUS_NORMAL, (unsigned char *)"done", 4); return -1; } break; case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: lwsl_notice("LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: len %d\n", len); for (n = 0; n < (int)len; n++) lwsl_notice(" %d: 0x%02X\n", n, ((unsigned char *)in)[n]); break; default: break; } return 0; } |
Added undroid/libwebsockets/test-server/test-server-http.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server * * It defines the following websocket protocols: * * dumb-increment-protocol: once the socket is opened, an incrementing * ascii string is sent down it every 50ms. * If you send "reset\n" on the websocket, then * the incrementing number is reset to 0. * * lws-mirror-protocol: copies any received packet to every connection also * using this protocol, including the sender */ #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) /* location of the certificate revocation list */ extern char crl_path[1024]; #endif #endif #endif extern int debug_level; enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, PROTOCOL_DUMB_INCREMENT, PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; /* * We take a strict whitelist approach to stop ../ attacks */ struct serveable { const char *urlpath; const char *mimetype; }; /* * this is just an example of parsing handshake headers, you don't need this * in your code unless you will filter allowing connections by the header * content */ void dump_handshake_info(struct lws *wsi) { int n = 0, len; char buf[256]; const unsigned char *c; do { c = lws_token_to_string(n); if (!c) { n++; continue; } len = lws_hdr_total_length(wsi, n); if (!len || len > sizeof(buf) - 1) { n++; continue; } lws_hdr_copy(wsi, buf, sizeof buf, n); buf[sizeof(buf) - 1] = '\0'; fprintf(stderr, " %s = %s\n", (char *)c, buf); n++; } while (c); } const char * get_mimetype(const char *file) { int n = strlen(file); if (n < 5) return NULL; if (!strcmp(&file[n - 4], ".ico")) return "image/x-icon"; if (!strcmp(&file[n - 4], ".png")) return "image/png"; if (!strcmp(&file[n - 5], ".html")) return "text/html"; if (!strcmp(&file[n - 4], ".css")) return "text/css"; return NULL; } /* this protocol server (always the first one) handles HTTP, * * Some misc callbacks that aren't associated with a protocol also turn up only * here on the first protocol server. */ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__http *pss = (struct per_session_data__http *)user; unsigned char buffer[4096 + LWS_PRE]; unsigned long amount, file_len, sent; char leaf_path[1024]; const char *mimetype; char *other_headers; unsigned char *end, *start; struct timeval tv; unsigned char *p; #ifndef LWS_NO_CLIENT struct per_session_data__http *pss1; struct lws *wsi1; #endif char buf[256]; char b64[64]; int n, m; #ifdef EXTERNAL_POLL struct lws_pollargs *pa = (struct lws_pollargs *)in; #endif switch (reason) { case LWS_CALLBACK_HTTP: lwsl_notice("lws_http_serve: %s\n",in); if (debug_level & LLL_INFO) { dump_handshake_info(wsi); /* dump the individual URI Arg parameters */ n = 0; while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_URI_ARGS, n) > 0) { lwsl_notice("URI Arg %d: %s\n", ++n, buf); } } { char name[100], rip[50]; lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip)); sprintf(buf, "%s (%s)", name, rip); lwsl_notice("HTTP connect from %s\n", buf); } if (len < 1) { lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } #ifndef LWS_NO_CLIENT if (!strncmp(in, "/proxytest", 10)) { struct lws_client_connect_info i; char *rootpath = "/"; const char *p = (const char *)in; if (lws_get_child(wsi)) break; pss->client_finished = 0; memset(&i,0, sizeof(i)); i.context = lws_get_context(wsi); i.address = "git.libwebsockets.org"; i.port = 80; i.ssl_connection = 0; if (p[10]) i.path = (char *)in + 10; else i.path = rootpath; i.host = "git.libwebsockets.org"; i.origin = NULL; i.method = "GET"; i.parent_wsi = wsi; i.uri_replace_from = "git.libwebsockets.org/"; i.uri_replace_to = "/proxytest/"; if (!lws_client_connect_via_info(&i)) { lwsl_err("proxy connect fail\n"); break; } break; } #endif #if 1 /* this example server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL); goto try_to_reuse; } #endif if (!strncmp(in, "/postresults", 12)) { m = sprintf(buf, "<html><body>Form results: '%s'<br>" "</body></html>", pss->post_string); p = buffer + LWS_PRE; start = p; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, m, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n < 0) return 1; n = lws_write(wsi, (unsigned char *)buf, m, LWS_WRITE_HTTP); if (n < 0) return 1; goto try_to_reuse; } /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* check for the "send a big file by hand" example case */ if (!strcmp((const char *)in, "/leaf.jpg")) { if (strlen(resource_path) > sizeof(leaf_path) - 10) return -1; sprintf(leaf_path, "%s/leaf.jpg", resource_path); /* well, let's demonstrate how to send the hard way */ p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; pss->fd = lws_plat_file_open(wsi, leaf_path, &file_len, LWS_O_RDONLY); if (pss->fd == LWS_INVALID_FILE) { lwsl_err("faild to open file %s\n", leaf_path); return -1; } /* * we will send a big jpeg file, but it could be * anything. Set the Content-Type: appropriately * so the browser knows what to do with it. * * Notice we use the APIs to build the header, which * will do the right thing for HTTP 1/1.1 and HTTP2 * depending on what connection it happens to be working * on */ if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"image/jpeg", 10, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, file_len, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; /* * send the http headers... * this won't block since it's the first payload sent * on the connection since it was established * (too small for partial) * * Notice they are sent using LWS_WRITE_HTTP_HEADERS * which also means you can't send body too in one step, * this is mandated by changes in HTTP2 */ *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) { lws_plat_file_close(wsi, pss->fd); return -1; } /* * book us a LWS_CALLBACK_HTTP_WRITEABLE callback */ lws_callback_on_writable(wsi); break; } /* if not, send a file the easy way */ if (!strncmp(in, "/cgit-data/", 11)) { in = (char *)in + 11; strcpy(buf, "/usr/share/cgit"); } else strcpy(buf, resource_path); if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(buf) - 1); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); lws_return_http_status(wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demonstrates how to set a cookie on / */ other_headers = leaf_path; p = (unsigned char *)leaf_path; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)b64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; } if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *) "max-age=15768000 ; " "includeSubDomains", 36, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; n = (char *)p - leaf_path; n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: lwsl_notice("LWS_CALLBACK_HTTP_BODY: len %d\n", (int)len); strncpy(pss->post_string, in, sizeof (pss->post_string) -1); pss->post_string[sizeof(pss->post_string) - 1] = '\0'; if (len < sizeof(pss->post_string) - 1) pss->post_string[len] = '\0'; break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* * the whole of the sent body arrived, * respond to the client with a redirect to show the * results */ p = (unsigned char *)buf + LWS_PRE; n = lws_http_redirect(wsi, HTTP_STATUS_SEE_OTHER, /* 303 */ (unsigned char *)"/postresults", 12, /* location + len */ &p, /* temp buffer to use */ p + sizeof(buf) - 1 - LWS_PRE /* buffer len */ ); goto try_to_reuse; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n"); if (pss->client_finished) return -1; if (pss->fd == LWS_INVALID_FILE) goto try_to_reuse; #ifndef LWS_NO_CLIENT if (pss->reason_bf & 2) { char *px = buf + LWS_PRE; int lenx = sizeof(buf) - LWS_PRE; /* * our sink is writeable and our source has something * to read. So read a lump of source material of * suitable size to send or what's available, whichever * is the smaller. */ pss->reason_bf &= ~2; wsi1 = lws_get_child(wsi); if (!wsi1) break; if (lws_http_client_read(wsi1, &px, &lenx) < 0) goto bail; if (pss->client_finished) return -1; break; } #endif /* * we can send more of whatever it is we were sending */ sent = 0; do { /* we'd like the send this much */ n = sizeof(buffer) - LWS_PRE; /* but if the peer told us he wants less, we can adapt */ m = lws_get_peer_write_allowance(wsi); /* -1 means not using a protocol that has this info */ if (m == 0) /* right now, peer can't handle anything */ goto later; if (m != -1 && m < n) /* he couldn't handle that much */ n = m; n = lws_plat_file_read(wsi, pss->fd, &amount, buffer + LWS_PRE, n); /* problem reading, close conn */ if (n < 0) { lwsl_err("problem reading file\n"); goto bail; } n = (int)amount; /* sent it all, close conn */ if (n == 0) goto penultimate; /* * To support HTTP2, must take care about preamble space * * identification of when we send the last payload frame * is handled by the library itself if you sent a * content-length header */ m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP); if (m < 0) { lwsl_err("write failed\n"); /* write failed, close conn */ goto bail; } if (m) /* while still active, extend timeout */ lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5); sent += m; } while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024)); later: lws_callback_on_writable(wsi); break; penultimate: lws_plat_file_close(wsi, pss->fd); pss->fd = LWS_INVALID_FILE; goto try_to_reuse; bail: lws_plat_file_close(wsi, pss->fd); return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default unhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: /* if we returned non-zero from here, we kill the connection */ break; #ifndef LWS_NO_CLIENT case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: { char ctype[64], ctlen = 0; lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n"); p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(lws_get_parent(wsi), 200, &p, end)) return 1; if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE); if (ctlen > 0) { if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)ctype, ctlen, &p, end)) return 1; } #if 0 if (lws_add_http_header_content_length(lws_get_parent(wsi), file_len, &p, end)) return 1; #endif if (lws_finalize_http_header(lws_get_parent(wsi), &p, end)) return 1; *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) return -1; break; } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); return -1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; // lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p: sock: %d, parent_wsi: %p, parent_sock:%d, len %d\n", // wsi, lws_get_socket_fd(wsi), // lws_get_parent(wsi), // lws_get_socket_fd(lws_get_parent(wsi)), len); pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->reason_bf |= 2; lws_callback_on_writable(lws_get_parent(wsi)); break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len); assert(lws_get_parent(wsi)); m = lws_write(lws_get_parent(wsi), (unsigned char *)in, len, LWS_WRITE_HTTP); if (m < 0) return -1; break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n"); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->client_finished = 1; break; #endif /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_lock(len); break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_unlock(len); break; #ifdef EXTERNAL_POLL case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "lws_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: /* Verify the client certificate */ if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) { int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user); int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user); const char* msg = X509_verify_cert_error_string(err); lwsl_err("LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: SSL error: %s (%d), depth: %d\n", msg, err, depth); return 1; } break; #if defined(LWS_HAVE_SSL_CTX_set1_param) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if (crl_path[0]) { /* Enable CRL checking */ X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); SSL_CTX_set1_param((SSL_CTX*)user, param); X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); X509_VERIFY_PARAM_free(param); if (n != 1) { char errbuf[256]; n = ERR_get_error(); lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); return 1; } } break; #endif #endif #endif #endif default: break; } return 0; /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */ try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; } |
Added undroid/libwebsockets/test-server/test-server-libev.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2011-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" int close_testing; int max_poll_elements; int debug_level = 7; volatile int force_exit = 0; struct lws_context *context; struct lws_plat_file_ops fops_plat; /* http server gets files from this path */ #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" char *resource_path = LOCAL_RESOURCE_PATH; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) char crl_path[1024] = ""; #endif #endif #endif /* * libev dumps their hygiene problems on their users blaming compiler * http://lists.schmorp.de/pipermail/libev/2008q4/000442.html */ #if EV_MINPRI == EV_MAXPRI # define _ev_set_priority(ev, pri) ((ev), (pri)) #else # define _ev_set_priority(ev, pri) { \ ev_watcher *evw = (ev_watcher *)(void *)ev; \ evw->priority = pri; \ } #endif #define _ev_init(ev,cb_) { \ ev_watcher *evw = (ev_watcher *)(void *)ev; \ \ evw->active = evw->pending = 0; \ _ev_set_priority((ev), 0); \ ev_set_cb((ev), cb_); \ } #define _ev_timer_init(ev, cb, after, _repeat) { \ ev_watcher_time *evwt = (ev_watcher_time *)(void *)ev; \ \ _ev_init(ev, cb); \ evwt->at = after; \ (ev)->repeat = _repeat; \ } /* singlethreaded version --> no locks */ void test_server_lock(int care) { } void test_server_unlock(int care) { } /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server * * It defines the following websocket protocols: * * dumb-increment-protocol: once the socket is opened, an incrementing * ascii string is sent down it every 50ms. * If you send "reset\n" on the websocket, then * the incrementing number is reset to 0. * * lws-mirror-protocol: copies any received packet to every connection also * using this protocol, including the sender */ enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, PROTOCOL_DUMB_INCREMENT, PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http, /* callback */ sizeof (struct per_session_data__http), /* per_session_data_size */ 0, /* max frame size / rx buffer */ }, { "dumb-increment-protocol", callback_dumb_increment, sizeof(struct per_session_data__dumb_increment), 10, }, { "lws-mirror-protocol", callback_lws_mirror, sizeof(struct per_session_data__lws_mirror), 128, }, { NULL, NULL, 0, 0 } /* terminator */ }; static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_no_context_takeover; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; /* this shows how to override the lws file operations. You don't need * to do any of this unless you have a reason (eg, want to serve * compressed files without decompressing the whole archive) */ static lws_filefd_type test_server_fops_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) { lws_filefd_type n; /* call through to original platform implementation */ n = fops_plat.open(wsi, filename, filelen, flags); lwsl_notice("%s: opening %s, ret %ld, len %lu\n", __func__, filename, (long)n, *filelen); return n; } void signal_cb(struct ev_loop *loop, struct ev_signal* watcher, int revents) { lwsl_notice("Signal caught, exiting...\n"); force_exit = 1; switch (watcher->signum) { case SIGTERM: case SIGINT: ev_break(loop, EVBREAK_ALL); break; default: signal(SIGABRT, SIG_DFL); abort(); break; } } static void ev_timeout_cb (EV_P_ ev_timer *w, int revents) { lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_DUMB_INCREMENT]); } static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, { "libev", no_argument, NULL, 'e' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, { NULL, 0, 0, 0 } }; int main(int argc, char **argv) { int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE }; struct ev_signal signals[ARRAY_SIZE(sigs)]; struct ev_loop *loop = ev_default_loop(0); struct lws_context_creation_info info; char interface_name[128] = ""; const char *iface = NULL; ev_timer timeout_watcher; char cert_path[1024]; char key_path[1024]; int use_ssl = 0; int opts = 0; int n = 0; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; while (n >= 0) { n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL); if (n < 0) continue; switch (n) { case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 1; } #endif for (n = 0; n < ARRAY_SIZE(sigs); n++) { _ev_init(&signals[n], signal_cb); ev_signal_set(&signals[n], sigs[n]); ev_signal_start(loop, &signals[n]); } #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server libev - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); printf("Using resource path \"%s\"\n", resource_path); info.iface = iface; info.protocols = protocols; info.extensions = exts; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; } info.gid = -1; info.uid = -1; info.max_http_header_pool = 1; info.options = opts | LWS_SERVER_OPTION_LIBEV; context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } /* * this shows how to override the lws file operations. You don't need * to do any of this unless you have a reason (eg, want to serve * compressed files without decompressing the whole archive) */ /* stash original platform fops */ fops_plat = *(lws_get_fops(context)); /* override the active fops */ lws_get_fops(context)->open = test_server_fops_open; lws_ev_initloop(context, loop, 0); _ev_timer_init(&timeout_watcher, ev_timeout_cb, 0.05, 0.05); ev_timer_start(loop, &timeout_watcher); ev_run(loop, 0); lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/test-server/test-server-libuv.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server for libev - libwebsockets test implementation * * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "test-server.h" #include <uv.h> int close_testing; int max_poll_elements; int debug_level = 7; struct lws_context *context; struct lws_plat_file_ops fops_plat; /* http server gets files from this path */ #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" char *resource_path = LOCAL_RESOURCE_PATH; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) char crl_path[1024] = ""; #endif #endif #endif /* singlethreaded version --> no locks */ void test_server_lock(int care) { } void test_server_unlock(int care) { } /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server * * It defines the following websocket protocols: * * dumb-increment-protocol: once the socket is opened, an incrementing * ascii string is sent down it every 50ms. * If you send "reset\n" on the websocket, then * the incrementing number is reset to 0. * * lws-mirror-protocol: copies any received packet to every connection also * using this protocol, including the sender */ enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, PROTOCOL_DUMB_INCREMENT, PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http, /* callback */ sizeof (struct per_session_data__http), /* per_session_data_size */ 0, /* max frame size / rx buffer */ }, { "dumb-increment-protocol", callback_dumb_increment, sizeof(struct per_session_data__dumb_increment), 10, }, { "lws-mirror-protocol", callback_lws_mirror, sizeof(struct per_session_data__lws_mirror), 128, }, { "lws-status", callback_lws_status, sizeof(struct per_session_data__lws_status), 128, }, { NULL, NULL, 0, 0 } /* terminator */ }; static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_no_context_takeover; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; void signal_cb(uv_signal_t *watcher, int signum) { lwsl_err("Signal %d caught, exiting...\n", watcher->signum); switch (watcher->signum) { case SIGTERM: case SIGINT: break; default: signal(SIGABRT, SIG_DFL); abort(); break; } lws_libuv_stop(context); } static void uv_timeout_cb_dumb_increment(uv_timer_t *w #if UV_VERSION_MAJOR == 0 , int status #endif ) { lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_DUMB_INCREMENT]); } static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, { "libev", no_argument, NULL, 'e' }, { "foreign", no_argument, NULL, 'f' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, { NULL, 0, 0, 0 } }; #if UV_VERSION_MAJOR > 0 /* ----- this code is only needed for foreign / external libuv tests -----*/ struct counter { int cur, lim; int stop_loop; }; static void timer_cb(uv_timer_t *t) { struct counter *c = t->data; lwsl_notice(" timer %p cb, count %d, loop has %d handles\n", t, c->cur, t->loop->active_handles); if (c->cur++ == c->lim) { lwsl_debug("stop loop from timer\n"); uv_timer_stop(t); if (c->stop_loop) uv_stop(t->loop); } } static void timer_close_cb(uv_handle_t *h) { lwsl_notice("timer close cb %p, loop has %d handles\n", h, h->loop->active_handles); } void outer_signal_cb(uv_signal_t *s, int signum) { lwsl_notice("Foreign loop got signal %d\n", signum); uv_signal_stop(s); uv_stop(s->loop); } static void lws_uv_close_cb(uv_handle_t *handle) { //lwsl_err("%s\n", __func__); } static void lws_uv_walk_cb(uv_handle_t *handle, void *arg) { uv_close(handle, lws_uv_close_cb); } /* --- end of foreign test code ---- */ #endif int main(int argc, char **argv) { struct lws_context_creation_info info; char interface_name[128] = ""; #if UV_VERSION_MAJOR > 0 /* --- only needed for foreign loop test ---> */ uv_loop_t loop; uv_signal_t signal_outer; uv_timer_t timer_outer; struct counter ctr; int foreign_libuv_loop = 0; /* <--- only needed for foreign loop test --- */ #endif uv_timer_t timeout_watcher; const char *iface = NULL; char cert_path[1024]; char key_path[1024]; int use_ssl = 0; int opts = 0; int n = 0; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; while (n >= 0) { n = getopt_long(argc, argv, "feci:hsap:d:Dr:", options, NULL); if (n < 0) continue; switch (n) { case 'f': #if UV_VERSION_MAJOR > 0 foreign_libuv_loop = 1; #endif break; case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(WIN32) #if !defined(LWS_NO_DAEMONIZE) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 1; } #endif /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server libuv - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); lwsl_info("Using resource path \"%s\"\n", resource_path); info.iface = iface; info.protocols = protocols; info.extensions = exts; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; } info.gid = -1; info.uid = -1; info.max_http_header_pool = 1; info.timeout_secs = 5; info.options = opts | LWS_SERVER_OPTION_LIBUV; #if UV_VERSION_MAJOR > 0 if (foreign_libuv_loop) { /* create the foreign loop */ uv_loop_init(&loop); /* run some timer on that loop just so loop is not 'clean' */ uv_signal_init(&loop, &signal_outer); uv_signal_start(&signal_outer, outer_signal_cb, SIGINT); uv_timer_init(&loop, &timer_outer); timer_outer.data = &ctr; ctr.cur = 0; ctr.lim = ctr.cur + 5; ctr.stop_loop = 1; uv_timer_start(&timer_outer, timer_cb, 0, 1000); lwsl_notice("running loop without libwebsockets for %d s\n", ctr.lim); uv_run(&loop, UV_RUN_DEFAULT); /* timer will stop loop and we will get here */ } #endif context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } lws_uv_sigint_cfg(context, 1, signal_cb); #if UV_VERSION_MAJOR > 0 if (foreign_libuv_loop) /* we have our own uv loop outside of lws */ lws_uv_initloop(context, &loop, 0); else #endif { /* * lws will create his own libuv loop in the context */ if (lws_uv_initloop(context, NULL, 0)) { lwsl_err("lws_uv_initloop failed\n"); goto bail; } } uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher); uv_timer_start(&timeout_watcher, uv_timeout_cb_dumb_increment, 50, 50); #if UV_VERSION_MAJOR > 0 if (foreign_libuv_loop) { /* * prepare inner timer on loop, to run along with lws. * Will exit after 5s while lws keeps running */ struct counter ctr_inner = { 0, 3, 0 }; int e; uv_timer_t timer_inner; uv_timer_init(&loop, &timer_inner); timer_inner.data = &ctr_inner; uv_timer_start(&timer_inner, timer_cb, 200, 1000); /* make this timer long-lived, should keep * firing after lws exits */ ctr.cur = 0; ctr.lim = ctr.cur + 1000; uv_timer_start(&timer_outer, timer_cb, 0, 1000); uv_run(&loop, UV_RUN_DEFAULT); /* we are here either because signal stopped us, * or outer timer expired */ /* close short timer */ uv_timer_stop(&timer_inner); uv_close((uv_handle_t*)&timer_inner, timer_close_cb); /* stop the dumb increment timer */ uv_timer_stop(&timeout_watcher); lwsl_notice("Destroying lws context\n"); /* detach lws */ lws_context_destroy(context); lwsl_notice("Please wait while the outer libuv test continues for 10s\n"); ctr.lim = ctr.cur + 10; /* try and run outer timer for 10 more seconds, * (or sigint outer handler) after lws has left the loop */ uv_run(&loop, UV_RUN_DEFAULT); /* Clean up the foreign loop now */ /* PHASE 1: stop and close things we created * outside of lws */ uv_timer_stop(&timer_outer); uv_close((uv_handle_t*)&timer_outer, timer_close_cb); uv_signal_stop(&signal_outer); e = 100; while (e--) uv_run(&loop, UV_RUN_NOWAIT); /* PHASE 2: close anything remaining */ uv_walk(&loop, lws_uv_walk_cb, NULL); e = 100; while (e--) uv_run(&loop, UV_RUN_NOWAIT); /* PHASE 3: close the UV loop itself */ e = uv_loop_close(&loop); lwsl_notice("uv loop close rc %s\n", e ? uv_strerror(e) : "ok"); } else #endif { lws_libuv_run(context, 0); bail: lws_context_destroy(context); } lwsl_notice("libwebsockets-test-server exited cleanly\n"); return 0; } |
Added undroid/libwebsockets/test-server/test-server-mirror.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" /* lws-mirror_protocol */ #define MAX_MESSAGE_QUEUE 512 struct a_message { void *payload; size_t len; }; static struct a_message ringbuffer[MAX_MESSAGE_QUEUE]; static int ringbuffer_head; int callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user; int n, m; switch (reason) { case LWS_CALLBACK_ESTABLISHED: lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); pss->ringbuffer_tail = ringbuffer_head; pss->wsi = wsi; break; case LWS_CALLBACK_PROTOCOL_DESTROY: lwsl_notice("%s: mirror protocol cleaning up\n", __func__); for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++) if (ringbuffer[n].payload) free(ringbuffer[n].payload); break; case LWS_CALLBACK_SERVER_WRITEABLE: if (close_testing) break; while (pss->ringbuffer_tail != ringbuffer_head) { m = ringbuffer[pss->ringbuffer_tail].len; n = lws_write(wsi, (unsigned char *) ringbuffer[pss->ringbuffer_tail].payload + LWS_PRE, m, LWS_WRITE_TEXT); if (n < 0) { lwsl_err("ERROR %d writing to mirror socket\n", n); return -1; } if (n < m) lwsl_err("mirror partial write %d vs %d\n", n, m); if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1)) pss->ringbuffer_tail = 0; else pss->ringbuffer_tail++; if (((ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15)) lws_rx_flow_allow_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); if (lws_send_pipe_choked(wsi)) { lws_callback_on_writable(wsi); break; } } break; case LWS_CALLBACK_RECEIVE: if (((ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) { lwsl_err("dropping!\n"); goto choke; } if (ringbuffer[ringbuffer_head].payload) free(ringbuffer[ringbuffer_head].payload); ringbuffer[ringbuffer_head].payload = malloc(LWS_PRE + len); ringbuffer[ringbuffer_head].len = len; memcpy((char *)ringbuffer[ringbuffer_head].payload + LWS_PRE, in, len); if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1)) ringbuffer_head = 0; else ringbuffer_head++; if (((ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2)) goto done; choke: lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi); lws_rx_flow_control(wsi, 0); done: lws_callback_on_writable_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: dump_handshake_info(wsi); /* you could return non-zero here and kill the connection */ break; default: break; } return 0; } |
Added undroid/libwebsockets/test-server/test-server-pthreads.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" #include <pthread.h> int close_testing; int max_poll_elements; int debug_level = 7; #ifdef EXTERNAL_POLL struct lws_pollfd *pollfds; int *fd_lookup; int count_pollfds; #endif volatile int force_exit = 0; struct lws_context *context; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) char crl_path[1024] = ""; #endif #endif #endif /* * This mutex lock protects code that changes or relies on wsi list outside of * the service thread. The service thread will acquire it when changing the * wsi list and other threads should acquire it while dereferencing wsis or * calling apis like lws_callback_on_writable_all_protocol() which * use the wsi list and wsis from a different thread context. */ pthread_mutex_t lock_established_conns; /* http server gets files from this path */ #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" char *resource_path = LOCAL_RESOURCE_PATH; /* * multithreaded version - protect wsi lifecycle changes in the library * these are called from protocol 0 callbacks */ void test_server_lock(int care) { if (care) pthread_mutex_lock(&lock_established_conns); } void test_server_unlock(int care) { if (care) pthread_mutex_unlock(&lock_established_conns); } /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server * * It defines the following websocket protocols: * * dumb-increment-protocol: once the socket is opened, an incrementing * ascii string is sent down it every 50ms. * If you send "reset\n" on the websocket, then * the incrementing number is reset to 0. * * lws-mirror-protocol: copies any received packet to every connection also * using this protocol, including the sender */ enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, PROTOCOL_DUMB_INCREMENT, PROTOCOL_LWS_MIRROR, /* always last */ DEMO_PROTOCOL_COUNT }; /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http, /* callback */ sizeof (struct per_session_data__http), /* per_session_data_size */ 0, /* max frame size / rx buffer */ }, { "dumb-increment-protocol", callback_dumb_increment, sizeof(struct per_session_data__dumb_increment), 10, }, { "lws-mirror-protocol", callback_lws_mirror, sizeof(struct per_session_data__lws_mirror), 128, }, { NULL, NULL, 0, 0 } /* terminator */ }; void *thread_dumb_increment(void *threadid) { while (!force_exit) { /* * this lock means wsi in the active list cannot * disappear underneath us, because the code to add and remove * them is protected by the same lock */ pthread_mutex_lock(&lock_established_conns); lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_DUMB_INCREMENT]); pthread_mutex_unlock(&lock_established_conns); usleep(100000); } pthread_exit(NULL); } void *thread_service(void *threadid) { while (lws_service_tsi(context, 50, (int)(long)threadid) >= 0 && !force_exit) ; pthread_exit(NULL); } void sighandler(int sig) { force_exit = 1; lws_cancel_service(context); } static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate; client_no_context_takeover; client_max_window_bits" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, { "libev", no_argument, NULL, 'e' }, { "threads", required_argument, NULL, 'j' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, { NULL, 0, 0, 0 } }; int main(int argc, char **argv) { struct lws_context_creation_info info; char interface_name[128] = ""; const char *iface = NULL; pthread_t pthread_dumb, pthread_service[32]; char cert_path[1024]; char key_path[1024]; int threads = 1; int use_ssl = 0; void *retval; int opts = 0; int n = 0; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; pthread_mutex_init(&lock_established_conns, NULL); while (n >= 0) { n = getopt_long(argc, argv, "eci:hsap:d:Dr:j:", options, NULL); if (n < 0) continue; switch (n) { case 'j': threads = atoi(optarg); if (threads > ARRAY_SIZE(pthread_service)) { lwsl_err("Max threads %d\n", ARRAY_SIZE(pthread_service)); return 1; } break; case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 1; } #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server pthreads - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); printf("Using resource path \"%s\"\n", resource_path); #ifdef EXTERNAL_POLL max_poll_elements = getdtablesize(); pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd)); fd_lookup = malloc(max_poll_elements * sizeof (int)); if (pollfds == NULL || fd_lookup == NULL) { lwsl_err("Out of memory pollfds=%d\n", max_poll_elements); return -1; } #endif info.iface = iface; info.protocols = protocols; info.extensions = exts; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; } info.gid = -1; info.uid = -1; info.options = opts; info.count_threads = threads; info.extensions = exts; info.max_http_header_pool = 4; context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } /* start the dumb increment thread */ n = pthread_create(&pthread_dumb, NULL, thread_dumb_increment, 0); if (n) { lwsl_err("Unable to create dumb thread\n"); goto done; } /* * notice the actual number of threads may be capped by the library, * so use lws_get_count_threads() to get the actual amount of threads * initialized. */ for (n = 0; n < lws_get_count_threads(context); n++) if (pthread_create(&pthread_service[n], NULL, thread_service, (void *)(long)n)) lwsl_err("Failed to start service thread\n"); /* wait for all the service threads to exit */ while ((--n) >= 0) pthread_join(pthread_service[n], &retval); /* wait for pthread_dumb to exit */ pthread_join(pthread_dumb, &retval); done: lws_context_destroy(context); pthread_mutex_destroy(&lock_established_conns); lwsl_notice("libwebsockets-test-server exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/test-server/test-server-status.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" #include <time.h> static unsigned char server_info[1024]; static int server_info_len; static int current; static char cache[16384]; static int cache_len; static struct per_session_data__lws_status *list; static int live_wsi; static void update_status(struct lws *wsi, struct per_session_data__lws_status *pss) { struct per_session_data__lws_status **pp = &list; int subsequent = 0; char *p = cache + LWS_PRE, *start = p; char date[128]; time_t t; struct tm *ptm; #ifndef WIN32 struct tm tm; #endif p += lws_snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[", server_info, live_wsi); /* render the list */ while (*pp) { t = (*pp)->tv_established.tv_sec; #ifdef WIN32 ptm = localtime(&t); if (!ptm) #else ptm = &tm; if (!localtime_r(&t, &tm)) #endif strcpy(date, "unknown"); else #ifdef WIN32 strftime(date, sizeof(date), "%Y %H:%M %Z", ptm); #else strftime(date, sizeof(date), "%F %H:%M %Z", ptm); #endif if ((p - start) > (sizeof(cache) - 512)) break; if (subsequent) *p++ = ','; subsequent = 1; p += lws_snprintf(p, sizeof(cache) - (p - start) - 1, "{\"peer\":\"%s\",\"time\":\"%s\"," "\"ua\":\"%s\"}", (*pp)->ip, date, (*pp)->user_agent); pp = &((*pp)->list); } p += sprintf(p, "]}"); cache_len = p - start; lwsl_err("cache_len %d\n", cache_len); *p = '\0'; /* since we changed the list, increment the 'version' */ current++; /* update everyone */ lws_callback_on_writable_all_protocol(lws_get_context(wsi), lws_get_protocol(wsi)); } /* lws-status protocol */ int callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_status *pss = (struct per_session_data__lws_status *)user, **pp; char name[128], rip[128]; int m; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: /* * Prepare the static server info */ server_info_len = sprintf((char *)server_info, "\"version\":\"%s\"," " \"hostname\":\"%s\"", lws_get_library_version(), lws_canonical_hostname( lws_get_context(wsi))); break; case LWS_CALLBACK_ESTABLISHED: /* * we keep a linked list of live pss, so we can walk it */ pss->last = 0; pss->list = list; list = pss; live_wsi++; lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip)); sprintf(pss->ip, "%s (%s)", name, rip); gettimeofday(&pss->tv_established, NULL); strcpy(pss->user_agent, "unknown"); lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent), WSI_TOKEN_HTTP_USER_AGENT); update_status(wsi, pss); break; case LWS_CALLBACK_SERVER_WRITEABLE: m = lws_write(wsi, (unsigned char *)cache + LWS_PRE, cache_len, LWS_WRITE_TEXT); if (m < server_info_len) { lwsl_err("ERROR %d writing to di socket\n", m); return -1; } break; case LWS_CALLBACK_CLOSED: /* * remove ourselves from live pss list */ lwsl_err("CLOSING pss %p ********\n", pss); pp = &list; while (*pp) { if (*pp == pss) { *pp = pss->list; pss->list = NULL; live_wsi--; break; } pp = &((*pp)->list); } update_status(wsi, pss); break; default: break; } return 0; } |
Added undroid/libwebsockets/test-server/test-server-v2.0.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server-v2.0 - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include <libwebsockets.h> #include <getopt.h> #ifndef WIN32 #include <syslog.h> #endif int debug_level = 7; struct lws_context *context; /* http server gets files from this path */ #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" char *resource_path = LOCAL_RESOURCE_PATH; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) char crl_path[1024] = ""; #endif #endif #endif /* * This test server is ONLY this .c file, it's radically simpler than the * pre-v2.0 test servers. For example it has no user callback content or * defines any protocols. * * To achieve that, it uses the LWS protocol plugins. Those in turn * use libuv. So you must configure with LWS_WITH_PLUGINS (which implies * libuv) to get this to build. * * You can find the individual protocol plugin sources in ../plugins */ void sighandler(int sig) { lws_cancel_service(context); } static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; /* * mount a filesystem directory into the URL space at / * point it to our /usr/share directory with our assets in * stuff from here is autoserved by the library */ static const struct lws_http_mount mount = { NULL, /* linked-list pointer to next, but we only have one */ "/", /* mountpoint in URL namespace on this vhost */ LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */ "test.html", /* default filename if none given */ NULL, NULL, 0, 0, 0, 0, 0, LWSMPRO_FILE, /* mount type is a directory in a filesystem */ 1, /* strlen("/"), ie length of the mountpoint */ }; /* * this sets a per-vhost, per-protocol option name:value pair * the effect is to set this protocol to be the default one for the vhost, * ie, selected if no Protocol: header is sent with the ws upgrade. */ static const struct lws_protocol_vhost_options pvo_opt = { NULL, NULL, "default", "1" }; /* * We must enable the plugin protocols we want into our vhost with a * linked-list. We can also give the plugin per-vhost options here. */ static const struct lws_protocol_vhost_options pvo_2 = { NULL, NULL, "lws-status", "" /* ignored, just matches the protocol name above */ }; static const struct lws_protocol_vhost_options pvo_1 = { &pvo_2, NULL, "lws-mirror-protocol", "" }; static const struct lws_protocol_vhost_options pvo = { &pvo_1, &pvo_opt, "dumb-increment-protocol", "" }; static void signal_cb(uv_signal_t *watcher, int signum) { lwsl_err("Signal %d caught, exiting...\n", watcher->signum); switch (watcher->signum) { case SIGTERM: case SIGINT: break; default: signal(SIGABRT, SIG_DFL); abort(); break; } lws_libuv_stop(context); } static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "ssl-cert", required_argument, NULL, 'C' }, { "ssl-key", required_argument, NULL, 'K' }, { "ssl-ca", required_argument, NULL, 'A' }, #if defined(LWS_OPENSSL_SUPPORT) { "ssl-verify-client", no_argument, NULL, 'v' }, #if defined(LWS_HAVE_SSL_CTX_set1_param) { "ssl-crl", required_argument, NULL, 'R' }, #endif #endif { "libev", no_argument, NULL, 'e' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, { NULL, 0, 0, 0 } }; static const char * const plugin_dirs[] = { INSTALL_DATADIR"/libwebsockets-test-server/plugins/", NULL }; int main(int argc, char **argv) { struct lws_context_creation_info info; char interface_name[128] = ""; const char *iface = NULL; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; int uid = -1, gid = -1; int use_ssl = 0; int opts = 0; int n = 0; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; while (n >= 0) { n = getopt_long(argc, argv, "ei:hsap:d:Dr:C:K:A:R:vu:g:", options, NULL); if (n < 0) continue; switch (n) { case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif case 'u': uid = atoi(optarg); break; case 'g': gid = atoi(optarg); break; case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; #if defined(LWS_OPENSSL_SUPPORT) case 'v': use_ssl = 1; opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif #endif #endif case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 10; } #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); lwsl_notice(" Using resource path \"%s\"\n", resource_path); info.iface = iface; info.protocols = NULL; /* all protocols from lib / plugins */ info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; info.gid = gid; info.uid = uid; info.max_http_header_pool = 16; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_LIBUV; /* plugins require this */ if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!cert_path[0]) sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!key_path[0]) sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; if (ca_path[0]) info.ssl_ca_filepath = ca_path; /* redirect guys coming on http */ info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS; } info.extensions = exts; info.timeout_secs = 5; info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "DHE-RSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-SHA384:" "HIGH:!aNULL:!eNULL:!EXPORT:" "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" "!DHE-RSA-AES128-SHA256:" "!AES128-GCM-SHA256:" "!AES128-SHA256:" "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; /* tell lws to look for protocol plugins here */ info.plugin_dirs = plugin_dirs; /* tell lws about our mount we want */ info.mounts = &mount; /* * give it our linked-list of Per-Vhost Options, these control * which protocols (from plugins) are allowed to be enabled on * our vhost */ info.pvo = &pvo; /* * As it is, this creates the context and a single Vhost at the same * time. You can use LWS_SERVER_OPTION_EXPLICIT_VHOSTS option above * to just create the context, and call lws_create_vhost() afterwards * multiple times with different info to get multiple listening vhosts. */ context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } /* libuv event loop */ lws_uv_sigint_cfg(context, 1, signal_cb); if (lws_uv_initloop(context, NULL, 0)) lwsl_err("lws_uv_initloop failed\n"); else lws_libuv_run(context, 0); /* when we decided to exit the event loop */ lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/test-server/test-server.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #include "test-server.h" int close_testing; int max_poll_elements; int debug_level = 7; #ifdef EXTERNAL_POLL struct lws_pollfd *pollfds; int *fd_lookup; int count_pollfds; #endif volatile int force_exit = 0; struct lws_context *context; struct lws_plat_file_ops fops_plat; /* http server gets files from this path */ #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" char *resource_path = LOCAL_RESOURCE_PATH; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) char crl_path[1024] = ""; #endif #endif #endif /* singlethreaded version --> no locks */ void test_server_lock(int care) { } void test_server_unlock(int care) { } /* * This demo server shows how to use libwebsockets for one or more * websocket protocols in the same server * * It defines the following websocket protocols: * * dumb-increment-protocol: once the socket is opened, an incrementing * ascii string is sent down it every 50ms. * If you send "reset\n" on the websocket, then * the incrementing number is reset to 0. * * lws-mirror-protocol: copies any received packet to every connection also * using this protocol, including the sender */ enum demo_protocols { /* always first */ PROTOCOL_HTTP = 0, PROTOCOL_DUMB_INCREMENT, PROTOCOL_LWS_MIRROR, PROTOCOL_LWS_ECHOGEN, PROTOCOL_LWS_STATUS, /* always last */ DEMO_PROTOCOL_COUNT }; /* list of supported protocols and callbacks */ static struct lws_protocols protocols[] = { /* first protocol must always be HTTP handler */ { "http-only", /* name */ callback_http, /* callback */ sizeof (struct per_session_data__http), /* per_session_data_size */ 0, /* max frame size / rx buffer */ }, { "dumb-increment-protocol", callback_dumb_increment, sizeof(struct per_session_data__dumb_increment), 10, /* rx buf size must be >= permessage-deflate rx size */ }, { "lws-mirror-protocol", callback_lws_mirror, sizeof(struct per_session_data__lws_mirror), 128, /* rx buf size must be >= permessage-deflate rx size */ }, { "lws-echogen", callback_lws_echogen, sizeof(struct per_session_data__echogen), 128, /* rx buf size must be >= permessage-deflate rx size */ }, { "lws-status", callback_lws_status, sizeof(struct per_session_data__lws_status), 128, /* rx buf size must be >= permessage-deflate rx size */ }, { NULL, NULL, 0, 0 } /* terminator */ }; /* this shows how to override the lws file operations. You don't need * to do any of this unless you have a reason (eg, want to serve * compressed files without decompressing the whole archive) */ static lws_filefd_type test_server_fops_open(struct lws *wsi, const char *filename, unsigned long *filelen, int flags) { lws_filefd_type n; /* call through to original platform implementation */ n = fops_plat.open(wsi, filename, filelen, flags); lwsl_notice("%s: opening %s, ret %ld, len %lu\n", __func__, filename, (long)n, *filelen); return n; } void sighandler(int sig) { force_exit = 1; lws_cancel_service(context); } static const struct lws_extension exts[] = { { "permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate" }, { "deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame" }, { NULL, NULL, NULL /* terminator */ } }; static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "debug", required_argument, NULL, 'd' }, { "port", required_argument, NULL, 'p' }, { "ssl", no_argument, NULL, 's' }, { "allow-non-ssl", no_argument, NULL, 'a' }, { "interface", required_argument, NULL, 'i' }, { "closetest", no_argument, NULL, 'c' }, { "ssl-cert", required_argument, NULL, 'C' }, { "ssl-key", required_argument, NULL, 'K' }, { "ssl-ca", required_argument, NULL, 'A' }, #if defined(LWS_OPENSSL_SUPPORT) { "ssl-verify-client", no_argument, NULL, 'v' }, #if defined(LWS_HAVE_SSL_CTX_set1_param) { "ssl-crl", required_argument, NULL, 'R' }, #endif #endif { "libev", no_argument, NULL, 'e' }, #ifndef LWS_NO_DAEMONIZE { "daemonize", no_argument, NULL, 'D' }, #endif { "resource_path", required_argument, NULL, 'r' }, { NULL, 0, 0, 0 } }; int main(int argc, char **argv) { struct lws_context_creation_info info; char interface_name[128] = ""; unsigned int ms, oldms = 0; const char *iface = NULL; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; int uid = -1, gid = -1; int use_ssl = 0; int opts = 0; int n = 0; #ifndef _WIN32 int syslog_options = LOG_PID | LOG_PERROR; #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; while (n >= 0) { n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:", options, NULL); if (n < 0) continue; switch (n) { case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #ifndef _WIN32 syslog_options &= ~LOG_PERROR; #endif break; #endif case 'u': uid = atoi(optarg); break; case 'g': gid = atoi(optarg); break; case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; #if defined(LWS_OPENSSL_SUPPORT) case 'v': use_ssl = 1; opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif #endif #endif case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 10; } #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n"); printf("Using resource path \"%s\"\n", resource_path); #ifdef EXTERNAL_POLL max_poll_elements = getdtablesize(); pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd)); fd_lookup = malloc(max_poll_elements * sizeof (int)); if (pollfds == NULL || fd_lookup == NULL) { lwsl_err("Out of memory pollfds=%d\n", max_poll_elements); return -1; } #endif info.iface = iface; info.protocols = protocols; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!cert_path[0]) sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!key_path[0]) sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; if (ca_path[0]) info.ssl_ca_filepath = ca_path; } info.gid = gid; info.uid = uid; info.max_http_header_pool = 16; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8; info.extensions = exts; info.timeout_secs = 5; info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "DHE-RSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-SHA384:" "HIGH:!aNULL:!eNULL:!EXPORT:" "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" "!DHE-RSA-AES128-SHA256:" "!AES128-GCM-SHA256:" "!AES128-SHA256:" "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; if (use_ssl) /* redirect guys coming on http */ info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS; context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } /* this shows how to override the lws file operations. You don't need * to do any of this unless you have a reason (eg, want to serve * compressed files without decompressing the whole archive) */ /* stash original platform fops */ fops_plat = *(lws_get_fops(context)); /* override the active fops */ lws_get_fops(context)->open = test_server_fops_open; n = 0; while (n >= 0 && !force_exit) { struct timeval tv; gettimeofday(&tv, NULL); /* * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every * live websocket connection using the DUMB_INCREMENT protocol, * as soon as it can take more packets (usually immediately) */ ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); if ((ms - oldms) > 50) { lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_DUMB_INCREMENT]); oldms = ms; } #ifdef EXTERNAL_POLL /* * this represents an existing server's single poll action * which also includes libwebsocket sockets */ n = poll(pollfds, count_pollfds, 50); if (n < 0) continue; if (n) for (n = 0; n < count_pollfds; n++) if (pollfds[n].revents) /* * returns immediately if the fd does not * match anything under libwebsockets * control */ if (lws_service_fd(context, &pollfds[n]) < 0) goto done; #else /* * If libwebsockets sockets are all we care about, * you can use this api which takes care of the poll() * and looping through finding who needed service. * * If no socket needs service, it'll return anyway after * the number of ms in the second argument. */ n = lws_service(context, 50); #endif } #ifdef EXTERNAL_POLL done: #endif lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; } |
Added undroid/libwebsockets/test-server/test-server.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * libwebsockets-test-server - libwebsockets test implementation * * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> * * This file is made available under the Creative Commons CC0 1.0 * Universal Public Domain Dedication. * * The person who associated a work with this deed has dedicated * the work to the public domain by waiving all of his or her rights * to the work worldwide under copyright law, including all related * and neighboring rights, to the extent allowed by law. You can copy, * modify, distribute and perform the work, even for commercial purposes, * all without asking permission. * * The test apps are intended to be adapted for use in your code, which * may be proprietary. So unlike the library itself, they are licensed * Public Domain. */ #if defined(_WIN32) && defined(EXTERNAL_POLL) #define WINVER 0x0600 #define _WIN32_WINNT 0x0600 #define poll(fdArray, fds, timeout) WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout)) #endif #include "lws_config.h" #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <signal.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #include "../lib/libwebsockets.h" #ifdef _WIN32 #include <io.h> #include "gettimeofday.h" #else #include <syslog.h> #include <sys/time.h> #include <unistd.h> #endif extern int close_testing; extern int max_poll_elements; #ifdef EXTERNAL_POLL extern struct lws_pollfd *pollfds; extern int *fd_lookup; extern int count_pollfds; #endif extern volatile int force_exit; extern struct lws_context *context; extern char *resource_path; #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) extern char crl_path[1024]; #endif extern void test_server_lock(int care); extern void test_server_unlock(int care); #ifndef __func__ #define __func__ __FUNCTION__ #endif struct per_session_data__http { lws_filefd_type fd; char post_string[256]; #ifdef LWS_WITH_CGI struct lws_cgi_args args; #endif #if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT) int reason_bf; #endif unsigned int client_finished:1; }; /* * one of these is auto-created for each connection and a pointer to the * appropriate instance is passed to the callback in the user parameter * * for this example protocol we use it to individualize the count for each * connection. */ struct per_session_data__dumb_increment { int number; }; struct per_session_data__lws_mirror { struct lws *wsi; int ringbuffer_tail; }; struct per_session_data__echogen { size_t total; size_t total_rx; int fd; int fragsize; int wr; }; struct per_session_data__lws_status { struct per_session_data__lws_status *list; struct timeval tv_established; int last; char ip[270]; char user_agent[512]; const char *pos; int len; }; extern int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); extern int callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); extern int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); extern int callback_lws_echogen(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); extern int callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); extern void dump_handshake_info(struct lws *wsi); |
Added undroid/libwebsockets/test-server/test.html.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <!DOCTYPE html> <html lang="en"> <head> <meta charset=utf-8 http-equiv="Content-Language" content="en"/> <title>Minimal Websocket test app</title> <style type="text/css"> span.title { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#000000; } .browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;} .group2 { vertical-align:middle; text-align:center; background:#f0f0e0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } .explain { vertical-align:middle; text-align:center; background:#f0f0c0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; color:#404000; } td.wsstatus { vertical-align:middle; width:200px; height:50px; text-align:center; background:#f0f0c0; padding:6px; -webkit-border-radius:8px; -moz-border-radius:8px; border-radius:8px; color:#404000; } td.l { vertical-align:middle; text-align:center; background:#d0d0b0; padding:3px; -webkit-border-radius:3px; -moz-border-radius:3px; border-radius:3px; } .content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } .canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } .tabs { position: relative; min-height: 750px; /* This part sucks */ clear: both; margin: 25px 0; } .tab { float: left; } .tab label { background: #eee; padding: 10px; border: 1px solid #ccc; margin-left: -1px; position: relative; left: 1px; } .tab [type=radio] { display: none; } .content { position: absolute; top: 28px; left: 0; background: white; right: 0; bottom: 0; padding: 20px; border: 1px solid #ccc; } [type=radio]:checked ~ label { background: white; border-bottom: 1px solid white; z-index: 2; } [type=radio]:checked ~ label ~ .content { z-index: 1; } </style> </head> <body> <header></header> <article> <table><tr><td> <table width=600px> <tr> <td valign=middle align=center> <a href="https://libwebsockets.org"> <img src="libwebsockets.org-logo.png"></a></td><td> <section class="browser">Detected Browser: <div id=brow>...</div></section> </td> </tr> </table> </td></tr> <tr><td colspan=2 align=center> Click <a href="leaf.jpg" target="_blank">Here</a> to have the test server send a big picture by http. </td></tr> <tr><td colspan=2> <div class="tabs"> <div class="tab"> <input type="radio" id="tab-1" name="tab-group-1" checked> <label for="tab-1">Dumb Increment Demo</label> <div class="content"> <div id="dumb" class="group2"> <table> <tr> <td id=wsdi_statustd align=center class="wsstatus"> <span id=wsdi_status>Websocket connection not initialized</span></td> <td><span class="title">dumb increment-protocol</span></td> </tr> <tr> <td class="explain" colspan=2> The incrementing number is coming from the server at 20Hz and is individual for each connection to the server... try opening a second browser window. <br/><br/> The button sends a message over the websocket link to ask the server to zero just this connection's number. </td> </tr> <tr> <td align=center><div id=number style="font-size:120%;"> </div></td> <td align=center> <input type=button id=offset value="Reset counter" onclick="reset();" > <input type=button id=junk value="Send junk" onclick="junk();" > </td> </tr> </table> </div> </div> </div> <div class="tab"> <input type="radio" id="tab-2" name="tab-group-1"> <label for="tab-2">Mirror Demo</label> <div class="content"> <div id="mirror" class="group2"> <table> <tr> <td colspan=1 id=wslm_statustd align=center class="wsstatus"> <span id=wslm_status>Websocket connection not initialized</span> </td> <td> <span class="title">lws-mirror-protocol</span> </td> </tr> <tr> <td colspan=2> <div class="explain"> Use the mouse to draw on the canvas below -- all other browser windows open on this page see your drawing in realtime and you can see any of theirs as well. <br/><br/> The lws-mirror protocol doesn't interpret what is being sent to it, it just re-sends it to every other websocket it has a connection with using that protocol, including the guy who sent the packet. <br/><br/> <b>libwebsockets-test-client</b> joins in by spamming circles on to this shared canvas when run. </div> </td> </tr> <tr> <td colspan=2>Drawing color: <select id="color" onchange="update_color();"> <option value=#000000>Black</option> <option value=#0000ff>Blue</option> <option value=#20ff20>Green</option> <option value=#802020>Dark Red</option> </select> </tr> <tr> <td colspan=2 width=500 height=320> <div id="wslm_drawing" style="background:white"></div> </td> </tr> </table> </div> </div> </div> <div class="tab"> <input type="radio" id="tab-3" name="tab-group-1"> <label for="tab-3">Close Testing</label> <div class="content"> <div id="ot" class="group2"> <table> <tr> <td> </td></tr> <tr><td id=ot_statustd align=center class="wsstatus"> <span id=ot_status>Websocket connection not initialized</span> </td> <td colspan=2><span class="title">Open and close testing</span></td> </tr> <tr> <td class="explain" colspan=3 style="padding:3"> To help with open and close testing, you can open and close a connection by hand using the buttons.<br> "<b>Close</b>" closes the connection from the browser with code 3000 and reason 'Bye!".<br> "<b>Request Server Close</b>" sends a message asking the server to initiate the close, which it does with code 1001 and reason "Seeya". </td></tr> <tr> <td align=center><input type=button id=ot_open_btn value="Open" onclick="ot_open();" ></td> <td align=center><input type=button id=ot_close_btn disabled value="Close" onclick="ot_close();" ></td> <td align=center><input type=button id=ot_req_close_btn disabled value="Request Server Close" onclick="ot_req_close();" ></td> </tr> </table> </div> </div> </div> <div class="tab"> <input type="radio" id="tab-4" name="tab-group-1"> <label for="tab-4">Server info</label> <div class="content"> <div id="ot" class="group2"> <table> <tr> <td id=s_statustd align=center class="wsstatus"> <div id=s_status>Websocket connection not initialized</div> </td> <td colspan=1> <span class="title">Server Info</span> </td> </tr><tr> <td class="explain" colspan=2> This information is sent by the server over a ws[s] link and updated live whenever the information changes server-side. </td></tr> <tr> <td align=center colspan=2><div id=servinfo></div></td> </tr> <tr> <td align=center colspan=2><div id=conninfo style="border : solid 2px #e0d040; padding : 4px; width : 500px; height : 350px; overflow : auto; "></</div></td> </tr> </table> </div> </div> </div> <div class="tab"> <input type="radio" id="tab-5" name="tab-group-1"> <label for="tab-5">POST</label> <div class="content"> <div id="ot" class="group2"> <table> <tr> <td colspan=1> <span class="title">POST Form testing</span> </td> </tr><tr> <td class="explain" colspan=2> This tests POST handling in lws. </td></tr> <tr> <td align=center colspan=2><div id=postinfo> <form action="formtest" method="post"> Some text:<br> <input type="text" name="Text" value="Give me some text"><br> <input type="submit" value="Send the form"> </form> </div></td> </tr> </table> </div> </div> </div> </div> </td></tr></table> Looking for support? <a href="https://libwebsockets.org">https://libwebsockets.org</a>, <a href="https://github.com/warmcat/libwebsockets">https://github.com/warmcat/libwebsockets</a></a><br/> Join the mailing list: <a href="https://libwebsockets.org/mailman/listinfo/libwebsockets">https://libwebsockets.org/mailman/listinfo/libwebsockets</a> </article> <script> /* * We display untrusted stuff in html context... reject anything * that has HTML stuff in it */ function san(s) { if (s.search("<") != -1) return "invalid string"; return s; } /* BrowserDetect came from http://www.quirksmode.org/js/detect.html */ var BrowserDetect = { init: function () { this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version"; this.OS = this.searchString(this.dataOS) || "an unknown OS"; }, searchString: function (data) { for (var i=0;i<data.length;i++) { var dataString = data[i].string; var dataProp = data[i].prop; this.versionSearchString = data[i].versionSearch || data[i].identity; if (dataString) { if (dataString.indexOf(data[i].subString) != -1) return data[i].identity; } else if (dataProp) return data[i].identity; } }, searchVersion: function (dataString) { var index = dataString.indexOf(this.versionSearchString); if (index == -1) return; return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); }, dataBrowser: [ { string: navigator.userAgent, subString: "Chrome", identity: "Chrome" }, { string: navigator.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" }, { string: navigator.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version" }, { prop: window.opera, identity: "Opera", versionSearch: "Version" }, { string: navigator.vendor, subString: "iCab", identity: "iCab" }, { string: navigator.vendor, subString: "KDE", identity: "Konqueror" }, { string: navigator.userAgent, subString: "Firefox", identity: "Firefox" }, { string: navigator.vendor, subString: "Camino", identity: "Camino" }, { // for newer Netscapes (6+) string: navigator.userAgent, subString: "Netscape", identity: "Netscape" }, { string: navigator.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" }, { string: navigator.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" }, { // for older Netscapes (4-) string: navigator.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" } ], dataOS : [ { string: navigator.platform, subString: "Win", identity: "Windows" }, { string: navigator.platform, subString: "Mac", identity: "Mac" }, { string: navigator.userAgent, subString: "iPhone", identity: "iPhone/iPod" }, { string: navigator.platform, subString: "Linux", identity: "Linux" } ] }; BrowserDetect.init(); document.getElementById("brow").textContent = " " + BrowserDetect.browser + " " + BrowserDetect.version +" " + BrowserDetect.OS +" "; var pos = 0; function get_appropriate_ws_url() { var pcol; var u = document.URL; /* * We open the websocket encrypted if this page came on an * https:// url itself, otherwise unencrypted */ if (u.substring(0, 5) == "https") { pcol = "wss://"; u = u.substr(8); } else { pcol = "ws://"; if (u.substring(0, 4) == "http") u = u.substr(7); } u = u.split('/'); /* + "/xxx" bit is for IE10 workaround */ return pcol + u[0] + "/xxx"; } document.getElementById("number").textContent = get_appropriate_ws_url(); /* dumb increment protocol */ var socket_di; if (typeof MozWebSocket != "undefined") { socket_di = new MozWebSocket(get_appropriate_ws_url(), "dumb-increment-protocol"); } else { socket_di = new WebSocket(get_appropriate_ws_url(), "dumb-increment-protocol"); } try { socket_di.onopen = function() { document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40"; document.getElementById("wsdi_status").innerHTML = " <b>websocket connection opened</b><br>" + san(socket_di.extensions); } socket_di.onmessage =function got_packet(msg) { document.getElementById("number").textContent = msg.data + "\n"; } socket_di.onclose = function(){ document.getElementById("wsdi_statustd").style.backgroundColor = "#ff4040"; document.getElementById("wsdi_status").textContent = " websocket connection CLOSED "; } } catch(exception) { alert('<p>Error' + exception); } var socket_status, jso, s; if (typeof MozWebSocket != "undefined") { socket_status = new MozWebSocket(get_appropriate_ws_url(), "lws-status"); } else { socket_status = new WebSocket(get_appropriate_ws_url(), "lws-status"); } try { socket_status.onopen = function() { document.getElementById("s_statustd").style.backgroundColor = "#40ff40"; document.getElementById("s_status").innerHTML = " <b>websocket connection opened</b><br>" + san(socket_status.extensions); } socket_status.onmessage =function got_packet(msg) { jso = JSON.parse(msg.data); document.getElementById("servinfo").innerHTML = "<table><tr><td class=l>Build info</td><td>"+ san(jso.version) + "</td></tr>" + "<tr><td class=l>Server info</td><td>" + san(jso.hostname) + "</td></tr>" + "</table>"; s="<table>"; var n; for (n = 0; n < jso.conns.length; n++) s = s + "<tr><td class=l>client " + (n + 1) + "</td><td><b>" + san(jso.conns[n].peer) + "</b><br>" + san(jso.conns[n].time) + "<br>" + san(jso.conns[n].ua) + "</td></tr>"; s = s + "</table>"; document.getElementById("conninfo").innerHTML = s; } socket_status.onclose = function(){ document.getElementById("s_statustd").style.backgroundColor = "#ff4040"; document.getElementById("s_status").textContent = " websocket connection CLOSED "; } } catch(exception) { alert('<p>Error' + exception); } function reset() { socket_di.send("reset\n"); } function junk() { for(var word = ''; word.length < 9000; word += 'a'){} socket_di.send(word); } var socket_ot; function ot_open() { if (typeof MozWebSocket != "undefined") { socket_ot = new MozWebSocket(get_appropriate_ws_url(), "dumb-increment-protocol"); } else { socket_ot = new WebSocket(get_appropriate_ws_url(), "dumb-increment-protocol"); } try { socket_ot.onopen = function() { document.getElementById("ot_statustd").style.backgroundColor = "#40ff40"; document.getElementById("ot_status").innerHTML = " <b>websocket connection opened</b><br>" + san(socket_di.extensions); document.getElementById("ot_open_btn").disabled = true; document.getElementById("ot_close_btn").disabled = false; document.getElementById("ot_req_close_btn").disabled = false; } socket_ot.onclose = function(e){ document.getElementById("ot_statustd").style.backgroundColor = "#ff4040"; document.getElementById("ot_status").textContent = " websocket connection CLOSED, code: " + e.code + ", reason: " + e.reason; document.getElementById("ot_open_btn").disabled = false; document.getElementById("ot_close_btn").disabled = true; document.getElementById("ot_req_close_btn").disabled = true; } } catch(exception) { alert('<p>Error' + exception); } } /* browser will close the ws in a controlled way */ function ot_close() { socket_ot.close(3000, "Bye!"); } /* we ask the server to close the ws in a controlled way */ function ot_req_close() { socket_ot.send("closeme\n"); } /* lws-mirror protocol */ var down = 0; var no_last = 1; var last_x = 0, last_y = 0; var ctx; var socket_lm; var color = "#000000"; if (typeof MozWebSocket != "undefined") { socket_lm = new MozWebSocket(get_appropriate_ws_url(), "lws-mirror-protocol"); } else { socket_lm = new WebSocket(get_appropriate_ws_url(), "lws-mirror-protocol"); } try { socket_lm.onopen = function() { document.getElementById("wslm_statustd").style.backgroundColor = "#40ff40"; document.getElementById("wslm_status").innerHTML = " <b>websocket connection opened</b><br>" + san(socket_lm.extensions); } socket_lm.onmessage =function got_packet(msg) { j = msg.data.split(';'); f = 0; while (f < j.length - 1) { i = j[f].split(' '); if (i[0] == 'd') { ctx.strokeStyle = i[1]; ctx.beginPath(); ctx.moveTo(+(i[2]), +(i[3])); ctx.lineTo(+(i[4]), +(i[5])); ctx.stroke(); } if (i[0] == 'c') { ctx.strokeStyle = i[1]; ctx.beginPath(); ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true); ctx.stroke(); } f++; } } socket_lm.onclose = function(){ document.getElementById("wslm_statustd").style.backgroundColor = "#ff4040"; document.getElementById("wslm_status").textContent = " websocket connection CLOSED "; } } catch(exception) { alert('<p>Error' + exception); } var canvas = document.createElement('canvas'); canvas.height = 300; canvas.width = 480; ctx = canvas.getContext("2d"); document.getElementById('wslm_drawing').appendChild(canvas); canvas.addEventListener('mousemove', ev_mousemove, false); canvas.addEventListener('mousedown', ev_mousedown, false); canvas.addEventListener('mouseup', ev_mouseup, false); offsetX = offsetY = 0; element = canvas; if (element.offsetParent) { do { offsetX += element.offsetLeft; offsetY += element.offsetTop; } while ((element = element.offsetParent)); } function update_color() { color = document.getElementById("color").value; } function ev_mousedown (ev) { down = 1; } function ev_mouseup(ev) { down = 0; no_last = 1; } function ev_mousemove (ev) { var x, y; if (ev.offsetX) { x = ev.offsetX; y = ev.offsetY; } else { x = ev.layerX - offsetX; y = ev.layerY - offsetY; } if (!down) return; if (no_last) { no_last = 0; last_x = x; last_y = y; return; } socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y + ';'); last_x = x; last_y = y; } </script> </body> </html> |
Added undroid/libwebsockets/travis_install.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/bin/bash if [ "$COVERITY_SCAN_BRANCH" == 1 ]; then exit; fi if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq if [ "$LWS_METHOD" == "libev" ]; then sudo apt-get install -y -qq libev-dev; fi if [ "$LWS_METHOD" == "libuv" -o "$LWS_METHOD" == "lwsws" ]; then sudo apt-get install -y -qq libuv-dev; fi fi if [ "$TRAVIS_OS_NAME" == "osx" ]; then if [ "$LWS_METHOD" == "libev" ]; then brew install libev; fi if [ "$LWS_METHOD" == "libuv" -o "$LWS_METHOD" == "lwsws" ]; then brew install libuv; fi fi |
Added undroid/libwebsockets/win32port/libwebsockets.nsi.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ; NSIS installer script for libwebsockets !include "MUI.nsh" Name "libwebsockets" OutFile "libwebsockets-${VERSION}-install.exe" InstallDir "$PROGRAMFILES\libwebsockets" ;-------------------------------- ; Installer pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH ;-------------------------------- ; Uninstaller pages !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH ;-------------------------------- ; Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- ; Installer sections Section "Files" SecInstall SectionIn RO SetOutPath "$INSTDIR" File "..\libwebsockets-api-doc.html" File "..\LICENSE" File "..\README.md" File "..\README.build.md" File "..\README.coding.md" File "..\README.test-apps.md" File /nonfatal "..\build\bin\Release\libwebsockets-test-client.exe" File /nonfatal "..\build\bin\Release\libwebsockets-test-echo.exe" File /nonfatal "..\build\bin\Release\libwebsockets-test-fraggle.exe" File /nonfatal "..\build\bin\Release\libwebsockets-test-ping.exe" File /nonfatal "..\build\bin\Release\libwebsockets-test-server.exe" File /nonfatal "..\build\bin\Release\libwebsockets-test-server-extpoll.exe" File /nonfatal "..\build\bin\Release\websockets.dll" File /nonfatal "..\build\bin\Release\websockets_shared.dll" SetOutPath "$INSTDIR\libwebsockets-test-server" File /nonfatal "..\build\bin\share\libwebsockets-test-server\favicon.ico" File /nonfatal "..\build\bin\share\libwebsockets-test-server\leaf.jpg" File /nonfatal "..\build\bin\share\libwebsockets-test-server\libwebsockets.org-logo.png" File /nonfatal "..\build\bin\share\libwebsockets-test-server\libwebsockets-test-server.key.pem" File /nonfatal "..\build\bin\share\libwebsockets-test-server\libwebsockets-test-server.pem" File /nonfatal "..\build\bin\share\libwebsockets-test-server\test.html" SetOutPath "$INSTDIR\lib" File /nonfatal "..\build\lib\Release\websockets.lib" File /nonfatal "..\build\lib\Release\websockets_static.lib" File /nonfatal "..\build\lib\Release\websockets_shared.lib" File /nonfatal "..\build\lib\Release\websockets.lib" SetOutPath "$INSTDIR\include" File "..\lib\libwebsockets.h" WriteUninstaller "$INSTDIR\Uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "DisplayName" "libwebsockets library and clients" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "HelpLink" "https://libwebsockets.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "URLInfoAbout" "http://libwebsockets.org/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "DisplayVersion" "${VERSION}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "NoModify" "1" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "NoRepair" "1" SectionEnd Section "Uninstall" Delete "$INSTDIR\libwebsockets-api-doc.html" Delete "$INSTDIR\LICENSE" Delete "$INSTDIR\README.md" Delete "$INSTDIR\README.build.md" Delete "$INSTDIR\README.coding.md" Delete "$INSTDIR\README.test-apps.md" Delete "$INSTDIR\libwebsockets-test-client.exe" Delete "$INSTDIR\libwebsockets-test-echo.exe" Delete "$INSTDIR\libwebsockets-test-fraggle.exe" Delete "$INSTDIR\libwebsockets-test-ping.exe" Delete "$INSTDIR\libwebsockets-test-server.exe" Delete "$INSTDIR\libwebsockets-test-server-extpoll.exe" Delete "$INSTDIR\websockets.dll" Delete "$INSTDIR\libwebsockets-test-server\favicon.ico" Delete "$INSTDIR\libwebsockets-test-server\leaf.jpg" Delete "$INSTDIR\libwebsockets-test-server\libwebsockets.org-logo.png" Delete "$INSTDIR\libwebsockets-test-server\libwebsockets-test-server.key.pem" Delete "$INSTDIR\libwebsockets-test-server\libwebsockets-test-server.pem" Delete "$INSTDIR\libwebsockets-test-server\test.html" RMDir "$INSTDIR\libwebsockets-test-server" Delete "$INSTDIR\lib\websockets.lib" Delete "$INSTDIR\lib\websockets_static.lib" RMDir "$INSTDIR\lib" Delete "$INSTDIR\include\libwebsockets.h" RMDir "$INSTDIR\include" Delete "$INSTDIR\Uninstall.exe" RMDir "$INSTDIR" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" SectionEnd LangString DESC_SecInstall ${LANG_ENGLISH} "The main installation." !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall) !insertmacro MUI_FUNCTION_DESCRIPTION_END |
Added undroid/libwebsockets/win32port/win32helpers/getopt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */ /* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; #endif #include <assert.h> #include <errno.h> #include <stdio.h> #include <string.h> #define __P(x) x #define _DIAGASSERT(x) assert(x) #ifdef __weak_alias __weak_alias(getopt,_getopt); #endif int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ static char * _progname __P((char *)); int getopt_internal __P((int, char * const *, const char *)); static char * _progname(nargv0) char * nargv0; { char * tmp; _DIAGASSERT(nargv0 != NULL); tmp = strrchr(nargv0, '/'); if (tmp) tmp++; else tmp = nargv0; return(tmp); } #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const nargv[]; const char *ostr; { static char *__progname = 0; static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ __progname = __progname?__progname:_progname(*nargv); _DIAGASSERT(nargv != NULL); _DIAGASSERT(ostr != NULL); if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-' /* found "--" */ && place[1] == '\0') { ++optind; place = EMSG; return (-1); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (optopt == (int)'-') return (-1); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } |
Added undroid/libwebsockets/win32port/win32helpers/getopt.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #ifndef __GETOPT_H__ #define __GETOPT_H__ #ifdef __cplusplus extern "C" { #endif extern int opterr; /* if error message should be printed */ extern int optind; /* index into parent argv vector */ extern int optopt; /* character checked for validity */ extern int optreset; /* reset getopt */ extern char *optarg; /* argument associated with option */ struct option { const char *name; int has_arg; int *flag; int val; }; #define no_argument 0 #define required_argument 1 #define optional_argument 2 int getopt(int, char**, char*); int getopt_long(int, char**, char*, struct option*, int*); #ifdef __cplusplus } #endif #endif /* __GETOPT_H__ */ |
Added undroid/libwebsockets/win32port/win32helpers/getopt_long.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * Copyright (c) 1987, 1993, 1994, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <assert.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "getopt.h" extern int opterr; /* if error message should be printed */ extern int optind; /* index into parent argv vector */ extern int optopt; /* character checked for validity */ extern int optreset; /* reset getopt */ extern char *optarg; /* argument associated with option */ #define __P(x) x #define _DIAGASSERT(x) assert(x) static char * __progname __P((char *)); int getopt_internal __P((int, char * const *, const char *)); static char * __progname(nargv0) char * nargv0; { char * tmp; _DIAGASSERT(nargv0 != NULL); tmp = strrchr(nargv0, '/'); if (tmp) tmp++; else tmp = nargv0; return(tmp); } #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt_internal(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ _DIAGASSERT(nargv != NULL); _DIAGASSERT(ostr != NULL); if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ /* ++optind; */ place = EMSG; return (-2); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (optopt == (int)'-') return (-1); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname(nargv[0]), optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if ((opterr) && (*ostr != ':')) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname(nargv[0]), optopt); return (BADARG); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } #if 0 /* * getopt -- * Parse argc/argv argument vector. */ int getopt2(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { int retval; if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) { retval = -1; ++optind; } return(retval); } #endif /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(nargc, nargv, options, long_options, index) int nargc; char ** nargv; char * options; struct option * long_options; int * index; { int retval; _DIAGASSERT(nargv != NULL); _DIAGASSERT(options != NULL); _DIAGASSERT(long_options != NULL); /* index may be NULL */ if ((retval = getopt_internal(nargc, nargv, options)) == -2) { char *current_argv = nargv[optind++] + 2, *has_equal; int i, current_argv_len, match = -1; if (*current_argv == '\0') { return(-1); } if ((has_equal = strchr(current_argv, '=')) != NULL) { current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == (unsigned)current_argv_len) { match = i; break; } if (match == -1) match = i; } if (match != -1) { if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else optarg = nargv[optind++]; } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument, leading : * indicates no error should be generated */ if ((opterr) && (*options != ':')) (void)fprintf(stderr, "%s: option requires an argument -- %s\n", __progname(nargv[0]), current_argv); return (BADARG); } } else { /* No matching argument */ if ((opterr) && (*options != ':')) (void)fprintf(stderr, "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv); return (BADCH); } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (index) *index = match; } return(retval); } |
Added undroid/libwebsockets/win32port/win32helpers/gettimeofday.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include <time.h> #include <windows.h> //I've omitted context line #include "gettimeofday.h" int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; /*converting file time to unix epoch*/ tmpres /= 10; /*convert into microseconds*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } |
Added undroid/libwebsockets/win32port/win32helpers/gettimeofday.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #ifndef _GET_TIME_OF_DAY_H #define _GET_TIME_OF_DAY_H #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif #ifdef LWS_MINGW_SUPPORT #include <winsock2.h> #endif #ifndef _TIMEZONE_DEFINED struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; int gettimeofday(struct timeval *tv, struct timezone *tz); #endif #endif |
Added undroid/libwebsockets/win32port/zlib/ZLib.vcxproj.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug static|Win32"> <Configuration>Debug static</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Debug|x64"> <Configuration>Debug</Configuration> <Platform>x64</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release DLL|Win32"> <Configuration>Release DLL</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release DLL|x64"> <Configuration>Release DLL</Configuration> <Platform>x64</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release static|Win32"> <Configuration>Release static</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release|Win32"> <Configuration>Release</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release|x64"> <Configuration>Release</Configuration> <Platform>x64</Platform> </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{4156FC56-8443-2973-4FE2-A0BB2C621525}</ProjectGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <UseOfMfc>false</UseOfMfc> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <UseOfMfc>false</UseOfMfc> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release static|Win32'"> <ConfigurationType>StaticLibrary</ConfigurationType> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|x64'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <OutDir>DebugV10\</OutDir> <IntDir>DebugV10\</IntDir> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|Win32'"> <OutDir>$(SolutionDir)..\output\</OutDir> <IntDir>DebugV10\</IntDir> <TargetName>ZLib_vc100-mt-sgd</TargetName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <OutDir>DebugV10\</OutDir> <IntDir>DebugV10\</IntDir> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|x64'"> <OutDir>DebugV10\</OutDir> <IntDir>DebugV10\</IntDir> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <IntDir>.\Release\</IntDir> <OutDir>.\Release\</OutDir> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <OutDir>.\Release\</OutDir> <IntDir>.\Release\</IntDir> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release static|Win32'"> <OutDir>$(SolutionDir)..\output\</OutDir> <TargetName>ZLib_vc100-mt-s</TargetName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'"> <OutDir>$(SolutionDir)..\output\</OutDir> <TargetName>ZLib_vc100-mt-s</TargetName> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <InlineFunctionExpansion>Default</InlineFunctionExpansion> <FunctionLevelLinking>false</FunctionLevelLinking> <Optimization>Disabled</Optimization> <SuppressStartupBanner>true</SuppressStartupBanner> <WarningLevel>Level3</WarningLevel> <MinimalRebuild>true</MinimalRebuild> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AssemblerListingLocation>DebugV10\</AssemblerListingLocation> <PrecompiledHeaderOutputFile>DebugV10\ZLib.pch</PrecompiledHeaderOutputFile> <ObjectFileName>DebugV10\</ObjectFileName> <ProgramDataBaseFileName>DebugV10\</ProgramDataBaseFileName> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <ForceConformanceInForLoopScope>false</ForceConformanceInForLoopScope> <ExceptionHandling>false</ExceptionHandling> </ClCompile> <ResourceCompile> <Culture>0x1c09</Culture> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Bscmake> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.bsc</OutputFile> </Bscmake> <Lib> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|Win32'"> <ClCompile> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <InlineFunctionExpansion>Default</InlineFunctionExpansion> <FunctionLevelLinking>false</FunctionLevelLinking> <Optimization>Disabled</Optimization> <SuppressStartupBanner>true</SuppressStartupBanner> <WarningLevel>Level3</WarningLevel> <MinimalRebuild>true</MinimalRebuild> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AssemblerListingLocation>DebugV10\</AssemblerListingLocation> <PrecompiledHeaderOutputFile>DebugV10\ZLib.pch</PrecompiledHeaderOutputFile> <ObjectFileName>DebugV10\</ObjectFileName> <ProgramDataBaseFileName>DebugV10\</ProgramDataBaseFileName> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <ForceConformanceInForLoopScope>false</ForceConformanceInForLoopScope> <ExceptionHandling>false</ExceptionHandling> </ClCompile> <ResourceCompile> <Culture>0x1c09</Culture> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Bscmake> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.bsc</OutputFile> </Bscmake> <Lib> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>$(OutDir)ZLib_vc100-mt-sgd.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <InlineFunctionExpansion>Default</InlineFunctionExpansion> <FunctionLevelLinking>false</FunctionLevelLinking> <Optimization>Disabled</Optimization> <SuppressStartupBanner>true</SuppressStartupBanner> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AssemblerListingLocation>DebugV10\</AssemblerListingLocation> <PrecompiledHeaderOutputFile>DebugV10\ZLib.pch</PrecompiledHeaderOutputFile> <ObjectFileName>DebugV10\</ObjectFileName> <ProgramDataBaseFileName>DebugV10\</ProgramDataBaseFileName> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <ForceConformanceInForLoopScope>false</ForceConformanceInForLoopScope> </ClCompile> <ResourceCompile> <Culture>0x1c09</Culture> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Bscmake> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.bsc</OutputFile> </Bscmake> <Lib> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug static|x64'"> <ClCompile> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <InlineFunctionExpansion>Default</InlineFunctionExpansion> <FunctionLevelLinking>false</FunctionLevelLinking> <Optimization>Disabled</Optimization> <SuppressStartupBanner>true</SuppressStartupBanner> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AssemblerListingLocation>DebugV10\</AssemblerListingLocation> <PrecompiledHeaderOutputFile>DebugV10\ZLib.pch</PrecompiledHeaderOutputFile> <ObjectFileName>DebugV10\</ObjectFileName> <ProgramDataBaseFileName>DebugV10\</ProgramDataBaseFileName> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <ForceConformanceInForLoopScope>false</ForceConformanceInForLoopScope> </ClCompile> <ResourceCompile> <Culture>0x1c09</Culture> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Bscmake> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.bsc</OutputFile> </Bscmake> <Lib> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>DebugV10\ZLib.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <StringPooling>true</StringPooling> <FunctionLevelLinking>true</FunctionLevelLinking> <Optimization>MaxSpeed</Optimization> <SuppressStartupBanner>true</SuppressStartupBanner> <WarningLevel>Level3</WarningLevel> <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AssemblerListingLocation>.\Release\</AssemblerListingLocation> <PrecompiledHeaderOutputFile>.\Release\ZLib.pch</PrecompiledHeaderOutputFile> <ObjectFileName>.\Release\</ObjectFileName> <ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName> <ForceConformanceInForLoopScope>false</ForceConformanceInForLoopScope> <ExceptionHandling>false</ExceptionHandling> </ClCompile> <ResourceCompile> <Culture>0x1c09</Culture> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Bscmake> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>.\Release\ZLib.bsc</OutputFile> </Bscmake> <Lib> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>.\Release\ZLib.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion> <StringPooling>true</StringPooling> <FunctionLevelLinking>true</FunctionLevelLinking> <Optimization>MaxSpeed</Optimization> <SuppressStartupBanner>true</SuppressStartupBanner> <WarningLevel>Level3</WarningLevel> <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AssemblerListingLocation>.\Release\</AssemblerListingLocation> <PrecompiledHeaderOutputFile>.\Release\ZLib.pch</PrecompiledHeaderOutputFile> <ObjectFileName>.\Release\</ObjectFileName> <ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName> <ForceConformanceInForLoopScope>false</ForceConformanceInForLoopScope> </ClCompile> <ResourceCompile> <Culture>0x1c09</Culture> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ResourceCompile> <Bscmake> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>.\Release\ZLib.bsc</OutputFile> </Bscmake> <Lib> <SuppressStartupBanner>true</SuppressStartupBanner> <OutputFile>.\Release\ZLib.lib</OutputFile> </Lib> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release static|Win32'"> <Lib> <OutputFile>$(OutDir)ZLib_vc100-mt-s.lib</OutputFile> </Lib> <ClCompile> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <ExceptionHandling>false</ExceptionHandling> </ClCompile> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'"> <Lib> <OutputFile>$(OutDir)ZLib_vc100-mt-s.lib</OutputFile> <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration> </Lib> <ClCompile> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> <ExceptionHandling>false</ExceptionHandling> <BufferSecurityCheck>false</BufferSecurityCheck> <WholeProgramOptimization>true</WholeProgramOptimization> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <PreprocessorDefinitions>WIN32</PreprocessorDefinitions> <FunctionLevelLinking>true</FunctionLevelLinking> </ClCompile> </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="adler32.c" /> <ClCompile Include="compress.c" /> <ClCompile Include="crc32.c" /> <ClCompile Include="deflate.c" /> <ClCompile Include="gzclose.c" /> <ClCompile Include="gzlib.c" /> <ClCompile Include="gzread.c" /> <ClCompile Include="gzwrite.c" /> <ClCompile Include="infback.c" /> <ClCompile Include="inffast.c" /> <ClCompile Include="inflate.c" /> <ClCompile Include="inftrees.c" /> <ClCompile Include="trees.c" /> <ClCompile Include="uncompr.c" /> <ClCompile Include="zutil.c" /> </ItemGroup> <ItemGroup> <ClInclude Include="crc32.h" /> <ClInclude Include="deflate.h" /> <ClInclude Include="gzguts.h" /> <ClInclude Include="inffast.h" /> <ClInclude Include="inffixed.h" /> <ClInclude Include="inflate.h" /> <ClInclude Include="inftrees.h" /> <ClInclude Include="trees.h" /> <ClInclude Include="zconf.h" /> <ClInclude Include="zlib.h" /> <ClInclude Include="zutil.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project> |
Added undroid/libwebsockets/win32port/zlib/ZLib.vcxproj.filters.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> <UniqueIdentifier>{2e5deede-b2ef-40bd-950a-a7f7f0fc0413}</UniqueIdentifier> <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions> </Filter> <Filter Include="Header Files"> <UniqueIdentifier>{85d35343-9068-43e8-875e-60b528a03c9b}</UniqueIdentifier> <Extensions>h;hpp;hxx;hm;inl</Extensions> </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="adler32.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="compress.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="crc32.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="deflate.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="inffast.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="inflate.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="inftrees.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="trees.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="uncompr.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="zutil.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="gzlib.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="gzread.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="gzwrite.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="gzclose.c"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="infback.c"> <Filter>Source Files</Filter> </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="deflate.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="inffast.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="inffixed.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="inftrees.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="trees.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="zconf.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="zlib.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="zutil.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="gzguts.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="inflate.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="crc32.h"> <Filter>Header Files</Filter> </ClInclude> </ItemGroup> </Project> |
Added undroid/libwebsockets/win32port/zlib/adler32.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2007 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #define local static local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); #define BASE 65521UL /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware */ #ifdef NO_DIVIDE # define MOD(a) \ do { \ if (a >= (BASE << 16)) a -= (BASE << 16); \ if (a >= (BASE << 15)) a -= (BASE << 15); \ if (a >= (BASE << 14)) a -= (BASE << 14); \ if (a >= (BASE << 13)) a -= (BASE << 13); \ if (a >= (BASE << 12)) a -= (BASE << 12); \ if (a >= (BASE << 11)) a -= (BASE << 11); \ if (a >= (BASE << 10)) a -= (BASE << 10); \ if (a >= (BASE << 9)) a -= (BASE << 9); \ if (a >= (BASE << 8)) a -= (BASE << 8); \ if (a >= (BASE << 7)) a -= (BASE << 7); \ if (a >= (BASE << 6)) a -= (BASE << 6); \ if (a >= (BASE << 5)) a -= (BASE << 5); \ if (a >= (BASE << 4)) a -= (BASE << 4); \ if (a >= (BASE << 3)) a -= (BASE << 3); \ if (a >= (BASE << 2)) a -= (BASE << 2); \ if (a >= (BASE << 1)) a -= (BASE << 1); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD4(a) \ do { \ if (a >= (BASE << 4)) a -= (BASE << 4); \ if (a >= (BASE << 3)) a -= (BASE << 3); \ if (a >= (BASE << 2)) a -= (BASE << 2); \ if (a >= (BASE << 1)) a -= (BASE << 1); \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD4(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD4(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { unsigned long sum1; unsigned long sum2; unsigned rem; /* the derivation of this formula is left as an exercise for the reader */ rem = (unsigned)(len2 % BASE); sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong adler1; uLong adler2; z_off_t len2; { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { return adler32_combine_(adler1, adler2, len2); } |
Added undroid/libwebsockets/win32port/zlib/compress.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* compress.c -- compress a memory buffer * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; int level; { z_stream stream; int err; stream.next_in = (Bytef*)source; stream.avail_in = (uInt)sourceLen; #ifdef MAXSEG_64K /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; #endif stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; err = deflateEnd(&stream); return err; } /* =========================================================================== */ int ZEXPORT compress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound (sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } |
Added undroid/libwebsockets/win32port/zlib/crc32.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). */ #ifdef MAKECRCH # include <stdio.h> # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ #define local static /* Find a four-byte integer type for crc32_little() and crc32_big(). */ #ifndef NOBYFOUR # ifdef STDC /* need ANSI C limits.h to determine sizes */ # include <limits.h> # define BYFOUR # if (UINT_MAX == 0xffffffffUL) typedef unsigned int u4; # else # if (ULONG_MAX == 0xffffffffUL) typedef unsigned long u4; # else # if (USHRT_MAX == 0xffffffffUL) typedef unsigned short u4; # else # undef BYFOUR /* can't find a four-byte integer type! */ # endif # endif # endif # endif /* STDC */ #endif /* !NOBYFOUR */ /* Definitions for doing the crc four data bytes at a time. */ #ifdef BYFOUR # define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \ (((w)&0xff00)<<8)+(((w)&0xff)<<24)) local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, unsigned)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local unsigned long FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const unsigned long FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { unsigned long c; int n, k; unsigned long poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0UL; for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) poly |= 1UL << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (unsigned long)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = REV(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = REV(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const unsigned long FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const unsigned long FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const unsigned long FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const unsigned long FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { u4 endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } #ifdef BYFOUR /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register u4 c; register const u4 FAR *buf4; c = (u4)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const u4 FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *++buf4; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register u4 c; register const u4 FAR *buf4; c = REV((u4)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const u4 FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(REV(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times(mat, vec) unsigned long *mat; unsigned long vec; { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square(square, mat) unsigned long *square; unsigned long *mat; { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { return crc32_combine_(crc1, crc2, len2); } |
Added undroid/libwebsockets/win32port/zlib/crc32.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const unsigned long FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; |
Added undroid/libwebsockets/win32port/zlib/deflate.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 | /* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://www.ietf.org/rfc/rfc1951.txt * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif #ifdef DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ #define EQUAL 0 /* result of memcmp for equal strings */ #ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; int method; int windowBits; int memLevel; int strategy; const char *version; int stream_size; { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; } if (strm->zfree == (free_func)0) strm->zfree = zcfree; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { deflate_state *s; uInt length = dictLength; uInt n; IPos hash_head = 0; if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || strm->state->wrap == 2 || (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) return Z_STREAM_ERROR; s = strm->state; if (s->wrap) strm->adler = adler32(strm->adler, dictionary, dictLength); if (length < MIN_MATCH) return Z_OK; if (length > s->w_size) { length = s->w_size; dictionary += dictLength - length; /* use the tail of the dictionary */ } zmemcpy(s->window, dictionary, length); s->strstart = length; s->block_start = (long)length; /* Insert all strings in the hash table (except for the last two bytes). * s->lookahead stays null, so s->ins_h will be recomputed at the next * call of fill_window. */ s->ins_h = s->window[0]; UPDATE_HASH(s, s->ins_h, s->window[1]); for (n = 0; n <= length - MIN_MATCH; n++) { INSERT_STRING(s, n, hash_head); } if (hash_head) hash_head = 0; /* to make compiler happy */ return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset (strm) z_streamp strm; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); lm_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; strm->state->bi_valid = bits; strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; { deflate_state *s; compress_func func; int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); } if (s->level != level) { s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return err; } /* ========================================================================= */ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) z_streamp strm; int good_length; int max_lazy; int nice_length; int max_chain; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; s->good_match = good_length; s->max_lazy_match = max_lazy; s->nice_match = nice_length; s->max_chain_length = max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; uLong complen, wraplen; Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (strm == Z_NULL || strm->state == Z_NULL) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB (s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes * through this function so some applications may wish to modify it * to avoid allocating a large strm->next_out buffer and copying into it. * (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; { unsigned len = strm->state->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, strm->state->pending_out, len); strm->next_out += len; strm->state->pending_out += len; strm->total_out += len; strm->avail_out -= len; strm->state->pending -= len; if (strm->state->pending == 0) { strm->state->pending_out = strm->state->pending_buf; } } /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; int flush; { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; /* Write the header */ if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } else #endif { uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); s->status = BUSY_STATE; putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); } } #ifdef GZIP if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) break; } put_byte(s, s->gzhead->extra[s->gzindex]); s->gzindex++; } if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (s->gzindex == s->gzhead->extra_len) { s->gzindex = 0; s->status = NAME_STATE; } } else s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) { s->gzindex = 0; s->status = COMMENT_STATE; } } else s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) s->status = HCRC_STATE; } else s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) flush_pending(strm); if (s->pending + 2 <= s->pending_buf_size) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); s->status = BUSY_STATE; } } else s->status = BUSY_STATE; } #endif /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && flush <= old_flush && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : (s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush)); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd (strm) z_streamp strm; { int status; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; if (status != INIT_STATE && status != EXTRA_STATE && status != NAME_STATE && status != COMMENT_STATE && status != HCRC_STATE && status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy (dest, source) z_streamp dest; z_streamp source; { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy(dest, source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy(ds, ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local int read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, strm->next_in, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, strm->next_in, len); } #endif zmemcpy(buf, strm->next_in, len); strm->next_in += len; strm->total_in += len; return (int)len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init (s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #ifndef ASMV /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef DEBUG /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(s, start, match, length) deflate_state *s; IPos start, match; int length; { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(s) deflate_state *s; { register unsigned n, m; register Posf *p; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; /* Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level == 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif more += wsize; } if (s->strm->avail_in == 0) return; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead >= MIN_MATCH) { s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ ulg max_block_size = 0xffff; ulg max_start; if (max_block_size > s->pending_buf_size - 5) { max_block_size = s->pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } Assert(s->block_start >= 0L, "block gone"); s->strstart += s->lookahead; s->lookahead = 0; /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s->lookahead = (uInt)(s->strstart - max_start); s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); } } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest encodable run. */ if (s->lookahead < MAX_MATCH) { fill_window(s); if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (int)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return flush == Z_FINISH ? finish_done : block_done; } |
Added undroid/libwebsockets/win32port/zlib/deflate.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* deflate.h -- internal compression state * Copyright (C) 1995-2010 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73 #define COMMENT_STATE 91 #define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */ Byte method; /* STORED (for zip only) or DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to supress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ int last_eob_len; /* bit length of EOB code for last block */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (length); \ ush dist = (distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ |
Added undroid/libwebsockets/win32port/zlib/gzclose.c.
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose(file) gzFile file; { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } |
Added undroid/libwebsockets/win32port/zlib/gzguts.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS # endif #endif #if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) && !defined(_WIN32) # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include <stdio.h> #include "zlib.h" #ifdef STDC # include <string.h> # include <stdlib.h> # include <limits.h> #endif #include <fcntl.h> #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif #ifdef _MSC_VER # include <io.h> # define vsnprintf _vsnprintf #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include <windows.h> # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifdef STDC # include <errno.h> # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default i/o buffer size -- double this for output when reading */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ z_off64_t pos; /* current position in uncompressed data */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer */ unsigned char *out; /* output buffer (double-sized when reading) */ unsigned char *next; /* next output data to deliver or write */ /* just for reading */ unsigned have; /* amount of output data unused at next */ int eof; /* true if end of input file reached */ z_off64_t start; /* where the gzip data started, for rewinding */ z_off64_t raw; /* where the raw data started, for seeking */ int how; /* 0: get header, 1: copy, 2: decompress */ int direct; /* true if last read direct, false if gzip */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else unsigned ZLIB_INTERNAL gz_intmax OF((void)); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif |
Added undroid/libwebsockets/win32port/zlib/gzio.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* gzio.c -- IO on .gz files * Copyright (C) 1995-2003 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h * * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. */ /* @(#) $Id$ */ #include <stdio.h> #include "zutil.h" #include "gzguts.h" #ifdef NO_DEFLATE /* for compatiblity with old definition */ # define NO_GZCOMPRESS #endif #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif #ifndef Z_BUFSIZE # ifdef MAXSEG_64K # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ # else # define Z_BUFSIZE 16384 # endif #endif #ifndef Z_PRINTF_BUFSIZE # define Z_PRINTF_BUFSIZE 4096 #endif #ifdef __MVS__ # pragma map (fdopen , "\174\174FDOPEN") FILE *fdopen(int, const char *); #endif #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif #define ALLOC(size) malloc(size) #define TRYFREE(p) {if (p) free(p);} static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ typedef struct gz_stream { z_stream stream; int z_err; /* error code for last stream operation */ int z_eof; /* set if end of input file */ FILE *file; /* .gz file */ Byte *inbuf; /* input buffer */ Byte *outbuf; /* output buffer */ uLong crc; /* crc32 of uncompressed data */ char *msg; /* error message */ char *path; /* path name for debugging only */ int transparent; /* 1 if input file is not a .gz file */ char mode; /* 'w' or 'r' */ z_off_t start; /* start of compressed data in file (header skipped) */ z_off_t in; /* bytes into deflate or inflate */ z_off_t out; /* bytes out of deflate or inflate */ int back; /* one character push-back */ int last; /* true if push-back is last character */ } gz_stream; local gzFile gz_open OF((const char *path, const char *mode, int fd)); local int do_flush OF((gzFile file, int flush)); local int get_byte OF((gz_stream *s)); local void check_header OF((gz_stream *s)); local int destroy OF((gz_stream *s)); local void putLong OF((FILE *file, uLong x)); local uLong getLong OF((gz_stream *s)); /* =========================================================================== Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb"). The file is given either by file descriptor or path name (if fd == -1). gz_open returns NULL if the file could not be opened or if there was insufficient memory to allocate the (de)compression state; errno can be checked to distinguish the two cases (if errno is zero, the zlib error is Z_MEM_ERROR). */ local gzFile gz_open (path, mode, fd) const char *path; const char *mode; int fd; { int err; int level = Z_DEFAULT_COMPRESSION; /* compression level */ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ char *p = (char*)mode; gz_stream *s; char fmode[80]; /* copy of mode, without the compression level */ char *m = fmode; if (!path || !mode) return Z_NULL; s = (gz_stream *)ALLOC(sizeof(gz_stream)); if (!s) return Z_NULL; s->stream.zalloc = (alloc_func)0; s->stream.zfree = (free_func)0; s->stream.opaque = (voidpf)0; s->stream.next_in = s->inbuf = Z_NULL; s->stream.next_out = s->outbuf = Z_NULL; s->stream.avail_in = s->stream.avail_out = 0; s->file = NULL; s->z_err = Z_OK; s->z_eof = 0; s->in = 0; s->out = 0; s->back = EOF; s->crc = crc32(0L, Z_NULL, 0); s->msg = NULL; s->transparent = 0; s->path = (char*)ALLOC(strlen(path)+1); if (s->path == NULL) { return destroy(s), (gzFile)Z_NULL; } strcpy(s->path, path); /* do this early for debugging */ s->mode = '\0'; do { if (*p == 'r') s->mode = 'r'; if (*p == 'w' || *p == 'a') s->mode = 'w'; if (*p >= '0' && *p <= '9') { level = *p - '0'; } else if (*p == 'f') { strategy = Z_FILTERED; } else if (*p == 'h') { strategy = Z_HUFFMAN_ONLY; } else if (*p == 'R') { strategy = Z_RLE; } else { *m++ = *p; /* copy the mode */ } } while (*p++ && m != fmode + sizeof(fmode)); if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; if (s->mode == 'w') { #ifdef NO_GZCOMPRESS err = Z_STREAM_ERROR; #else err = deflateInit2(&(s->stream), level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); /* windowBits is passed < 0 to suppress zlib header */ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); #endif if (err != Z_OK || s->outbuf == Z_NULL) { return destroy(s), (gzFile)Z_NULL; } } else { s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); err = inflateInit2(&(s->stream), -MAX_WBITS); /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are * present after the compressed stream. */ if (err != Z_OK || s->inbuf == Z_NULL) { return destroy(s), (gzFile)Z_NULL; } } s->stream.avail_out = Z_BUFSIZE; errno = 0; s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); if (s->file == NULL) { return destroy(s), (gzFile)Z_NULL; } if (s->mode == 'w') { /* Write a very simple .gz header: */ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); s->start = 10L; /* We use 10L instead of ftell(s->file) to because ftell causes an * fflush on some systems. This version of the library doesn't use * start anyway in write mode, so this initialization is not * necessary. */ } else { check_header(s); /* skip the .gz header */ s->start = ftell(s->file) - s->stream.avail_in; } return (gzFile)s; } /* =========================================================================== Opens a gzip (.gz) file for reading or writing. */ gzFile ZEXPORT gzopen (path, mode) const char *path; const char *mode; { return gz_open (path, mode, -1); } /* =========================================================================== Associate a gzFile with the file descriptor fd. fd is not dup'ed here to mimic the behavio(u)r of fdopen. */ gzFile ZEXPORT gzdopen (fd, mode) int fd; const char *mode; { char name[20]; if (fd < 0) return (gzFile)Z_NULL; sprintf(name, "<fd:%d>", fd); /* for debugging */ return gz_open (name, mode, fd); } /* =========================================================================== * Update the compression level and strategy */ int ZEXPORT gzsetparams (file, level, strategy) gzFile file; int level; int strategy; { gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; /* Make room to allow flushing */ if (s->stream.avail_out == 0) { s->stream.next_out = s->outbuf; if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { s->z_err = Z_ERRNO; } s->stream.avail_out = Z_BUFSIZE; } return deflateParams (&(s->stream), level, strategy); } /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int get_byte(s) gz_stream *s; { if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { errno = 0; s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; if (ferror(s->file)) s->z_err = Z_ERRNO; return EOF; } s->stream.next_in = s->inbuf; } s->stream.avail_in--; return *(s->stream.next_in)++; } /* =========================================================================== Check the gzip header of a gz_stream opened for reading. Set the stream mode to transparent if the gzip magic header is not present; set s->err to Z_DATA_ERROR if the magic header is present but the rest of the header is incorrect. IN assertion: the stream s has already been created sucessfully; s->stream.avail_in is zero for the first time, but may be non-zero for concatenated .gz files. */ local void check_header(s) gz_stream *s; { int method; /* method byte */ int flags; /* flags byte */ uInt len; int c; /* Assure two bytes in the buffer so we can peek ahead -- handle case where first byte of header is at the end of the buffer after the last gzip segment */ len = s->stream.avail_in; if (len < 2) { if (len) s->inbuf[0] = s->stream.next_in[0]; errno = 0; len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; s->stream.avail_in += len; s->stream.next_in = s->inbuf; if (s->stream.avail_in < 2) { s->transparent = s->stream.avail_in; return; } } /* Peek ahead to check the gzip magic header */ if (s->stream.next_in[0] != gz_magic[0] || s->stream.next_in[1] != gz_magic[1]) { s->transparent = 1; return; } s->stream.avail_in -= 2; s->stream.next_in += 2; /* Check the rest of the gzip header */ method = get_byte(s); flags = get_byte(s); if (method != Z_DEFLATED || (flags & RESERVED) != 0) { s->z_err = Z_DATA_ERROR; return; } /* Discard time, xflags and OS code: */ for (len = 0; len < 6; len++) (void)get_byte(s); if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ len = (uInt)get_byte(s); len += ((uInt)get_byte(s))<<8; /* len is garbage if EOF but the loop below will quit anyway */ while (len-- != 0 && get_byte(s) != EOF) ; } if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ for (len = 0; len < 2; len++) (void)get_byte(s); } s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; } /* =========================================================================== * Cleanup then free the given gz_stream. Return a zlib error code. Try freeing in the reverse order of allocations. */ local int destroy (s) gz_stream *s; { int err = Z_OK; if (!s) return Z_STREAM_ERROR; TRYFREE(s->msg); if (s->stream.state != NULL) { if (s->mode == 'w') { #ifdef NO_GZCOMPRESS err = Z_STREAM_ERROR; #else err = deflateEnd(&(s->stream)); #endif } else if (s->mode == 'r') { err = inflateEnd(&(s->stream)); } } if (s->file != NULL && fclose(s->file)) { #ifdef ESPIPE if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ #endif err = Z_ERRNO; } if (s->z_err < 0) err = s->z_err; TRYFREE(s->inbuf); TRYFREE(s->outbuf); TRYFREE(s->path); TRYFREE(s); return err; } /* =========================================================================== Reads the given number of uncompressed bytes from the compressed file. gzread returns the number of bytes actually read (0 for end of file). */ int ZEXPORT gzread (file, buf, len) gzFile file; voidp buf; unsigned len; { gz_stream *s = (gz_stream*)file; Bytef *start = (Bytef*)buf; /* starting point for crc computation */ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; if (s->z_err == Z_STREAM_END) return 0; /* EOF */ next_out = (Byte*)buf; s->stream.next_out = (Bytef*)buf; s->stream.avail_out = len; if (s->stream.avail_out && s->back != EOF) { *next_out++ = s->back; s->stream.next_out++; s->stream.avail_out--; s->back = EOF; s->out++; if (s->last) { s->z_err = Z_STREAM_END; return 1; } } while (s->stream.avail_out != 0) { if (s->transparent) { /* Copy first the lookahead bytes: */ uInt n = s->stream.avail_in; if (n > s->stream.avail_out) n = s->stream.avail_out; if (n > 0) { zmemcpy(s->stream.next_out, s->stream.next_in, n); next_out += n; s->stream.next_out = next_out; s->stream.next_in += n; s->stream.avail_out -= n; s->stream.avail_in -= n; } if (s->stream.avail_out > 0) { s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, s->file); } len -= s->stream.avail_out; s->in += len; s->out += len; if (len == 0) s->z_eof = 1; return (int)len; } if (s->stream.avail_in == 0 && !s->z_eof) { errno = 0; s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; if (ferror(s->file)) { s->z_err = Z_ERRNO; break; } } s->stream.next_in = s->inbuf; } s->in += s->stream.avail_in; s->out += s->stream.avail_out; s->z_err = inflate(&(s->stream), Z_NO_FLUSH); s->in -= s->stream.avail_in; s->out -= s->stream.avail_out; if (s->z_err == Z_STREAM_END) { /* Check CRC and original size */ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); start = s->stream.next_out; if (getLong(s) != s->crc) { s->z_err = Z_DATA_ERROR; } else { (void)getLong(s); /* The uncompressed length returned by above getlong() may be * different from s->out in case of concatenated .gz files. * Check for such files: */ check_header(s); if (s->z_err == Z_OK) { inflateReset(&(s->stream)); s->crc = crc32(0L, Z_NULL, 0); } } } if (s->z_err != Z_OK || s->z_eof) break; } s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); return (int)(len - s->stream.avail_out); } /* =========================================================================== Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. */ int ZEXPORT gzgetc(file) gzFile file; { unsigned char c; return gzread(file, &c, 1) == 1 ? c : -1; } /* =========================================================================== Push one byte back onto the stream. */ int ZEXPORT gzungetc(c, file) int c; gzFile file; { gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; s->back = c; s->out--; s->last = (s->z_err == Z_STREAM_END); if (s->last) s->z_err = Z_OK; s->z_eof = 0; return c; } /* =========================================================================== Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. The string is then terminated with a null character. gzgets returns buf, or Z_NULL in case of error. The current implementation is not optimized at all. */ char * ZEXPORT gzgets(file, buf, len) gzFile file; char *buf; int len; { char *b = buf; if (buf == Z_NULL || len <= 0) return Z_NULL; while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; *buf = '\0'; return b == buf && len > 0 ? Z_NULL : b; } #ifndef NO_GZCOMPRESS /* =========================================================================== Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of bytes actually written (0 in case of error). */ int ZEXPORT gzwrite (file, buf, len) gzFile file; voidpc buf; unsigned len; { gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; s->stream.next_in = (Bytef*)buf; s->stream.avail_in = len; while (s->stream.avail_in != 0) { if (s->stream.avail_out == 0) { s->stream.next_out = s->outbuf; if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { s->z_err = Z_ERRNO; break; } s->stream.avail_out = Z_BUFSIZE; } s->in += s->stream.avail_in; s->out += s->stream.avail_out; s->z_err = deflate(&(s->stream), Z_NO_FLUSH); s->in -= s->stream.avail_in; s->out -= s->stream.avail_out; if (s->z_err != Z_OK) break; } s->crc = crc32(s->crc, (const Bytef *)buf, len); return (int)(len - s->stream.avail_in); } /* =========================================================================== Converts, formats, and writes the args to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written (0 in case of error). */ #ifdef STDC #include <stdarg.h> int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) { char buf[Z_PRINTF_BUFSIZE]; va_list va; int len; buf[sizeof(buf) - 1] = 0; va_start(va, format); #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf(buf, format, va); va_end(va); for (len = 0; len < sizeof(buf); len++) if (buf[len] == 0) break; # else len = vsprintf(buf, format, va); va_end(va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf(buf, sizeof(buf), format, va); va_end(va); len = strlen(buf); # else len = vsnprintf(buf, sizeof(buf), format, va); va_end(va); # endif #endif if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) return 0; return gzwrite(file, buf, (unsigned)len); } #else /* not ANSI C */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { char buf[Z_PRINTF_BUFSIZE]; int len; buf[sizeof(buf) - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < sizeof(buf); len++) if (buf[len] == 0) break; # else len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen(buf); # else len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) return 0; return gzwrite(file, buf, len); } #endif /* =========================================================================== Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ int ZEXPORT gzputc(file, c) gzFile file; int c; { unsigned char cc = (unsigned char) c; /* required for big endian systems */ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; } /* =========================================================================== Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ int ZEXPORT gzputs(file, s) gzFile file; const char *s; { return gzwrite(file, (char*)s, (unsigned)strlen(s)); } /* =========================================================================== Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. */ local int do_flush (file, flush) gzFile file; int flush; { uInt len; int done = 0; gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; s->stream.avail_in = 0; /* should be zero already anyway */ for (;;) { len = Z_BUFSIZE - s->stream.avail_out; if (len != 0) { if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { s->z_err = Z_ERRNO; return Z_ERRNO; } s->stream.next_out = s->outbuf; s->stream.avail_out = Z_BUFSIZE; } if (done) break; s->out += s->stream.avail_out; s->z_err = deflate(&(s->stream), flush); s->out -= s->stream.avail_out; /* Ignore the second of two consecutive flushes: */ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; /* deflate has finished flushing only when it hasn't used up * all the available space in the output buffer: */ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; } return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; } int ZEXPORT gzflush (file, flush) gzFile file; int flush; { gz_stream *s = (gz_stream*)file; int err = do_flush (file, flush); if (err) return err; fflush(s->file); return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; } #endif /* NO_GZCOMPRESS */ /* =========================================================================== Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error. SEEK_END is not implemented, returns error. In this version of the library, gzseek can be extremely slow. */ z_off_t ZEXPORT gzseek (file, offset, whence) gzFile file; z_off_t offset; int whence; { gz_stream *s = (gz_stream*)file; if (s == NULL || whence == SEEK_END || s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { return -1L; } if (s->mode == 'w') { #ifdef NO_GZCOMPRESS return -1L; #else if (whence == SEEK_SET) { offset -= s->in; } if (offset < 0) return -1L; /* At this point, offset is the number of zero bytes to write. */ if (s->inbuf == Z_NULL) { s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ if (s->inbuf == Z_NULL) return -1L; zmemzero(s->inbuf, Z_BUFSIZE); } while (offset > 0) { uInt size = Z_BUFSIZE; if (offset < Z_BUFSIZE) size = (uInt)offset; size = gzwrite(file, s->inbuf, size); if (size == 0) return -1L; offset -= size; } return s->in; #endif } /* Rest of function is for reading only */ /* compute absolute position */ if (whence == SEEK_CUR) { offset += s->out; } if (offset < 0) return -1L; if (s->transparent) { /* map to fseek */ s->back = EOF; s->stream.avail_in = 0; s->stream.next_in = s->inbuf; if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; s->in = s->out = offset; return offset; } /* For a negative seek, rewind and use positive seek */ if (offset >= s->out) { offset -= s->out; } else if (gzrewind(file) < 0) { return -1L; } /* offset is now the number of bytes to skip. */ if (offset != 0 && s->outbuf == Z_NULL) { s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); if (s->outbuf == Z_NULL) return -1L; } if (offset && s->back != EOF) { s->back = EOF; s->out++; offset--; if (s->last) s->z_err = Z_STREAM_END; } while (offset > 0) { int size = Z_BUFSIZE; if (offset < Z_BUFSIZE) size = (int)offset; size = gzread(file, s->outbuf, (uInt)size); if (size <= 0) return -1L; offset -= size; } return s->out; } /* =========================================================================== Rewinds input file. */ int ZEXPORT gzrewind (file) gzFile file; { gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'r') return -1; s->z_err = Z_OK; s->z_eof = 0; s->back = EOF; s->stream.avail_in = 0; s->stream.next_in = s->inbuf; s->crc = crc32(0L, Z_NULL, 0); if (!s->transparent) (void)inflateReset(&s->stream); s->in = 0; s->out = 0; return fseek(s->file, s->start, SEEK_SET); } /* =========================================================================== Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream. */ z_off_t ZEXPORT gztell (file) gzFile file; { return gzseek(file, 0L, SEEK_CUR); } /* =========================================================================== Returns 1 when EOF has previously been detected reading the given input stream, otherwise zero. */ int ZEXPORT gzeof (file) gzFile file; { gz_stream *s = (gz_stream*)file; /* With concatenated compressed files that can have embedded * crc trailers, z_eof is no longer the only/best indicator of EOF * on a gz_stream. Handle end-of-stream error explicitly here. */ if (s == NULL || s->mode != 'r') return 0; if (s->z_eof) return 1; return s->z_err == Z_STREAM_END; } /* =========================================================================== Outputs a long in LSB order to the given file */ local void putLong (file, x) FILE *file; uLong x; { int n; for (n = 0; n < 4; n++) { fputc((int)(x & 0xff), file); x >>= 8; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets z_err in case of error. */ local uLong getLong (s) gz_stream *s; { uLong x = (uLong)get_byte(s); int c; x += ((uLong)get_byte(s))<<8; x += ((uLong)get_byte(s))<<16; c = get_byte(s); if (c == EOF) s->z_err = Z_DATA_ERROR; x += ((uLong)c)<<24; return x; } /* =========================================================================== Flushes all pending output if necessary, closes the compressed file and deallocates all the (de)compression state. */ int ZEXPORT gzclose (file) gzFile file; { int err; gz_stream *s = (gz_stream*)file; if (s == NULL) return Z_STREAM_ERROR; if (s->mode == 'w') { #ifdef NO_GZCOMPRESS return Z_STREAM_ERROR; #else err = do_flush (file, Z_FINISH); if (err != Z_OK) return destroy((gz_stream*)file); putLong (s->file, s->crc); putLong (s->file, (uLong)(s->in & 0xffffffff)); #endif } return destroy((gz_stream*)file); } /* =========================================================================== Returns the error message for the last error which occured on the given compressed file. errnum is set to zlib error number. If an error occured in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. */ const char * ZEXPORT gzerror (file, errnum) gzFile file; int *errnum; { char *m; gz_stream *s = (gz_stream*)file; if (s == NULL) { *errnum = Z_STREAM_ERROR; return (const char*)ERR_MSG(Z_STREAM_ERROR); } *errnum = s->z_err; if (*errnum == Z_OK) return (const char*)""; m = (char*)(*errnum == Z_ERRNO ? zstrerror() : s->stream.msg); if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); TRYFREE(s->msg); s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); strcpy(s->msg, s->path); strcat(s->msg, ": "); strcat(s->msg, m); return (const char*)s->msg; } /* =========================================================================== Clear the error and end-of-file flags, and do the same for the real file. */ void ZEXPORT gzclearerr (file) gzFile file; { gz_stream *s = (gz_stream*)file; if (s == NULL) return; if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; s->z_eof = 0; clearerr(s->file); } |
Added undroid/libwebsockets/win32port/zlib/gzlib.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif /* Local functions */ local void gz_reset OF((gz_statep)); local gzFile gz_open OF((const char *, int, const char *)); #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror (error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset(state) gz_statep state; { if (state->mode == GZ_READ) { /* for reading ... */ state->have = 0; /* no output data available */ state->eof = 0; /* not at end of file */ state->how = LOOK; /* look for gzip header */ state->direct = 1; /* default for empty file */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(path, fd, mode) const char *path; int fd; const char *mode; { gz_statep state; /* allocate gzFile structure to return */ state = malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* save the path name for error messages */ state->path = malloc(strlen(path) + 1); if (state->path == NULL) { free(state); return NULL; } strcpy(state->path, path); /* open the file with the appropriate mode (or just use fd) */ state->fd = fd != -1 ? fd : open(path, #ifdef O_LARGEFILE O_LARGEFILE | #endif #ifdef O_BINARY O_BINARY | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | ( state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))), 0666); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) state->mode = GZ_WRITE; /* simplify later checks */ /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen(fd, mode) int fd; const char *mode; { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL) return NULL; sprintf(path, "<fd:%d>", fd); /* for debugging */ gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ int ZEXPORT gzbuffer(file, size) gzFile file; unsigned size; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if (size == 0) return -1; state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || state->err != Z_OK) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64(file, offset, whence) gzFile file; z_off64_t offset; int whence; { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->pos + offset >= state->raw) { ret = LSEEK(state->fd, offset - state->have, SEEK_CUR); if (ret == -1) return -1; state->have = 0; state->eof = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->pos += offset; return state->pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->have) || (z_off64_t)state->have > offset ? (unsigned)offset : state->have; state->have -= n; state->next += n; state->pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek(file, offset, whence) gzFile file; z_off_t offset; int whence; { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell(file) gzFile file; { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64(file) gzFile file; { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset(file) gzFile file; { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror(file, errnum) gzFile file; int *errnum; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->msg == NULL ? "" : state->msg; } /* -- see zlib.h -- */ void ZEXPORT gzclearerr(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) state->eof = 0; gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error(state, err, msg) gz_statep state; int err; const char *msg; { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, save as static string */ if (err == Z_MEM_ERROR) { state->msg = (char *)msg; return; } /* construct error message with path */ if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; state->msg = (char *)"out of memory"; return; } strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); return; } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax() { unsigned p, q; p = 1; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; } #endif |
Added undroid/libwebsockets/win32port/zlib/gzread.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); local int gz_next4 OF((gz_statep, unsigned long *)); local int gz_head OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_make OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load(state, buf, len, have) gz_statep state; unsigned char *buf; unsigned len; unsigned *have; { int ret; *have = 0; do { ret = read(state->fd, buf + *have, len - *have); if (ret <= 0) break; *have += ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. gz_avail() assumes that strm->avail_in == 0. */ local int gz_avail(state) gz_statep state; { z_streamp strm = &(state->strm); if (state->err != Z_OK) return -1; if (state->eof == 0) { if (gz_load(state, state->in, state->size, (unsigned *)&(strm->avail_in)) == -1) return -1; strm->next_in = state->in; } return 0; } /* Get next byte from input, or -1 if end or error. */ #define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \ (strm->avail_in == 0 ? -1 : \ (strm->avail_in--, *(strm->next_in)++))) /* Get a four-byte little-endian integer and return 0 on success and the value in *ret. Otherwise -1 is returned and *ret is not modified. */ local int gz_next4(state, ret) gz_statep state; unsigned long *ret; { int ch; unsigned long val; z_streamp strm = &(state->strm); val = NEXT(); val += (unsigned)NEXT() << 8; val += (unsigned long)NEXT() << 16; ch = NEXT(); if (ch == -1) return -1; val += (unsigned long)ch << 24; *ret = val; return 0; } /* Look for gzip header, set up for inflate or copy. state->have must be zero. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression, and the gzip header will be skipped so that the next available input data is the raw deflate stream. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state and the check value will be initialized. gz_head() will return 0 on success or -1 on failure. Failures may include read errors or gzip header errors. */ local int gz_head(state) gz_statep state; { z_streamp strm = &(state->strm); int flags; unsigned len; /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = malloc(state->want); state->out = malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { if (state->out != NULL) free(state->out); if (state->in != NULL) free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get some data in the input buffer */ if (strm->avail_in == 0) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for the gzip magic header bytes 31 and 139 */ if (strm->next_in[0] == 31) { strm->avail_in--; strm->next_in++; if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in && strm->next_in[0] == 139) { /* we have a gzip header, woo hoo! */ strm->avail_in--; strm->next_in++; /* skip rest of header */ if (NEXT() != 8) { /* compression method */ gz_error(state, Z_DATA_ERROR, "unknown compression method"); return -1; } flags = NEXT(); if (flags & 0xe0) { /* reserved flag bits */ gz_error(state, Z_DATA_ERROR, "unknown header flags set"); return -1; } NEXT(); /* modification time */ NEXT(); NEXT(); NEXT(); NEXT(); /* extra flags */ NEXT(); /* operating system */ if (flags & 4) { /* extra field */ len = (unsigned)NEXT(); len += (unsigned)NEXT() << 8; while (len--) if (NEXT() < 0) break; } if (flags & 8) /* file name */ while (NEXT() > 0) ; if (flags & 16) /* comment */ while (NEXT() > 0) ; if (flags & 2) { /* header crc */ NEXT(); NEXT(); } /* an unexpected end of file is not checked for here -- it will be noticed on the first request for uncompressed data */ /* set up for decompression */ inflateReset(strm); strm->adler = crc32(0L, Z_NULL, 0); state->how = GZIP; state->direct = 0; return 0; } else { /* not a gzip file -- save first byte (31) and fall to raw i/o */ state->out[0] = 31; state->have = 1; } } /* doing raw i/o, save start of raw data for seeking, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->raw = state->pos; state->next = state->out; if (strm->avail_in) { memcpy(state->next + state->have, strm->next_in, strm->avail_in); state->have += strm->avail_in; strm->avail_in = 0; } state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. If the end of the compressed data is reached, then verify the gzip trailer check value and length (modulo 2^32). state->have and state->next are set to point to the just decompressed data, and the crc is updated. If the trailer is verified, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->have is depleted. Returns 0 on success, -1 on failure. Failures may include invalid compressed data or a failed gzip trailer verification. */ local int gz_decomp(state) gz_statep state; { int ret; unsigned had; unsigned long crc, len; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_DATA_ERROR, "unexpected end of file"); return -1; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output and crc check value */ state->have = had - strm->avail_out; state->next = strm->next_out - state->have; strm->adler = crc32(strm->adler, state->next, state->have); /* check gzip trailer if at end of deflate stream */ if (ret == Z_STREAM_END) { if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) { gz_error(state, Z_DATA_ERROR, "unexpected end of file"); return -1; } if (crc != strm->adler) { gz_error(state, Z_DATA_ERROR, "incorrect data check"); return -1; } if (len != (strm->total_out & 0xffffffffL)) { gz_error(state, Z_DATA_ERROR, "incorrect length check"); return -1; } state->how = LOOK; /* ready for next stream, once have is 0 (leave state->direct unchanged to remember how) */ } /* good decompression */ return 0; } /* Make data and put in the output buffer. Assumes that state->have == 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for (and skipped if found) to determine wither to copy or decompress. Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_make(state) gz_statep state; { z_streamp strm = &(state->strm); if (state->how == LOOK) { /* look for gzip header */ if (gz_head(state) == -1) return -1; if (state->have) /* got some data from gz_head() */ return 0; } if (state->how == COPY) { /* straight copy */ if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1) return -1; state->next = state->out; } else if (state->how == GZIP) { /* decompress */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip(state, len) gz_statep state; z_off64_t len; { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->have) { n = GT_OFF(state->have) || (z_off64_t)state->have > len ? (unsigned)len : state->have; state->have -= n; state->next += n; state->pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_make(state) == -1) return -1; } return 0; } /* -- see zlib.h -- */ int ZEXPORT gzread(file, buf, len) gzFile file; voidp buf; unsigned len; { unsigned got, n; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || state->err != Z_OK) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); return -1; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* first just try copying data from the output buffer */ if (state->have) { n = state->have > len ? len : state->have; memcpy(buf, state->next, n); state->next += n; state->have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && strm->avail_in == 0) break; /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || len < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_make(state) == -1) return -1; continue; /* no progress yet -- go back to memcpy() above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, buf, len, &n) == -1) return -1; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ strm->avail_out = len; strm->next_out = buf; if (gz_decomp(state) == -1) return -1; n = state->have; state->have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->pos += n; } while (len); /* return number of bytes read into user buffer (will fit in int) */ return (int)got; } /* -- see zlib.h -- */ int ZEXPORT gzgetc(file) gzFile file; { int ret; unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || state->err != Z_OK) return -1; /* try output buffer (no need to check for skip request) */ if (state->have) { state->have--; state->pos++; return *(state->next)++; } /* nothing there -- try gzread() */ ret = gzread(file, buf, 1); return ret < 1 ? -1 : buf[0]; } /* -- see zlib.h -- */ int ZEXPORT gzungetc(c, file) int c; gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || state->err != Z_OK) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->have == 0) { state->have = 1; state->next = state->out + (state->size << 1) - 1; state->next[0] = c; state->pos--; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->have == (state->size << 1)) { gz_error(state, Z_BUF_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->next == state->out) { unsigned char *src = state->out + state->have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->next = dest; } state->have++; state->next--; state->next[0] = c; state->pos--; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets(file, buf, len) gzFile file; char *buf; int len; { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || state->err != Z_OK) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->have == 0) { if (gz_make(state) == -1) return NULL; /* error */ if (state->have == 0) { /* end of file */ if (buf == str) /* got bupkus */ return NULL; break; /* got something -- return it */ } } /* look for end-of-line in current output buffer */ n = state->have > left ? left : state->have; eol = memchr(state->next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->next, n); state->have -= n; state->next += n; state->pos += n; left -= n; buf += n; } while (left && eol == NULL); /* found end-of-line or out of space -- terminate string and return it */ buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return 0; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->how == LOOK && state->have == 0) (void)gz_head(state); /* return 1 if reading direct, 0 if decompressing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r(file) gzFile file; { int ret; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : Z_OK; } |
Added undroid/libwebsockets/win32port/zlib/gzwrite.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004, 2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on failure or 0 on success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); /* allocate input and output buffers */ state->in = malloc(state->want); state->out = malloc(state->want); if (state->in == NULL || state->out == NULL) { if (state->out != NULL) free(state->out); if (state->in != NULL) free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, 15 + 16, 8, state->strategy); if (ret != Z_OK) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* mark state as initialized */ state->size = state->want; /* initialize write buffer */ strm->avail_out = state->size; strm->next_out = state->out; state->next = strm->next_out; return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. */ local int gz_comp(state, flush) gz_statep state; int flush; { int ret, got; unsigned have; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { have = (unsigned)(strm->next_out - state->next); if (have && ((got = write(state->fd, state->next, have)) < 0 || (unsigned)got != have)) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; } state->next = strm->next_out; } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) deflateReset(strm); /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on error, 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* -- see zlib.h -- */ int ZEXPORT gzwrite(file, buf, len) gzFile file; voidpc buf; unsigned len; { unsigned put = len; unsigned n; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); return 0; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { if (strm->avail_in == 0) strm->next_in = state->in; n = state->size - strm->avail_in; if (n > len) n = len; memcpy(strm->next_in + strm->avail_in, buf, n); strm->avail_in += n; state->pos += n; buf = (char *)buf + n; len -= n; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ strm->avail_in = len; strm->next_in = (voidp)buf; state->pos += len; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; } /* input was all buffered or compressed (put will fit in int) */ return (int)put; } /* -- see zlib.h -- */ int ZEXPORT gzputc(file, c) gzFile file; int c; { unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (strm->avail_in < state->size) { if (strm->avail_in == 0) strm->next_in = state->in; strm->next_in[strm->avail_in++] = c; state->pos++; return c; } /* no room in buffer or not initialized, use gz_write() */ buf[0] = c; if (gzwrite(file, buf, 1) != 1) return -1; return c; } /* -- see zlib.h -- */ int ZEXPORT gzputs(file, str) gzFile file; const char *str; { int ret; unsigned len; /* write string */ len = (unsigned)strlen(str); ret = gzwrite(file, str, len); return ret == 0 && len != 0 ? -1 : ret; } #ifdef STDC #include <stdarg.h> /* -- see zlib.h -- */ int ZEXPORTVA gzprintf (gzFile file, const char *format, ...) { int size, len; gz_statep state; z_streamp strm; va_list va; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; va_start(va, format); #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf(state->in, format, va); va_end(va); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = vsprintf(state->in, format, va); va_end(va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf(state->in, size, format, va); va_end(va); len = strlen(state->in); # else len = vsnprintf((char *)(state->in), size, format, va); va_end(va); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->pos += len; return len; } #else /* !STDC */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { int size, len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen(state->in); # else len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->pos += len; return len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush(file, flush) gzFile file; int flush; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* compress remaining data with requested flush */ gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams(file, level, strategy) gzFile file; int level; int strategy; { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w(file) gzFile file; { int ret = 0; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; ret += gz_zero(state, state->skip); } /* flush, free memory, and close file */ ret += gz_comp(state, Z_FINISH); (void)deflateEnd(&(state->strm)); free(state->out); free(state->in); gz_error(state, Z_OK, NULL); free(state->path); ret += close(state->fd); free(state); return ret ? Z_ERRNO : Z_OK; } |
Added undroid/libwebsockets/win32port/zlib/infback.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2009 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; int stream_size; { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; } if (strm->zfree == (free_func)0) strm->zfree = zcfree; state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } /* Macros for inflateBack(): */ /* Load returned state from inflate_fast() */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Set state from registers for inflate_fast() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ #define PULL() \ do { \ if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflateBack() with an error if there is no input available. */ #define PULLBYTE() \ do { \ PULL(); \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflateBack() with an error. */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ #define ROOM() \ do { \ if (left == 0) { \ put = state->window; \ left = state->wsize; \ state->whave = left; \ if (out(out_desc, put, left)) { \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* strm provides the memory allocation functions and window buffer on input, and provides information on the unused input on return. For Z_DATA_ERROR returns, strm will also provide an error message. in() and out() are the call-back input and output functions. When inflateBack() needs more input, it calls in(). When inflateBack() has filled the window with output, or when it completes with data in the window, it calls out() to write out the data. The application must not change the provided input until in() is called again or inflateBack() returns. The application must not change the window/output buffer until inflateBack() returns. in() and out() are called with a descriptor parameter provided in the inflateBack() call. This parameter can be a structure that provides the information required to do the read or write, as well as accumulated information on the input and output such as totals and check values. in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) z_streamp strm; in_func in; void FAR *in_desc; out_func out; void FAR *out_desc; { struct inflate_state FAR *state; unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* Reset the state */ strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; left = state->wsize; /* Inflate until end of block marked as last */ for (;;) switch (state->mode) { case TYPE: /* determine and dispatch block type */ if (state->last) { BYTEBITS(); state->mode = DONE; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); /* copy stored block from input to output */ while (state->length != 0) { copy = state->length; PULL(); ROOM(); if (copy > have) copy = have; if (copy > left) copy = left; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); /* get code length code lengths (not a typo) */ state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); /* get length and distance code code lengths */ state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; inflate_fast(strm, state->wsize); LOAD(); break; } /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); state->length = (unsigned)here.val; /* process literal */ if (here.op == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; } /* process end of block */ if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } /* length code -- get extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; /* get distance extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { ROOM(); copy = state->wsize - state->offset; if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; } if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly -- write leftover output */ ret = Z_STREAM_END; if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left)) ret = Z_BUF_ERROR; } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd(strm) z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } |
Added undroid/libwebsockets/win32port/zlib/inffast.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inffast.c -- fast decoding * Copyright (C) 1995-2008, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifndef ASMINF /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; unsigned char FAR *in; /* local strm->next_in */ unsigned char FAR *last; /* while in < last, enough input available */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); PUP(out) = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in + OFF; strm->next_out = out + OFF; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ |
Added undroid/libwebsockets/win32port/zlib/inffast.h.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); |
Added undroid/libwebsockets/win32port/zlib/inffixed.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; |
Added undroid/libwebsockets/win32port/zlib/inflate.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inflate.c -- zlib decompression * Copyright (C) 1995-2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, unsigned out)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, unsigned len)); int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; strm->adler = 1; /* to support ill-conceived Java test suite */ state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->wsize = 0; state->whave = 0; state->wnext = 0; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 1; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; } if (strm->zfree == (free_func)0) strm->zfree = zcfree; state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->window = Z_NULL; ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += value << state->bits; state->bits += bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include <stdio.h> /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, out) z_streamp strm; unsigned out; { struct inflate_state FAR *state; unsigned copy, dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ copy = out - strm->avail_out; if (copy >= state->wsize) { zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, strm->next_out - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Reverse the bytes in a 32-bit value */ #define REVERSE(q) \ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; else if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if (hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = REVERSE(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if (out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if (( #ifdef GUNZIP state->flags ? hold : #endif REVERSE(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) if (updatewindow(strm, out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if (state->wrap && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long id; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary id */ if (state->mode == DICT) { id = adler32(0L, Z_NULL, 0); id = adler32(id, dictionary, dictLength); if (id != state->check) return Z_DATA_ERROR; } /* copy dictionary to window */ if (updatewindow(strm, strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } if (dictLength > state->wsize) { zmemcpy(state->window, dictionary + dictLength - state->wsize, state->wsize); state->whave = state->wsize; } else { zmemcpy(state->window + state->wsize - dictLength, dictionary, dictLength); state->whave = dictLength; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy(dest, source, sizeof(z_stream)); zmemcpy(copy, state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state->sane = 1; return Z_DATA_ERROR; #endif } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; state = (struct inflate_state FAR *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } |
Added undroid/libwebsockets/win32port/zlib/inflate.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inflate.h -- internal inflate state definition * Copyright (C) 1995-2009 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* state maintained between inflate() calls. Approximately 10K bytes. */ struct inflate_state { inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; |
Added undroid/libwebsockets/win32port/zlib/inftrees.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.5 Copyright 1995-2010 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ int end; /* use base and extra for symbol > end */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used >= ENOUGH_LENS) || (type == DISTS && used >= ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used >= ENOUGH_LENS) || (type == DISTS && used >= ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* Fill in rest of table for incomplete codes. This loop is similar to the loop above in incrementing huff for table indices. It is assumed that len is equal to curr + drop, so there is no loop needed to increment through high index bits. When the current sub-table is filled, the loop drops back to the root table to fill in any remaining entries there. */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; while (huff != 0) { /* when done with sub-table, drop back to root table */ if (drop != 0 && (huff & mask) != low) { drop = 0; len = root; next = *table; here.bits = (unsigned char)len; } /* put invalid code marker in table */ next[huff >> drop] = here; /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; } /* set return parameters */ *table += used; *bits = root; return 0; } |
Added undroid/libwebsockets/win32port/zlib/inftrees.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); |
Added undroid/libwebsockets/win32port/zlib/trees.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2010 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef DEBUG # include <ctype.h> #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ #define Buf_size (8 * 2*sizeof(char)) /* Number of bits used within bi_buf. (bi_buf might be implemented on * more than 16 bits on some systems.) */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, ct_data *ltree, ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); local void copy_block OF((deflate_state *s, charf *buf, unsigned len, int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1<<extra_lbits[code]); n++) { _length_code[length++] = (uch)code; } } Assert (length == 256, "tr_static_init: length != 256"); /* Note that the length 255 (match length 258) can be represented * in two different ways: code 284 + 5 bits or code 285, so we * overwrite length_code[255] to use the best encoding: */ _length_code[length-1] = (uch)code; /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<<extra_dbits[code]); n++) { _dist_code[dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: dist != 256"); dist >>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef DEBUG # include <stdio.h> # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(s) deflate_state *s; { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; s->last_eob_len = 8; /* enough lookahead for inflate */ #ifdef DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; Trace((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes (tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, "inconsistent bit counts"); Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); for (n = 0; n <= max_code; n++) { int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ tree[n].Code = bi_reverse(next_code[len]++, len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); } } /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. * Update the total bit length for the current block. * IN assertion: the field freq is set for all tree elements. * OUT assertions: the fields len and code are set to the optimal bit length * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ local void build_tree(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*(max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ #ifdef DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; #endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. * The current inflate code requires 9 bits of lookahead. If the * last two codes for the previous block (real code plus EOB) were coded * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode * the last real code. In this case we send two empty static blocks instead * of one. (There are no problems if the previous block is stored or fixed.) * To simplify the code, we assume the worst case of last real code encoded * on one bit only. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s; { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); /* Of the 10 bits for the empty block, we have already sent * (10 - bi_valid) bits. The lookahead for the last real code (before * the EOB of the previous block) was thus at least one plus the length * of the EOB plus what we have just sent of the empty static block. */ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; #endif bi_flush(s); } s->last_eob_len = 7; } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally (s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(s, ltree, dtree) deflate_state *s; ct_data *ltree; /* literal tree */ ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); s->last_eob_len = ltree[END_BLOCK].Len; } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(s) deflate_state *s; { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(s) deflate_state *s; { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ local void copy_block(s, buf, len, header) deflate_state *s; charf *buf; /* the input data */ unsigned len; /* its length */ int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */ s->last_eob_len = 8; /* enough lookahead for inflate */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } |
Added undroid/libwebsockets/win32port/zlib/trees.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* header created automatically with -DGEN_TREES_H */ local const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; local const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; local const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; local const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; |
Added undroid/libwebsockets/win32port/zlib/uncompr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted. */ int ZEXPORT uncompress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { z_stream stream; int err; stream.next_in = (Bytef*)source; stream.avail_in = (uInt)sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; err = inflateInit(&stream); if (err != Z_OK) return err; err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) return Z_DATA_ERROR; return err; } *destLen = stream.total_out; err = inflateEnd(&stream); return err; } |
Added undroid/libwebsockets/win32port/zlib/zconf.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ /* all linked symbols */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzgetc z_gzgetc # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # define gzprintf z_gzprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzwrite z_gzwrite # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit_ z_inflateBackInit_ # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetHeader z_inflateGetHeader # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # define uncompress z_uncompress # define zError z_zError # define zcalloc z_zcalloc # define zcfree z_zcfree # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # define gzFile z_gzFile # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus a few kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include <windows.h> /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef STDC # include <sys/types.h> /* for off_t */ #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include <unistd.h> /* for SEEK_* and off_t */ # ifdef VMS # include <unixio.h> /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif #endif #ifndef SEEK_SET # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define z_off64_t off64_t #else # define z_off64_t z_off_t #endif #if defined(__OS400__) # define NO_vsnprintf #endif #if defined(__MVS__) # define NO_vsnprintf #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ |
Added undroid/libwebsockets/win32port/zlib/zlib.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.5, April 19th, 2010 Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.5" #define ZLIB_VERNUM 0x1250 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 5 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed code block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the value returned by deflateBound (see below). If deflate does not return Z_STREAM_END, then it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all the uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH is never required, but can be used to inform inflate that a faster approach may be used for the single inflate() call. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the only effect of the flush parameter in this implementation is on the return value of inflate(), as noted below, or when it returns early because Z_BLOCK or Z_TREES is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the adler32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the adler32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is desired. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute an adler32 check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. This function must be called immediately after deflateInit, deflateInit2 or deflateReset, before any call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if the compression method is bsort). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an adler32 or a crc32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called immediately after inflateInit2() or inflateReset() and before any call of inflate() to set the dictionary. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above or -1 << 16 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the paramaters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is more efficient than inflate() for file i/o applications in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. This function trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the normal behavior of inflate(), which expects either a zlib or gzip header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero--buf is ignored in that case--and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef voidp gzFile; /* opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) Also "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Two buffers are allocated, either both of the specified size when writing, or one of the specified size and the other twice that size when reading. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file was not in gzip format, gzread copies the given number of bytes into the buffer. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream, or failing that, reading the rest of the input file directly without decompression. The entire input file will be read if gzread is called until it returns less than the requested len. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or 0 in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatented gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. This state can change from false to true while reading the input file if the end of a gzip stream is reached, but is followed by data that is not another gzip stream. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, sizeof(z_stream)) /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # ifdef _LARGEFILE64_SOURCE ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; #endif /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); #ifdef __cplusplus } #endif #endif /* ZLIB_H */ |
Added undroid/libwebsockets/win32port/zlib/zutil.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2005, 2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ "file error", /* Z_ERRNO (-1) */ "stream error", /* Z_STREAM_ERROR (-2) */ "data error", /* Z_DATA_ERROR (-3) */ "insufficient memory", /* Z_MEM_ERROR (-4) */ "buffer error", /* Z_BUF_ERROR (-5) */ "incompatible version",/* Z_VERSION_ERROR (-6) */ ""}; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #ifdef STDC # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef DEBUG # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error (m) char *m; { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(err) int err; { return ERR_MSG(err); } #if defined(_WIN32_WCE) /* The Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(dest, source, len) Bytef* dest; const Bytef* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(s1, s2, len) const Bytef* s1; const Bytef* s2; uInt len; { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(dest, len) Bytef* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { voidpf buf = opaque; /* just to make some compilers happy */ ulg bsize = (ulg)items*size; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { if (opaque) opaque = 0; /* to make compiler happy */ return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { if (opaque) opaque = 0; /* to make compiler happy */ _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) voidpf opaque; unsigned items; unsigned size; { if (opaque) items += size - size; /* make compiler happy */ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { free(ptr); if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ |
Added undroid/libwebsockets/win32port/zlib/zutil.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ) && !defined(_WIN32) # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "zlib.h" #ifdef STDC # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include <stddef.h> # endif # include <string.h> # include <stdlib.h> #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = (char*)ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include <alloc.h> # endif # else /* MSC or DJGPP */ # include <malloc.h> # endif #endif #ifdef AMIGA # define OS_CODE 0x01 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 0x02 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 0x05 #endif #ifdef OS2 # define OS_CODE 0x06 # ifdef M_I86 # include <malloc.h> # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include <unix.h> /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif #endif #ifdef TOPS20 # define OS_CODE 0x0a #endif #ifdef WIN32 # ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ # define OS_CODE 0x0b # endif #endif #ifdef __50SERIES /* Prime/PRIMOS */ # define OS_CODE 0x0f #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # ifndef _PTRDIFF_T_DEFINED typedef int ptrdiff_t; # define _PTRDIFF_T_DEFINED # endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(__CYGWIN__) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #ifndef HAVE_VSNPRINTF # ifdef MSDOS /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), but for now we just assume it doesn't. */ # define NO_vsnprintf # endif # ifdef __TURBOC__ # define NO_vsnprintf # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ # if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # define vsnprintf _vsnprintf # endif # endif # endif # ifdef __SASC # define NO_vsnprintf # endif #endif #ifdef VMS # define NO_vsnprintf #endif #if defined(pyr) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef DEBUG # include <stdio.h> extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} #endif /* ZUTIL_H */ |