Sfoglia il codice sorgente

Merge branch 'master' into feature/btdm_bluedroid

feature/btdm_bluedroid use newest master

# Conflicts:
#	components/bt/component.mk
Tian Hao 9 anni fa
parent
commit
0b37621438
100 ha cambiato i file con 13469 aggiunte e 1630 eliminazioni
  1. 10 0
      .gitignore
  2. 19 1
      .gitlab-ci.yml
  3. 37 0
      CONTRIBUTING.md
  4. 9 9
      Kconfig
  5. 16 2
      README.md
  6. 4 0
      components/bootloader/src/main/bootloader_config.h
  7. 21 5
      components/bootloader/src/main/bootloader_start.c
  8. 18 12
      components/bt/Kconfig
  9. 41 28
      components/bt/bt.c
  10. 7 5
      components/bt/component.mk
  11. 11 8
      components/bt/include/bt.h
  12. 1 1
      components/bt/lib
  13. 31 18
      components/driver/gpio.c
  14. 3 3
      components/driver/include/driver/gpio.h
  15. 406 0
      components/driver/include/driver/ledc.h
  16. 70 0
      components/driver/include/driver/periph_ctrl.h
  17. 432 0
      components/driver/ledc.c
  18. 170 0
      components/driver/periph_ctrl.c
  19. 48 29
      components/esp32/Kconfig
  20. 14 17
      components/esp32/component.mk
  21. 43 49
      components/esp32/cpu_start.c
  22. 49 0
      components/esp32/deepsleep.c
  23. 38 124
      components/esp32/event_default_handlers.c
  24. 107 0
      components/esp32/event_loop.c
  25. 14 2
      components/esp32/include/esp_attr.h
  26. 137 0
      components/esp32/include/esp_deepsleep.h
  27. 7 0
      components/esp32/include/esp_err.h
  28. 12 43
      components/esp32/include/esp_event.h
  29. 81 0
      components/esp32/include/esp_event_loop.h
  30. 143 0
      components/esp32/include/esp_smartconfig.h
  31. 1 15
      components/esp32/include/esp_system.h
  32. 6 7
      components/esp32/include/esp_task.h
  33. 15 189
      components/esp32/include/esp_wifi.h
  34. 190 0
      components/esp32/include/esp_wifi_types.h
  35. 0 131
      components/esp32/include/esp_wps.h
  36. 13 13
      components/esp32/include/rom/rtc.h
  37. 126 124
      components/esp32/include/soc/io_mux_reg.h
  38. 68 127
      components/esp32/include/soc/ledc_struct.h
  39. 0 14
      components/esp32/ld/esp32.bt.ld
  40. 0 14
      components/esp32/ld/esp32.bt.trace.ld
  41. 15 3
      components/esp32/ld/esp32.common.ld
  42. 47 6
      components/esp32/ld/esp32.ld
  43. 5 1
      components/esp32/ld/esp32.rom.ld
  44. 0 14
      components/esp32/ld/esp32.trace.ld
  45. 1 1
      components/esp32/lib
  46. 4 5
      components/esp32/syscalls.c
  47. 0 115
      components/esp32/wifi.c
  48. 1 1
      components/esptool_py/Makefile.projbuild
  49. 1 1
      components/esptool_py/esptool
  50. 1 1
      components/expat/component.mk
  51. 22 0
      components/expat/expat.rst
  52. 132 124
      components/freertos/Kconfig
  53. 1 0
      components/freertos/croutine.c
  54. 0 7
      components/freertos/event_groups.c
  55. 12 0
      components/freertos/include/freertos/FreeRTOSConfig.h
  56. 206 0
      components/freertos/include/freertos/ringbuf.h
  57. 6 0
      components/freertos/include/freertos/task.h
  58. 2 2
      components/freertos/panic.c
  59. 90 304
      components/freertos/queue.c
  60. 474 0
      components/freertos/ringbuf.c
  61. 33 28
      components/freertos/tasks.c
  62. 20 0
      components/freertos/xtensa_vectors.S
  63. 7 7
      components/log/Kconfig
  64. 17 17
      components/lwip/Kconfig
  65. 1 1
      components/lwip/component.mk
  66. 11 1
      components/lwip/include/lwip/port/arch/sys_arch.h
  67. 8 0
      components/lwip/include/lwip/port/netif/wlanif.h
  68. 37 0
      components/mbedtls/Kconfig
  69. 5 1
      components/mbedtls/port/include/mbedtls/esp_config.h
  70. 23 0
      components/nghttp/COPYING
  71. 1 0
      components/nghttp/LICENSE
  72. 17 0
      components/nghttp/Makefile
  73. 4 0
      components/nghttp/Makefile.projbuild
  74. 1 0
      components/nghttp/README
  75. 9 0
      components/nghttp/component.mk
  76. 5030 0
      components/nghttp/include/nghttp2/nghttp2.h
  77. 42 0
      components/nghttp/include/nghttp2/nghttp2ver.h
  78. 388 0
      components/nghttp/include/nghttp2_buf.h
  79. 117 0
      components/nghttp/include/nghttp2_callbacks.h
  80. 581 0
      components/nghttp/include/nghttp2_frame.h
  81. 430 0
      components/nghttp/include/nghttp2_hd.h
  82. 77 0
      components/nghttp/include/nghttp2_hd_huffman.h
  83. 122 0
      components/nghttp/include/nghttp2_helper.h
  84. 97 0
      components/nghttp/include/nghttp2_http.h
  85. 58 0
      components/nghttp/include/nghttp2_int.h
  86. 144 0
      components/nghttp/include/nghttp2_map.h
  87. 45 0
      components/nghttp/include/nghttp2_mem.h
  88. 91 0
      components/nghttp/include/nghttp2_net.h
  89. 34 0
      components/nghttp/include/nghttp2_npn.h
  90. 116 0
      components/nghttp/include/nghttp2_option.h
  91. 166 0
      components/nghttp/include/nghttp2_outbound_item.h
  92. 128 0
      components/nghttp/include/nghttp2_pq.h
  93. 42 0
      components/nghttp/include/nghttp2_priority_spec.h
  94. 49 0
      components/nghttp/include/nghttp2_queue.h
  95. 80 0
      components/nghttp/include/nghttp2_rcbuf.h
  96. 878 0
      components/nghttp/include/nghttp2_session.h
  97. 436 0
      components/nghttp/include/nghttp2_stream.h
  98. 34 0
      components/nghttp/include/nghttp2_submit.h
  99. 494 0
      components/nghttp/library/nghttp2_buf.c
  100. 158 0
      components/nghttp/library/nghttp2_callbacks.c

+ 10 - 0
.gitignore

@@ -7,8 +7,18 @@ GTAGS
 GRTAGS
 GPATH
 
+# emacs
+.dir-locals.el
+
 # emacs temp file suffixes
 *~
 .#*
 \#*#
 
+# Example project files
+examples/*/sdkconfig
+examples/*/sdkconfig.old
+examples/*/build
+
+# Bootloader files
+components/bootloader/src/sdkconfig.old

+ 19 - 1
.gitlab-ci.yml

@@ -64,10 +64,28 @@ build_ssc:
   script:
     - git clone ssh://git@gitlab.espressif.cn:27227/yinling/SSC.git
     - cd SSC
+    - git checkout ${CI_BUILD_REF_NAME} || echo "Using SSC default branch..."
     - make defconfig
     - chmod +x gen_misc_ng.sh
     - ./gen_misc_ng.sh
 
+build_examples:
+  <<: *build_template
+  artifacts:
+    paths:
+      - build_examples/*/*/build/*.bin
+      - build_examples/*/*/build/*.elf
+      - build_examples/*/*/build/*.map
+      - build_examples/*/*/build/bootloader/*.bin
+    expire_in: 6 mos
+
+  script:
+    # it's not possible to build 100% out-of-tree and have the "artifacts"
+    # mechanism work, but this is the next best thing
+    - mkdir build_examples
+    - cd build_examples
+    - ${IDF_PATH}/make/build_examples.sh
+
 test_nvs_on_host:
   stage: test
   image: espressif/esp32-ci-env
@@ -146,4 +164,4 @@ push_master_to_github:
     - chmod 600 ~/.ssh/id_rsa
     - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
     - git remote add github git@github.com:espressif/esp-idf.git
-    - git push github HEAD:master
+    - git push --follow-tags github HEAD:master

+ 37 - 0
CONTRIBUTING.md

@@ -0,0 +1,37 @@
+# Contributions Guide
+
+We welcome contributions to the esp-idf project!
+
+## How to Contribute
+
+Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via [Github Pull Requests](https://help.github.com/articles/about-pull-requests/).
+
+## Before Contributing
+
+Before sending us a Pull Request, please consider this list of points:
+
+* Is the contribution entirely your own work, or already licensed under an Apache License 2.0 compatible Open Source License? If not then we unfortunately cannot accept it.
+
+* Does any new code conform to the esp-idf Style Guide? (Style Guide currently pending).
+
+* Is the code adequately commented for people to understand how it is structured?
+
+* Is there documentation or examples that go with code contributions? [There are additional suggestions for writing good examples in the examples README](examples/README.md).
+
+* Are comments and documentation written in clear English, with no spelling or grammar errors?
+
+* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" [squashed into previous commits](http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/)?
+
+* If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback.
+
+## Pull Request Process
+
+After you open the Pull Request, there will probably be some discussion in the comments field of the request itself.
+
+Once the Pull Request is ready to merge, it will first be merged into our internal git system for in-house automated testing.
+
+If this process passes, it will be merged onto the public github repository.
+
+## Legal Part
+
+Before a contribution can be accepted, you will need to sign our [Contributor Agreement](docs/contributor-agreement.rst). You will be prompted for this automatically as part of the Pull Request process.

+ 9 - 9
Kconfig

@@ -7,18 +7,18 @@ mainmenu "Espressif IoT Development Framework Configuration"
 
 menu "SDK tool configuration"
 config TOOLPREFIX
-	string "Compiler toolchain path/prefix"
-	default "xtensa-esp32-elf-"
-	help
-		The prefix/path that is used to call the toolchain. The default setting assumes
-		a crosstool-ng gcc setup that is in your PATH.
+    string "Compiler toolchain path/prefix"
+    default "xtensa-esp32-elf-"
+    help
+        The prefix/path that is used to call the toolchain. The default setting assumes
+        a crosstool-ng gcc setup that is in your PATH.
 
 config PYTHON
     string "Python 2 interpreter"
-	default "python"
-	help
-	    The executable name/path that is used to run python. On some systems Python 2.x
-		may need to be invoked as python2.
+    default "python"
+    help
+        The executable name/path that is used to run python. On some systems Python 2.x
+        may need to be invoked as python2.
 endmenu
 
 source "$COMPONENT_KCONFIGS_PROJBUILD"

+ 16 - 2
README.md

@@ -1,6 +1,18 @@
 # Using Espressif IoT Development Framework with the ESP32
 
-# Prerequisites
+# Setting Up ESP-IDF
+
+In the [docs](docs) directory you will find per-platform setup guides:
+
+* [Windows Setup Guide](docs/windows-setup.rst)
+* [Mac OS Setup Guide](docs/macos-setup.rst)
+* [Linux Setup Guide](docs/linux-setup.rst)
+
+# Finding A Project
+
+As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory.
+
+Once you've found the project you want to work with, change to its directory and you can configure and build it:
 
 # Configuring your project
 
@@ -52,8 +64,10 @@ For more details about partition tables and how to create custom variations, vie
 
 # Resources
 
-* The [docs directory of the esp-idf repository](https://github.com/espressif/esp-idf/tree/master/docs) contains esp-idf documentation.
+* The [docs directory of the esp-idf repository](docs) contains esp-idf documentation.
 
 * The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources.
 
 * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
+
+* If you're interested in contributing to esp-idf, please check the [CONTRIBUTING.md](CONTRIBUTING.md) file.

+ 4 - 0
components/bootloader/src/main/bootloader_config.h

@@ -30,6 +30,10 @@ extern "C"
 #define IROM_HIGH   0x40400000
 #define DROM_LOW    0x3F400000
 #define DROM_HIGH   0x3F800000
+#define RTC_IRAM_LOW  0x400C0000
+#define RTC_IRAM_HIGH 0x400C2000
+#define RTC_DATA_LOW  0x50000000
+#define RTC_DATA_HIGH 0x50002000
 
 /*spi mode,saved in third byte in flash */
 enum {

+ 21 - 5
components/bootloader/src/main/bootloader_start.c

@@ -22,6 +22,7 @@
 #include "rom/ets_sys.h"
 #include "rom/spi_flash.h"
 #include "rom/crc.h"
+#include "rom/rtc.h"
 
 #include "soc/soc.h"
 #include "soc/cpu.h"
@@ -362,11 +363,15 @@ void unpack_load_app(const partition_pos_t* partition)
     uint32_t irom_load_addr = 0;
     uint32_t irom_size = 0;
 
+    /* Reload the RTC memory sections whenever a non-deepsleep reset
+       is occuring */
+    bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
+
     ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
-              image_header.blocks,
-              image_header.spi_mode,
-              image_header.spi_size,
-              (unsigned)image_header.entry_addr);
+             image_header.blocks,
+             image_header.spi_mode,
+             image_header.spi_size,
+             (unsigned)image_header.entry_addr);
 
     for (uint32_t section_index = 0;
             section_index < image_header.blocks;
@@ -406,7 +411,18 @@ void unpack_load_app(const partition_pos_t* partition)
             map = true;
         }
 
-        ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos, section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
+		if(!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
+			ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos);
+			load = false;
+		}
+
+		if(!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) {
+			ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos);
+			load = false;
+		}
+
+        ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos,
+                 section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
 
         if (!load) {
             pos += section_header.data_len;

+ 18 - 12
components/bt/Kconfig

@@ -3,21 +3,27 @@ visible if MEMMAP_BT
 
 
 config BT_ENABLED
-	bool
-	depends on ESP32_ENABLE_STACK_BT
-	help
-		This compiles in the low-level BT stack.
+    bool
+    depends on ESP32_ENABLE_STACK_BT
+    help
+        This compiles in the low-level BT stack.
 
 #config BT_BTLE
-#	bool "Enable BTLE"
-#	depends on BT_ENABLED
-#	help
-#		This compiles BTLE support
+#    bool "Enable BTLE"
+#    depends on BT_ENABLED
+#    help
+#        This compiles BTLE support
 #
 #config BT_BT
-#	bool "Enable classic BT"
-#	depends on BT_ENABLED
-#	help
-#		This enables classic BT support
+#    bool "Enable classic BT"
+#    depends on BT_ENABLED
+#    help
+#        This enables classic BT support
 
 endmenu
+
+# Memory reserved at start of DRAM for Bluetooth stack
+config BT_RESERVE_DRAM
+    hex
+    default 0x10000 if MEMMAP_BT
+    default 0

+ 41 - 28
components/bt/bt.c

@@ -36,9 +36,6 @@ extern void btdm_osi_funcs_register(void *osi_funcs);
 extern void btdm_controller_init(void);
 
 
-static bt_app_startup_cb_t app_startup_cb;
-static void *app_startup_ctx;
-
 #define BT_DEBUG(...)
 #define BT_API_CALL_CHECK(info, api_call, ret) \
 do{\
@@ -56,8 +53,11 @@ struct osi_funcs_t {
     void (*_interrupt_restore)(void);
     void (*_task_yield)(void);
     void *(*_semphr_create)(uint32_t max, uint32_t init);
-    void *(*_semphr_give_from_isr)(void *semphr, void *hptw);
-    void *(*_semphr_take)(void *semphr, uint32_t block_time);
+    int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw);
+    int32_t (*_semphr_take)(void *semphr, uint32_t block_time_ms);
+    void *(*_mutex_create)(void);
+    int32_t (*_mutex_lock)(void *mutex);
+    int32_t (*_mutex_unlock)(void *mutex);
     esp_err_t (* _read_efuse_mac)(uint8_t mac[6]);
 };
 
@@ -73,9 +73,34 @@ static void IRAM_ATTR interrupt_restore(void)
     portEXIT_CRITICAL(&global_int_mux);
 }
 
-static void * IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time)
+static void * IRAM_ATTR semphr_create_wrapper(uint32_t max, uint32_t init)
+{
+    return (void *)xSemaphoreCreateCounting(max, init);
+}
+
+static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
+{
+    return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
+}
+
+static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
+{
+    return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_RATE_MS);
+}
+
+static void * IRAM_ATTR mutex_create_wrapper(void)
+{
+    return (void *)xSemaphoreCreateMutex();
+}
+
+static int32_t IRAM_ATTR mutex_lock_wrapper(void *mutex)
+{
+    return (int32_t)xSemaphoreTake(mutex, portMAX_DELAY);
+}
+
+static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex)
 {
-    return (void *)xSemaphoreTake(semphr, block_time);
+    return (int32_t)xSemaphoreGive(mutex);
 }
 
 static struct osi_funcs_t osi_funcs = {
@@ -84,9 +109,12 @@ static struct osi_funcs_t osi_funcs = {
     ._interrupt_disable = interrupt_disable,
     ._interrupt_restore = interrupt_restore,
     ._task_yield = vPortYield,
-    ._semphr_create = xQueueCreateCountingSemaphore,
-    ._semphr_give_from_isr = (void *)xQueueGiveFromISR,
+    ._semphr_create = semphr_create_wrapper,
+    ._semphr_give_from_isr = semphr_give_from_isr_wrapper,
     ._semphr_take = semphr_take_wrapper,
+    ._mutex_create = mutex_create_wrapper,
+    ._mutex_lock = mutex_lock_wrapper,
+    ._mutex_unlock = mutex_unlock_wrapper,
     ._read_efuse_mac = system_efuse_read_mac,
 };
 
@@ -96,26 +124,11 @@ static void bt_controller_task(void *pvParam)
     btdm_controller_init();
 }
 
-
-static void bt_init_task(void *pvParameters)
+void bt_controller_init()
 {
-    xTaskCreatePinnedToCore(bt_controller_task, "btControllerTask", ESP_TASK_BT_CONTROLLER_STACK, NULL, ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0);
-
-    if (app_startup_cb) {
-        app_startup_cb(app_startup_ctx);
-    }
-
-    vTaskDelete(NULL);
+    xTaskCreatePinnedToCore(bt_controller_task, "btController",
+            ESP_TASK_BT_CONTROLLER_STACK, NULL,
+            ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0);
 }
 
-
-esp_err_t esp_bt_startup(bt_app_startup_cb_t cb, void *ctx)
-{
-    app_startup_cb = cb;
-    app_startup_ctx = ctx;
-
-    xTaskCreatePinnedToCore(bt_init_task, "btInitTask", ESP_TASK_BT_INIT_STACK, NULL, ESP_TASK_BT_INIT_PRIO, NULL, 0);
-
-    return ESP_OK;
-}
 #endif

+ 7 - 5
components/bt/component.mk

@@ -28,7 +28,7 @@ COMPONENT_ADD_INCLUDEDIRS :=	bluedroid/bta/include			\
 				bluedroid/include			\
 				include	
 
-CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses -I./include
+CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses
 
 LIBS := btdm_app
 
@@ -36,10 +36,6 @@ COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \
                            $(addprefix -l,$(LIBS)) \
                           $(LINKER_SCRIPTS)
 
-
-ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
-$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
-
 COMPONENT_SRCDIRS := 	bluedroid/bta/dm			\
 			bluedroid/bta/gatt			\
 			bluedroid/bta/hh			\
@@ -76,3 +72,9 @@ COMPONENT_SRCDIRS := 	bluedroid/bta/dm			\
 			.
 
 include $(IDF_PATH)/make/component_common.mk
+
+ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
+$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
+
+# automatically trigger a git submodule update if BT library is missing
+$(eval $(call SubmoduleRequiredForFiles,$(ALL_LIB_FILES)))

+ 11 - 8
components/bt/include/bt.h

@@ -15,7 +15,7 @@
 #ifndef __BT_H__
 #define __BT_H__
 
-#include "freertos/FreeRTOS.h"
+#include <stdint.h>
 #include "esp_err.h"
 
 #ifdef __cplusplus
@@ -23,11 +23,14 @@ extern "C" {
 #endif
 
 
-typedef void (* bt_app_startup_cb_t)(void *param);
-
-esp_err_t esp_bt_startup(bt_app_startup_cb_t cb, void *ctx);
+/**
+ * @brief  Initialize BT controller
+ *
+ * This function should be called only once, before any other BT functions are called.
+ */
+void bt_controller_init();
 
-/* @breif: vhci_host_callback
+/** @brief: vhci_host_callback
  *  used for vhci call host function to notify what host need to do
  *  
  *  notify_host_send_available: notify host can send packet to controller
@@ -39,20 +42,20 @@ typedef struct vhci_host_callback {
     int (*notify_host_recv)(uint8_t *data, uint16_t len);
 } vhci_host_callback_t;
 
-/* @breif: API_vhci_host_check_send_available
+/** @brief: API_vhci_host_check_send_available
  *  used for check actively if the host can send packet to controller or not.
  *  return true for ready to send, false means cannot send packet
  */
 bool API_vhci_host_check_send_available(void);
 
-/* @breif: API_vhci_host_send_packet 
+/** @brief: API_vhci_host_send_packet
  * host send packet to controller
  * param data is the packet point, the param len is the packet length
  * return void
  */
 void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
 
-/* @breif: API_vhci_host_register_callback
+/** @brief: API_vhci_host_register_callback
  * register the vhci referece callback, the call back
  * struct defined by vhci_host_callback structure.
  * param is the vhci_host_callback type variable

+ 1 - 1
components/bt/lib

@@ -1 +1 @@
-Subproject commit 6c9a6de656262113a0aab63907d6871a64e00fae
+Subproject commit bcbc35215c6d87279da4b87a74d3360c537d6724

+ 31 - 18
components/driver/gpio.c

@@ -90,7 +90,6 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
     GPIO_PIN_REG_39
 };
 
-#define IS_VALID_GPIO(gpio_num)  ( (gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0))
 static int is_valid_gpio(int gpio_num)
 {
     if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) {
@@ -102,8 +101,9 @@ static int is_valid_gpio(int gpio_num)
 
 esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     if(intr_type >= GPIO_INTR_MAX) {
         GPIO_ERROR("Unknown GPIO intr:%u\n",intr_type);
         return ESP_ERR_INVALID_ARG;
@@ -114,8 +114,9 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 
 esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     if(xPortGetCoreID() == 0) {
         GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA;     //enable pro cpu intr
     } else {
@@ -126,16 +127,18 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 
 esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     GPIO.pin[gpio_num].int_ena = 0;                             //disable GPIO intr
     return ESP_OK;
 }
 
 static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     if(gpio_num < 32) {
         GPIO.enable_w1tc = (0x1 << gpio_num);
     } else {
@@ -150,8 +153,9 @@ static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
         GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
         return ESP_ERR_INVALID_ARG;
     }
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     if(gpio_num < 32) {
         GPIO.enable_w1ts = (0x1 << gpio_num);
     } else {
@@ -162,18 +166,21 @@ static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
 
 esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
 {
-    if(!IS_VALID_GPIO(gpio_num))
+    if(!GPIO_IS_VALID_GPIO(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     if(level) {
-        if(gpio_num < 32)
+        if(gpio_num < 32) {
             GPIO.out_w1ts = (1 << gpio_num);
-        else
+        } else {
             GPIO.out1_w1ts.data = (1 << (gpio_num - 32));
+        }
     } else {
-        if(gpio_num < 32)
+        if(gpio_num < 32) {
             GPIO.out_w1tc = (1 << gpio_num);
-        else
+        } else {
             GPIO.out1_w1tc.data = (1 << (gpio_num - 32));
+        }
     }
     return ESP_OK;
 }
@@ -189,8 +196,9 @@ int gpio_get_level(gpio_num_t gpio_num)
 
 esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     esp_err_t ret = ESP_OK;
     switch(pull) {
         case GPIO_PULLUP_ONLY:
@@ -219,8 +227,9 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
 
 esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) {
         GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
         return ESP_ERR_INVALID_ARG;
@@ -290,7 +299,8 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
                 gpio_output_enable(io_num);
             } else {
                 gpio_output_disable(io_num);
-            }GPIO_INFO("|");
+            }
+            GPIO_INFO("|");
             if(pGPIOConfig->pull_up_en) {
                 GPIO_INFO("PU ");
                 PIN_PULLUP_EN(io_reg);
@@ -310,7 +320,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
             } else {
                 gpio_intr_disable(io_num);
             }
-            PIN_FUNC_SELECT(io_reg, GPIO_FUNC_SEL); /*function number 2 is GPIO_FUNC for each pin */
+            PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */
         } else if(bit_valid && (io_reg == 0)) {
             GPIO_WARNING("io_num=%d does not exist\n",io_num);
         }
@@ -321,8 +331,9 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
 
 esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg)
 {
-    if(fn == NULL)
+    if(fn == NULL) {
         return ESP_ERR_INVALID_ARG;
+    }
     ESP_INTR_DISABLE(gpio_intr_num);
     intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
     xt_set_interrupt_handler(gpio_intr_num, fn, arg);
@@ -333,8 +344,9 @@ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * ar
 /*only level interrupt can be used for wake-up function*/
 esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     esp_err_t ret = ESP_OK;
     if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
         GPIO.pin[gpio_num].int_type = intr_type;
@@ -348,8 +360,9 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 
 esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
+    }
     GPIO.pin[gpio_num].wakeup_enable = 0;
     return ESP_OK;
 }

+ 3 - 3
components/driver/include/driver/gpio.h

@@ -14,7 +14,7 @@
 
 #ifndef _DRIVER_GPIO_H_
 #define _DRIVER_GPIO_H_
-
+#include "esp_err.h"
 #include <esp_types.h>
 #include "soc/gpio_reg.h"
 #include "soc/gpio_struct.h"
@@ -65,8 +65,6 @@ extern "C" {
 #define GPIO_SEL_38             ((uint64_t)(((uint64_t)1)<<38))  /* Pin 38 selected */
 #define GPIO_SEL_39             ((uint64_t)(((uint64_t)1)<<39))  /* Pin 39 selected */
 
-#define GPIO_FUNC_SEL           2
-
 #define GPIO_PIN_REG_0          PERIPHS_IO_MUX_GPIO0_U
 #define GPIO_PIN_REG_1          PERIPHS_IO_MUX_U0TXD_U
 #define GPIO_PIN_REG_2          PERIPHS_IO_MUX_GPIO2_U
@@ -115,6 +113,8 @@ extern "C" {
 
 #define GPIO_PIN_COUNT              40
 extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT];
+#define GPIO_IS_VALID_GPIO(gpio_num)      ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0))   //to decide whether it is a valid GPIO number
+#define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)      ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34))         //to decide whether it can be a valid GPIO number of output mode
 
 typedef enum {
     GPIO_NUM_0 = 0,

+ 406 - 0
components/driver/include/driver/ledc.h

@@ -0,0 +1,406 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+#ifndef _DRIVER_LEDC_H_
+#define _DRIVER_LEDC_H_
+#include "esp_err.h"
+#include "soc/soc.h"
+#include "soc/ledc_reg.h"
+#include "soc/ledc_reg.h"
+#include "soc/ledc_struct.h"
+#include "driver/gpio.h"
+#include "driver/periph_ctrl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
+#define LEDC_REF_CLK_HZ (1*1000000)
+
+typedef enum {
+    LEDC_HIGH_SPEED_MODE = 0, /*LEDC high speed speed_mode */
+    //in this version, we only support high speed speed_mode. We will access low speed speed_mode later
+    //LEDC_LOW_SPEED_MODE,    /*LEDC low speed speed_mode */
+    LEDC_SPEED_MODE_MAX,
+} ledc_mode_t;
+
+typedef enum {
+    LEDC_INTR_DISABLE = 0,    /*Disable LEDC interrupt */
+    LEDC_INTR_FADE_END,       /*Enable LEDC interrupt */
+} ledc_intr_type_t;
+
+typedef enum {
+    LEDC_DUTY_DIR_DECREASE = 0,    /*LEDC duty decrease direction */
+    LEDC_DUTY_DIR_INCREASE = 1,    /*LEDC duty increase direction */
+} ledc_duty_direction_t;
+
+typedef enum  {
+    LEDC_REF_TICK = 0, /*LEDC timer clock divided from reference tick(1Mhz) */
+    LEDC_APB_CLK,      /*LEDC timer clock divided from APB clock(80Mhz)*/
+} ledc_clk_src_t;
+
+typedef enum {
+    LEDC_TIMER_0 = 0, /*LEDC source timer TIMER0 */
+    LEDC_TIMER_1,     /*LEDC source timer TIMER1 */
+    LEDC_TIMER_2,     /*LEDC source timer TIMER2 */
+    LEDC_TIMER_3,     /*LEDC source timer TIMER3 */
+} ledc_timer_t;
+
+typedef enum {
+    LEDC_CHANNEL_0 = 0, /*LEDC channel 0 */
+    LEDC_CHANNEL_1,     /*LEDC channel 1 */
+    LEDC_CHANNEL_2,     /*LEDC channel 2 */
+    LEDC_CHANNEL_3,     /*LEDC channel 3 */
+    LEDC_CHANNEL_4,     /*LEDC channel 4 */
+    LEDC_CHANNEL_5,     /*LEDC channel 5 */
+    LEDC_CHANNEL_6,     /*LEDC channel 6 */
+    LEDC_CHANNEL_7,     /*LEDC channel 7 */
+} ledc_channel_t;
+
+typedef enum {
+    LEDC_TIMER_10_BIT = 10, /*LEDC PWM depth 10Bit */
+    LEDC_TIMER_11_BIT = 11, /*LEDC PWM depth 11Bit */
+    LEDC_TIMER_12_BIT = 12, /*LEDC PWM depth 12Bit */
+    LEDC_TIMER_13_BIT = 13, /*LEDC PWM depth 13Bit */
+    LEDC_TIMER_14_BIT = 14, /*LEDC PWM depth 14Bit */
+    LEDC_TIMER_15_BIT = 15, /*LEDC PWM depth 15Bit */
+} ledc_timer_bit_t;
+
+typedef struct {
+    int gpio_num;                   /*the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/
+    ledc_mode_t speed_mode;         /*LEDC speed speed_mode, high-speed mode or low-speed mode*/
+    ledc_channel_t channel;         /*LEDC channel(0 - 7)*/
+    ledc_intr_type_t intr_type;     /*configure interrupt, Fade interrupt enable  or Fade interrupt disable*/
+    ledc_timer_t timer_sel;         /*Select the timer source of channel (0 - 3)*/
+    uint32_t duty;                  /*LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */
+} ledc_channel_config_t;
+
+typedef struct {
+    ledc_mode_t speed_mode;         /*LEDC speed speed_mode, high-speed mode or low-speed mode*/
+    ledc_timer_bit_t bit_num;       /*LEDC channel duty depth*/
+    ledc_timer_t  timer_num;        /*The timer source of channel (0 - 3)*/
+    uint32_t freq_hz;               /*LEDC timer frequency(Hz)*/
+} ledc_timer_config_t;
+
+
+/**
+ * @brief      LEDC channel configuration
+ *
+ * User this Function, configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth
+ *
+ * @param[in]  ledc_channel_config_t
+ *             ledc_channel_config_t.speed_mode     : LEDC speed speed_mode
+ *             ledc_channel_config_t.gpio_num       : LEDC output gpio_num, if you want to use gpio16, ledc_channel_config_t.gpio_num = 16
+ *             ledc_channel_config_t.channel        : LEDC channel(0 - 7)
+ *             ledc_channel_config_t.intr_type      : configure interrupt, Fade interrupt enable  or Fade interrupt disable
+ *             ledc_channel_config_t.timer_sel      : Select the timer source of channel (0 - 3), high speed channel must bind with high speed timer.
+ *             ledc_channel_config_t.duty           : LEDC channel duty, the duty range is [0, (2**timer_bit_num) - 1],
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *
+ */
+esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf);
+
+/**
+ * @brief      LEDC timer configuration
+ *
+ * User this Function, configure LEDC timer with the given source timer/frequency(Hz)/bit_num
+ *
+ * @param[in]  ledc_timer_config_t
+ *             ledc_timer_config_t.speed_mode     : LEDC speed speed_mode
+ *             ledc_timer_config_t.timer_num      : Select the timer source of channel (0 - 3)
+ *             ledc_timer_config_t.freq_hz        : LEDC channel frequency(Hz),
+ *             ledc_timer_config_t.bit_num        : LEDC channel duty depth
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
+ *
+ */
+esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf);
+
+/**
+ * @brief      LEDC update channel parameters
+ *
+ * Call this function to activate the LEDC updated parameters.
+ * After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings.
+ *
+ * @param[in]  speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel    : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *
+ */
+esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
+
+/**
+ * @brief   LEDC stop
+ *
+ * Disable LEDC output, and set idle level
+ *
+ * @param[in]  speed_mode   : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel      : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ */
+esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level);
+
+/**
+ * @brief      LEDC set channel frequency(Hz)
+ *
+ * Set LEDC frequency(Hz)
+ *
+ * @param[in]  speed_mode  : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_num   : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ * @param[in]  freq_hz     : set the LEDC frequency
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
+ */
+esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz);
+
+/**
+ * @brief      LEDC get channel frequency(Hz)
+ *
+ * @param[in]  speed_mode  : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_num   : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ * @return    0      :  error
+ *            others :  current LEDC frequency
+ *
+ */
+uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
+
+/**
+ * @brief      LEDC set duty
+ *
+ * Set LEDC duty, After the function calls the ledc_update_duty function, the function can take effect.
+ *
+ * @param[in]  speed_mode  : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel     : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @param[in]  duty        : set the LEDC duty, the duty range is [0, (2**bit_num) - 1]
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ */
+esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty);
+
+/**
+ * @brief      LEDC get duty
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel : LEDC channel(0-7), select from ledc_channel_t
+ *
+ *
+ * @return     -1: parameter error
+ *             other value: current LEDC duty
+ *
+ */
+int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
+
+/**
+ * @brief      LEDC set gradient
+ *
+ * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect.
+ *
+ * @param[in]  speed_mode           : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel              : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @param[in]  duty                 : set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1]
+ *
+ * @param[in]  gradule_direction    : set the direction of the gradient
+ *
+ * @param[in]  step_num             : set the number of the gradient
+ *
+ * @param[in]  duty_cyle_num        : set how many LEDC tick each time the gradient lasts
+ *
+ * @param[in]  duty_scale           : set gradient change amplitude
+ *
+ * @return     ESP_OK               : success
+ *             ESP_ERR_INVALID_ARG  : parameter error
+ */
+esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction,
+                        uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale);
+
+/**
+ * @brief   register LEDC interrupt handler, the handler is an ISR.
+ *          The handler will be attached to the same CPU core that this function is running on.
+ *          Users should know that which CPU is running and then pick a INUM that is not used by system.
+ *          We can find the information of INUM and interrupt level in soc.h.
+ *          TODO: to move INUM options to menu_config
+ * @param[in]   uint32_t ledc_intr_num    : LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details
+ * @param[in]   void (* fn)(void* )       : interrupt handler function.
+ *                                          Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
+ * @param[in]   void * arg                : parameter for handler function
+ *
+ * @return      ESP_OK                    : success ;
+ *              ESP_ERR_INVALID_ARG       : function ptr error.
+ */
+esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg);
+
+/**
+ * @brief      configure LEDC settings
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : timer index(0-3), there are 4 timers in LEDC module
+ *
+ * @param[in]  div_num       : timer clock divide number, the timer clock is divided from the selected clock source
+ *
+ * @param[in]  bit_num       : the count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1)
+ *
+ * @param[in]  clk_src       : select LEDC source clock.
+ *
+ * @return     -1: parameter error
+ *             other value: current LEDC duty
+ *
+ */
+esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src);
+
+/**
+ * @brief      reset LEDC timer
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
+
+/**
+ * @brief      pause LEDC timer counter
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
+
+/**
+ * @brief      pause LEDC timer resume
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
+
+/**
+ * @brief      bind LEDC channel with the selected timer
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel       : LEDC channel index(0-7), select from ledc_channel_t
+ *
+ * @param[in]  timer_idx     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx);
+
+/***************************EXAMPLE**********************************
+ *
+ *
+ * ----------------EXAMPLE OF LEDC SETTING ---------------------
+ *     //1. enable LEDC
+ *     periph_module_enable(PERIPH_LEDC_MODULE);                //enable LEDC module, or you can not set any register of it.
+ *
+ *     //2. set LEDC timer
+ *     ledc_timer_config_t timer_conf = {
+ *         .bit_num = LEDC_TIMER_12_BIT,                        //set timer counter bit number
+ *         .freq_hz = 1000,                                     //set frequency of pwm, here, 1000Hz
+ *         .speed_mode = LEDC_HIGH_SPEED_MODE                   //timer mode,
+ *         .timer_num = LEDC_TIMER_0,                           //timer number
+ *     };
+ *     ledc_timer_config(&timer_conf);                          //setup timer.
+ *
+ *     //3. set LEDC channel
+ *     ledc_channel_config_t ledc_conf = {
+ *         .channel = LEDC_CHANNEL_0;                           //set LEDC channel 0
+ *         .duty = 1000;                                        //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
+ *         .gpio_num = 16;                                      //GPIO number
+ *         .intr_type = LEDC_INTR_FADE_END;                     //GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
+ *         .speed_mode = LEDC_HIGH_SPEED_MODE;                  //set LEDC mode, from ledc_mode_t
+ *         .timer_sel = LEDC_TIMER_0;                            //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same
+ *     }
+ *     ledc_channel_config(&ledc_conf);                                 //setup the configuration
+ *
+ * ----------------EXAMPLE OF SETTING DUTY --- -----------------
+ *     uint32_t ledc_channel = LEDC_CHANNEL_0;                  //LEDC channel(0-73)
+ *     uint32_t duty = 2000;                                    //duty range is 0 ~ ((2**bit_num)-1)
+ *     LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty.
+ *     ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel);    //after set duty, we need to call ledc_update_duty to update the settings.
+ *
+ *
+ * ----------------EXAMPLE OF LEDC INTERRUPT ------------------
+ *     //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
+ *     ledc_isr_register(18, ledc_isr_handler, NULL);           //hook the isr handler for LEDC interrupt
+ *                                                              //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
+ *                                                              //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
+ *                                                              //NOTE2:do not pick the INUM that already occupied by the system.
+ *                                                              //NOTE3:refer to soc.h to check which INUMs that can be used.
+ * ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
+ * #include "esp_attr.h"
+ * void IRAM_ATTR ledc_isr_handler(void* arg)                   //we should add 'IRAM_ATTR' attribution when we declare the isr function
+ * {
+ *    uint32_t intr_st = LEDC.int_st.val;                       //read LEDC interrupt status.
+ *
+ *    //you will find which channels have triggered fade_end interrupt here,
+ *    //then, you can post some event to RTOS queue to process the event.
+ *    //later we will add a queue in the driver code.
+ *
+ *    LEDC.int_clr.val = intr_st;                               //clear LEDC interrupt status.
+ * }
+ *
+ *
+ *--------------------------END OF EXAMPLE --------------------------
+ */
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_LEDC_H_ */

+ 70 - 0
components/driver/include/driver/periph_ctrl.h

@@ -0,0 +1,70 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+#ifndef _DRIVER_PERIPH_CTRL_H_
+#define _DRIVER_PERIPH_CTRL_H_
+#include "esp_err.h"
+#include "soc/soc.h"
+#include "soc/dport_reg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    PERIPH_LEDC_MODULE = 0,
+    PERIPH_UART0_MODULE,
+    PERIPH_UART1_MODULE,
+    PERIPH_UART2_MODULE,
+    PERIPH_I2C0_MODULE,
+    PERIPH_I2C1_MODULE,
+    PERIPH_I2S0_MODULE,
+    PERIPH_I2S1_MODULE,
+    PERIPH_TIMG0_MODULE,
+    PERIPH_TIMG1_MODULE,
+    PERIPH_PWM0_MODULE,
+    PERIPH_PWM1_MODULE,
+    PERIPH_PWM2_MODULE,
+    PERIPH_PWM3_MODULE,
+    PERIPH_UHCI0_MODULE,
+    PERIPH_UHCI1_MODULE,
+} periph_module_t;
+
+/**
+ * @brief      enable peripheral module
+ *
+ * @param[in]  periph    :  Peripheral module name
+ *
+ *
+ * @return     NULL
+ *
+ */
+void periph_module_enable(periph_module_t periph);
+
+/**
+ * @brief      disable peripheral module
+ *
+ * @param[in]  periph    :  Peripheral module name
+ *
+ *
+ * @return     NULL
+ *
+ */
+void periph_module_disable(periph_module_t periph);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_PERIPH_CTRL_H_ */

+ 432 - 0
components/driver/ledc.c

@@ -0,0 +1,432 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+#include <esp_types.h>
+#include "esp_intr.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "soc/gpio_sig_map.h"
+#include "driver/ledc.h"
+
+//TODO: to use APIs in esp_log.h.
+#define LEDC_DBG_WARING_ENABLE (0)
+#define LEDC_DBG_ERROR_ENABLE  (0)
+#define LEDC_INFO_ENABLE       (0)
+#define LEDC_DBG_ENABLE        (0)
+
+//DBG INFOR
+#if LEDC_DBG_ENABLE
+#define LEDC_DBG(format,...) do{\
+        ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define LEDC_DBG(...)
+#endif
+
+#if LEDC_INFO_ENABLE
+#define LEDC_INFO(format,...) do{\
+        ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define LEDC_INFO(...)
+#endif
+
+#if LEDC_DBG_WARING_ENABLE
+#define LEDC_WARING(format,...) do{\
+        ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define LEDC_WARING(...)
+#endif
+#if LEDC_DBG_ERROR_ENABLE
+#define LEDC_ERROR(format,...) do{\
+        ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
+        ets_printf(format,##__VA_ARGS__);\
+}while(0)
+#else
+#define LEDC_ERROR(...)
+#endif
+
+static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
+
+static bool ledc_is_valid_channel(uint32_t channel)
+{
+    if(channel > LEDC_CHANNEL_7) {
+        LEDC_ERROR("LEDC CHANNEL ERR: %d\n",channel);
+        return false;
+    }
+    return true;
+}
+
+static bool ledc_is_valid_mode(uint32_t mode)
+{
+    if(mode >= LEDC_SPEED_MODE_MAX) {
+        LEDC_ERROR("LEDC MODE ERR: %d\n",mode);
+        return false;
+    }
+    return true;
+}
+
+static bool ledc_is_valid_timer(int timer)
+{
+    if(timer > LEDC_TIMER_3) {
+        LEDC_ERROR("LEDC TIMER ERR: %d\n", timer);
+        return false;
+    }
+    return true;
+}
+
+esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_timer(timer_sel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.div_num = div_num;
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num = bit_num;
+    if(speed_mode != LEDC_HIGH_SPEED_MODE) {
+        LEDC.timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
+    }
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num, uint32_t hpoint_val, uint32_t duty_val,
+    uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
+{
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
+    LEDC.channel_group[speed_mode].channel[channel_num].duty.duty = duty_val;
+    LEDC.channel_group[speed_mode].channel[channel_num].conf1.val = ((duty_direction & LEDC_DUTY_INC_HSCH0_V) << LEDC_DUTY_INC_HSCH0_S) |
+                                                                    ((duty_num & LEDC_DUTY_NUM_HSCH0_V) << LEDC_DUTY_NUM_HSCH0_S) |
+                                                                    ((duty_cycle & LEDC_DUTY_CYCLE_HSCH0_V) << LEDC_DUTY_CYCLE_HSCH0_S) |
+                                                                    ((duty_scale & LEDC_DUTY_SCALE_HSCH0_V) << LEDC_DUTY_SCALE_HSCH0_S);
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_timer(timer_idx)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_timer(timer_sel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_timer(timer_sel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_timer(timer_sel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    uint32_t value;
+    uint32_t intr_type = type;
+    portENTER_CRITICAL(&ledc_spinlock);
+    value = LEDC.int_ena.val;
+    if(intr_type == LEDC_INTR_FADE_END) {
+        LEDC.int_ena.val = value | BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel);
+    } else {
+        LEDC.int_ena.val = (value & (~(BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel))));
+    }
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg)
+{
+    if(fn == NULL) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    ESP_INTR_DISABLE(ledc_intr_num);
+    intr_matrix_set(xPortGetCoreID(), ETS_LEDC_INTR_SOURCE, ledc_intr_num);
+    xt_set_interrupt_handler(ledc_intr_num, fn, arg);
+    ESP_INTR_ENABLE(ledc_intr_num);
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
+{
+    int freq_hz = timer_conf->freq_hz;
+    int bit_num = timer_conf->bit_num;
+    int timer_num = timer_conf->timer_num;
+    int speed_mode = timer_conf->speed_mode;
+
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) {
+        LEDC_ERROR("freq_hz=%u bit_num=%u\n", freq_hz, bit_num);
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(timer_num > LEDC_TIMER_3) {
+        LEDC_ERROR("Time Select %u\n", timer_num);
+        return ESP_ERR_INVALID_ARG;
+    }
+    esp_err_t ret = ESP_OK;
+    uint32_t precision = (0x1 << bit_num);  //2**depth
+    uint64_t div_param = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision; //8bit fragment
+    int timer_clk_src;
+    /*Fail ,because the div_num overflow or too small*/
+    if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { //REF TICK
+        /*Selet the reference tick*/
+        div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
+        if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
+            LEDC_ERROR("div param err,div_param=%u\n", div_param);
+            ret = ESP_FAIL;
+        }
+        timer_clk_src = LEDC_REF_TICK;
+    } else { //APB TICK
+        timer_clk_src = LEDC_APB_CLK;
+    }
+    /*set timer parameters*/
+    /*timer settings decide the clk of counter and the period of PWM*/
+    ledc_timer_set(speed_mode, timer_num, div_param, bit_num, timer_clk_src);
+    /*   reset timer.*/
+    ledc_timer_rst(speed_mode, timer_num);
+    return ret;
+}
+
+esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
+{
+    uint32_t speed_mode = ledc_conf->speed_mode;
+    uint32_t gpio_num = ledc_conf->gpio_num;
+    uint32_t ledc_channel = ledc_conf->channel;
+    uint32_t timer_select = ledc_conf->timer_sel;
+    uint32_t intr_type = ledc_conf->intr_type;
+    uint32_t duty = ledc_conf->duty;
+
+    if(!ledc_is_valid_channel(ledc_channel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)) {
+        LEDC_ERROR("GPIO number error: IO%d\n ", gpio_num);
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(timer_select > LEDC_TIMER_3) {
+        LEDC_ERROR("Time Select %u\n", timer_select);
+        return ESP_ERR_INVALID_ARG;
+    }
+    esp_err_t ret = ESP_OK;
+    /*set channel parameters*/
+    /*   channel parameters decide how the waveform looks like in one period*/
+    /*   set channel duty, duty range is (0 ~ ((2 ** bit_num) - 1))*/
+    ledc_set_duty(speed_mode, ledc_channel, duty);
+    /*update duty settings*/
+    ledc_update_duty(speed_mode, ledc_channel);
+    /*bind the channel with the timer*/
+    ledc_bind_channel_timer(speed_mode, ledc_channel, timer_select);
+    /*set interrupt type*/
+    ledc_enable_intr_type(speed_mode, ledc_channel, intr_type);
+    LEDC_INFO("LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u\n",
+        ledc_channel, gpio_num, duty, timer_select
+    );
+    /*set LEDC signal in gpio matrix*/
+    PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
+    gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
+    gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0);
+    return ret;
+}
+
+esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_channel(channel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
+    LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_channel(channel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.channel_group[speed_mode].channel[channel].conf0.idle_lv = idle_level & 0x1;
+    LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0;
+    LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 0;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
+    uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_channel(channel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(fade_direction > LEDC_DUTY_DIR_INCREASE) {
+        LEDC_ERROR("Duty direction err\n");
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) {
+        LEDC_ERROR("step_num=%u duty_cyle_num=%u duty_scale=%u\n", step_num, duty_cyle_num, duty_scale);
+        return ESP_ERR_INVALID_ARG;
+    }
+    ledc_duty_config(speed_mode,
+                     channel,        //uint32_t chan_num,
+                     0,              //uint32_t hpoint_val,
+                     duty << 4,      //uint32_t duty_val,the least 4 bits are decimal part
+                     fade_direction, //uint32_t increase,
+                     step_num,       //uint32_t duty_num,
+                     duty_cyle_num,  //uint32_t duty_cycle,
+                     duty_scale      //uint32_t duty_scale
+                     );
+    return ESP_OK;
+}
+
+esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(!ledc_is_valid_channel(channel)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    ledc_duty_config(speed_mode,
+                     channel,         //uint32_t chan_num,
+                     0,               //uint32_t hpoint_val,
+                     duty << 4,       //uint32_t duty_val,the least 4 bits are decimal part
+                     1,               //uint32_t increase,
+                     1,               //uint32_t duty_num,
+                     1,               //uint32_t duty_cycle,
+                     0                //uint32_t duty_scale
+                     );
+    return ESP_OK;
+}
+
+int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return -1;
+    }
+    uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
+    return duty;
+}
+
+esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    esp_err_t ret = ESP_OK;
+    uint32_t div_num = 0;
+    uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num;
+    uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
+    uint32_t precision = (0x1 << bit_num);
+    if(timer_source_clk == LEDC_APB_CLK) {
+        div_num = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision;
+    } else {
+        div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
+    }
+    if(div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) {
+        LEDC_ERROR("div param err,div_param=%u\n", div_num);
+        ret = ESP_FAIL;
+    }
+    LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num = div_num;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ret;
+}
+
+uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return 0;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    uint32_t freq = 0;
+    uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
+    uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num;
+    uint32_t div_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num;
+    uint32_t precision = (0x1 << bit_num);
+    if(timer_source_clk == LEDC_APB_CLK) {
+        freq = ((uint64_t) LEDC_APB_CLK_HZ << 8) / precision / div_num;
+    } else {
+        freq = ((uint64_t) LEDC_REF_CLK_HZ << 8) / precision / div_num;
+    }
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return freq;
+}

+ 170 - 0
components/driver/periph_ctrl.c

@@ -0,0 +1,170 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+#include <esp_types.h>
+#include "esp_intr.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "soc/dport_reg.h"
+#include "driver/periph_ctrl.h"
+
+static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
+
+void periph_module_enable(periph_module_t periph)
+{
+    portENTER_CRITICAL(&periph_spinlock);
+    switch(periph) {
+        case PERIPH_LEDC_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
+            break;
+        case PERIPH_UART0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
+            break;
+        case PERIPH_UART1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
+            break;
+        case PERIPH_UART2_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
+            break;
+        case PERIPH_I2C0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);
+            break;
+        case PERIPH_I2C1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT1_RST);
+            break;
+        case PERIPH_I2S0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+            break;
+        case PERIPH_I2S1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
+            break;
+        case PERIPH_TIMG0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
+            break;
+        case PERIPH_TIMG1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
+            break;
+        case PERIPH_PWM0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
+            break;
+        case PERIPH_PWM1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
+            break;
+        case PERIPH_PWM2_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM2_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM2_RST);
+            break;
+        case PERIPH_PWM3_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM3_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM3_RST);
+            break;
+        case PERIPH_UHCI0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI0_RST);
+            break;
+        case PERIPH_UHCI1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
+            break;
+        default:
+            break;
+    }
+    portEXIT_CRITICAL(&periph_spinlock);
+}
+
+void periph_module_disable(periph_module_t periph)
+{
+    portENTER_CRITICAL(&periph_spinlock);
+    switch(periph) {
+        case PERIPH_LEDC_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
+            break;
+        case PERIPH_UART0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
+            break;
+        case PERIPH_UART1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
+            break;
+        case PERIPH_UART2_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
+            break;
+        case PERIPH_I2C0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);
+            break;
+        case PERIPH_I2C1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT1_RST);
+            break;
+        case PERIPH_I2S0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+            break;
+        case PERIPH_I2S1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
+            break;
+        case PERIPH_TIMG0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
+            break;
+        case PERIPH_TIMG1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
+            break;
+        case PERIPH_PWM0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
+            break;
+        case PERIPH_PWM1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
+            break;
+        case PERIPH_PWM2_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM2_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM2_RST);
+            break;
+        case PERIPH_PWM3_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM3_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM3_RST);
+            break;
+        case PERIPH_UHCI0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI0_RST);
+            break;
+        case PERIPH_UHCI1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
+            break;
+        default:
+            break;
+    }
+    portEXIT_CRITICAL(&periph_spinlock);
+}

+ 48 - 29
components/esp32/Kconfig

@@ -63,6 +63,12 @@ config MEMMAP_TRACEMEM
         of memory that can't be used for general purposes anymore. Disable this if you do not know
         what this is.
 
+# Memory to reverse for trace, used in linker script
+config TRACEMEM_RESERVE_DRAM
+    hex
+    default 0x8000 if MEMMAP_TRACEMEM
+    default 0x0
+
 config MEMMAP_SPISRAM
     bool "Use external SPI SRAM chip as main memory"
     default "n"
@@ -78,47 +84,60 @@ config WIFI_ENABLED
     help
         This compiles in the low-level WiFi stack.
 
-		Temporarily, this option is not compatible with BT stack.
-
-config WIFI_AUTO_STARTUP
-    bool "Start WiFi with system startup"
-    default "y"
-    depends on WIFI_ENABLED
-    help
-        By default, WiFi is started with system startup, you can turn off this
-        feature and start by yourself.
-
-config WIFI_AUTO_CONNECT
-    bool "Enable auto connect"
-    default "y"
-    depends on WIFI_ENABLED
-    help
-        If station is enabled, and station config is set, this will enable WiFi
-        station auto connect when WiFi startup.
+        Temporarily, this option is not compatible with BT stack.
 
 config SYSTEM_EVENT_QUEUE_SIZE
-    int "system event queue size"
+    int "System event queue size"
     default 32
-    depends on WIFI_ENABLED
     help
         Config system event queue size in different application.
 
 config SYSTEM_EVENT_TASK_STACK_SIZE
-    int "system event task stack size"
+    int "Event loop task stack size"
     default 2048
-    depends on WIFI_ENABLED
+    help
+        Config system event task stack size in different application.
+
+
+config MAIN_TASK_STACK_SIZE
+    int "Main task stack size"
+    default 4096
     help
         Config system event task stack size in different application.
 
 
 config NEWLIB_STDOUT_ADDCR
-	bool "Standard-out output adds carriage return before newline"
-	default y
-	help
-		Most people are used to end their printf strings with a newline. If this
-		is sent as is to the serial port, most terminal programs will only move the
-		cursor one line down, not also move it to the beginning of the line. This
-		is usually done by an added CR character. Enabling this will make the
-		standard output code automatically add a CR character before a LF.
+    bool "Standard-out output adds carriage return before newline"
+    default y
+    help
+        Most people are used to end their printf strings with a newline. If this
+        is sent as is to the serial port, most terminal programs will only move the
+        cursor one line down, not also move it to the beginning of the line. This
+        is usually done by an added CR character. Enabling this will make the
+        standard output code automatically add a CR character before a LF.
+
+config ULP_COPROC_ENABLED
+    bool "Enable Ultra Low Power (ULP) Coprocessor"
+    default "n"
+    help
+        Set to 'y' if you plan to load a firmware for the coprocessor.
+
+        If this option is enabled, further coprocessor configuration will appear in the Components menu.
+
+config ULP_COPROC_RESERVE_MEM
+    int "RTC slow memory reserved for coprocessor"
+    default 512
+    range 32 8192
+    depends on ULP_COPROC_ENABLED
+    help
+        Bytes of memory to reserve for ULP coprocessor firmware & data.
+
+        Data is reserved at the beginning of RTC slow memory.
+
+# Set CONFIG_ULP_COPROC_RESERVE_MEM to 0 if ULP is disabled
+config ULP_COPROC_RESERVE_MEM
+    int
+    default 0
+    depends on !ULP_COPROC_ENABLED
 
 endmenu

+ 14 - 17
components/esp32/component.mk

@@ -10,23 +10,9 @@
 
 COMPONENT_SRCDIRS := . hwcrypto
 
-LIBS := crypto core net80211 phy rtc pp wpa wps
-
-ifeq ($(CONFIG_MEMMAP_BT),y)
-    ifeq ($(CONFIG_MEMMAP_TRACEMEM),y)
-        LINKER_SCRIPTS = -T esp32.bt.trace.ld
-    else
-        LINKER_SCRIPTS = -T esp32.bt.ld
-    endif
-else
-    ifeq ($(CONFIG_MEMMAP_TRACEMEM),y)
-        LINKER_SCRIPTS = -T esp32.trace.ld
-    else
-        LINKER_SCRIPTS = -T esp32.ld
-    endif
-endif
-
-LINKER_SCRIPTS += -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
+LIBS := crypto core net80211 phy rtc pp wpa smartconfig
+
+LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
 
 COMPONENT_ADD_LDFLAGS := -lesp32 \
                            $(abspath libhal.a) \
@@ -51,3 +37,14 @@ $(eval $(call SubmoduleRequiredForFiles,$(ALL_LIB_FILES)))
 # It would be better for components to be able to expose any of these
 # non-standard dependencies via get_variable, but this will do for now.
 $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
+
+# Preprocess esp32.ld linker script into esp32_out.ld
+#
+# The library doesn't really depend on esp32_out.ld, but it
+# saves us from having to add the target to a Makefile.projbuild
+$(COMPONENT_LIBRARY): esp32_out.ld
+
+esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h
+	$(CC) -I ../include -C -P -x c -E $< -o $@
+
+COMPONENT_EXTRA_CLEAN := esp32_out.ld

+ 43 - 49
components/esp32/cpu_start.c

@@ -43,14 +43,19 @@
 #include "esp_ipc.h"
 #include "esp_log.h"
 
-static void IRAM_ATTR user_start_cpu0(void);
-static void IRAM_ATTR call_user_start_cpu1();
-static void IRAM_ATTR user_start_cpu1(void);
+void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
+void start_cpu0_default(void) IRAM_ATTR;
+#if !CONFIG_FREERTOS_UNICORE
+static void IRAM_ATTR call_start_cpu1();
+void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default")));
+void start_cpu1_default(void) IRAM_ATTR;
+static bool app_cpu_started = false;
+#endif //!CONFIG_FREERTOS_UNICORE
+
+static void do_global_ctors(void);
+static void main_task(void* args);
 extern void ets_setup_syscalls(void);
-extern esp_err_t app_main(void *ctx);
-#if CONFIG_BT_ENABLED
-extern void bt_app_main(void *param);
-#endif
+extern void app_main(void);
 
 extern int _bss_start;
 extern int _bss_end;
@@ -60,14 +65,13 @@ extern void (*__init_array_end)(void);
 extern volatile int port_xSchedulerRunning[2];
 
 static const char* TAG = "cpu_start";
-static bool app_cpu_started = false;
 
 /*
  * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
  * and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
  */
 
-void IRAM_ATTR call_user_start_cpu0()
+void IRAM_ATTR call_start_cpu0()
 {
     //Kill wdt
     REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
@@ -90,14 +94,14 @@ void IRAM_ATTR call_user_start_cpu0()
 
     ESP_EARLY_LOGI(TAG, "Pro cpu up.");
 
-#ifndef CONFIG_FREERTOS_UNICORE
-    ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_user_start_cpu1);
+#if !CONFIG_FREERTOS_UNICORE
+    ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
 
     SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
     SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
-    ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
+    ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1);
 
     while (!app_cpu_started) {
         ets_delay_us(100);
@@ -107,11 +111,11 @@ void IRAM_ATTR call_user_start_cpu0()
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
 #endif
     ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
-    user_start_cpu0();
+    start_cpu0();
 }
 
-
-void IRAM_ATTR call_user_start_cpu1()
+#if !CONFIG_FREERTOS_UNICORE
+void IRAM_ATTR call_start_cpu1()
 {
     asm volatile (\
                   "wsr    %0, vecbase\n" \
@@ -121,10 +125,27 @@ void IRAM_ATTR call_user_start_cpu1()
 
     ESP_EARLY_LOGI(TAG, "App cpu up.");
     app_cpu_started = 1;
-    user_start_cpu1();
+    start_cpu1();
+}
+#endif //!CONFIG_FREERTOS_UNICORE
+
+void start_cpu0_default(void)
+{
+    esp_set_cpu_freq();     // set CPU frequency configured in menuconfig
+    uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
+    ets_setup_syscalls();
+    do_global_ctors();
+    esp_ipc_init();
+    spi_flash_init();
+    xTaskCreatePinnedToCore(&main_task, "main",
+            ESP_TASK_MAIN_STACK, NULL,
+            ESP_TASK_MAIN_PRIO, NULL, 0);
+    ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
+    vTaskStartScheduler();
 }
 
-void IRAM_ATTR user_start_cpu1(void)
+#if !CONFIG_FREERTOS_UNICORE
+void start_cpu1_default(void)
 {
     // Wait for FreeRTOS initialization to finish on PRO CPU
     while (port_xSchedulerRunning[0] == 0) {
@@ -133,46 +154,19 @@ void IRAM_ATTR user_start_cpu1(void)
     ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
     xPortStartScheduler();
 }
+#endif //!CONFIG_FREERTOS_UNICORE
 
 static void do_global_ctors(void)
 {
     void (**p)(void);
-    for (p = &__init_array_start; p != &__init_array_end; ++p) {
+    for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
         (*p)();
     }
 }
 
-void user_start_cpu0(void)
+static void main_task(void* args)
 {
-    esp_set_cpu_freq();     // set CPU frequency configured in menuconfig
-    uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
-    ets_setup_syscalls();
-    do_global_ctors();
-    esp_ipc_init();
-    spi_flash_init();
-
-#if CONFIG_WIFI_ENABLED
-    esp_err_t ret = nvs_flash_init(5, 3);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "nvs_flash_init failed, ret=%d", ret);
-    }
-
-    system_init();
-    esp_event_init(NULL, NULL);
-    tcpip_adapter_init();
-#endif
-
-#if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP
-#include "esp_wifi.h"
-	esp_wifi_startup(app_main, NULL);
-#elif CONFIG_BT_ENABLED
-#include "bt.h"
-        esp_bt_startup(bt_app_main, NULL);
-#else
-    app_main(NULL);
-#endif
-
-    ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
-    vTaskStartScheduler();
+    app_main();
+    vTaskDelete(NULL);
 }
 

+ 49 - 0
components/esp32/deepsleep.c

@@ -0,0 +1,49 @@
+/* Wake from deep sleep stub
+
+   See esp_deepsleep.h esp_wake_deep_sleep() comments for details.
+*/
+#include <stddef.h>
+#include <sys/lock.h>
+#include "rom/cache.h"
+#include "rom/rtc.h"
+#include "soc/rtc_cntl_reg.h"
+#include "soc/dport_reg.h"
+#include "esp_attr.h"
+#include "esp_deepsleep.h"
+
+/* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
+   is not thread-safe. */
+static _lock_t lock_rtc_memory_crc;
+
+esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void)
+{
+    _lock_acquire(&lock_rtc_memory_crc);
+    uint32_t stored_crc = REG_READ(RTC_MEMORY_CRC_REG);
+    set_rtc_memory_crc();
+    uint32_t calc_crc = REG_READ(RTC_MEMORY_CRC_REG);
+    REG_WRITE(RTC_MEMORY_CRC_REG, stored_crc);
+    _lock_release(&lock_rtc_memory_crc);
+
+    if(stored_crc == calc_crc) {
+        return (esp_deep_sleep_wake_stub_fn_t)REG_READ(RTC_ENTRY_ADDR_REG);
+    } else {
+        return NULL;
+    }
+}
+
+void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub)
+{
+    _lock_acquire(&lock_rtc_memory_crc);
+    REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub);
+    set_rtc_memory_crc();
+    _lock_release(&lock_rtc_memory_crc);
+}
+
+void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
+    //
+    //mmu_init(0);
+    REG_SET_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
+    REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
+}
+
+void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_sleep(void);

+ 38 - 124
components/esp32/event.c → components/esp32/event_default_handlers.c

@@ -19,6 +19,7 @@
 #include "esp_err.h"
 #include "esp_wifi.h"
 #include "esp_event.h"
+#include "esp_event_loop.h"
 #include "esp_task.h"
 
 #include "freertos/FreeRTOS.h"
@@ -27,22 +28,15 @@
 #include "freertos/semphr.h"
 
 #include "tcpip_adapter.h"
+#include "esp_log.h"
 
-#define ESP32_WORKAROUND 1
+const char* TAG = "event";
 
-#if CONFIG_WIFI_ENABLED
-static bool event_init_flag = false;
-static xQueueHandle g_event_handler = NULL;
-
-static system_event_cb_t g_event_handler_cb;
-static void *g_event_ctx;
-
-#define WIFI_DEBUG(...)
 #define WIFI_API_CALL_CHECK(info, api_call, ret) \
 do{\
     esp_err_t __err = (api_call);\
     if ((ret) != __err) {\
-        WIFI_DEBUG("%s %d %s ret=%d\n", __FUNCTION__, __LINE__, (info), __err);\
+        ESP_LOGE(TAG, "%s %d %s ret=%d", __FUNCTION__, __LINE__, (info), __err);\
         return __err;\
     }\
 } while(0)
@@ -71,7 +65,7 @@ static system_event_handle_t g_system_event_handle_table[] = {
     {SYSTEM_EVENT_STA_CONNECTED,       system_event_sta_connected_handle_default},
     {SYSTEM_EVENT_STA_DISCONNECTED,    system_event_sta_disconnected_handle_default},
     {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
-    {SYSTEM_EVENT_STA_GOT_IP,           system_event_sta_got_ip_default},
+    {SYSTEM_EVENT_STA_GOT_IP,          system_event_sta_got_ip_default},
     {SYSTEM_EVENT_AP_START,            system_event_ap_start_handle_default},
     {SYSTEM_EVENT_AP_STOP,             system_event_ap_stop_handle_default},
     {SYSTEM_EVENT_AP_STACONNECTED,     NULL},
@@ -85,7 +79,7 @@ static esp_err_t system_event_sta_got_ip_default(system_event_t *event)
     extern esp_err_t esp_wifi_set_sta_ip(void);
     WIFI_API_CALL_CHECK("esp_wifi_set_sta_ip", esp_wifi_set_sta_ip(), ESP_OK);
 
-    printf("ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR "\n",
+    ESP_LOGI(TAG, "ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
            IP2STR(&event->event_info.got_ip.ip_info.ip),
            IP2STR(&event->event_info.got_ip.ip_info.netmask),
            IP2STR(&event->event_info.got_ip.ip_info.gw));
@@ -161,7 +155,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
 
             esp_event_send(&evt);
         } else {
-            WIFI_DEBUG("invalid static ip\n");
+            ESP_LOGE(TAG, "invalid static ip");
         }
     }
 
@@ -175,104 +169,89 @@ esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event)
     return ESP_OK;
 }
 
-static esp_err_t esp_wifi_post_event_to_user(system_event_t *event)
-{
-    if (g_event_handler_cb) {
-        return (*g_event_handler_cb)(g_event_ctx, event);
-    }
-
-    return ESP_OK;
-}
-
 static esp_err_t esp_system_event_debug(system_event_t *event)
 {
     if (event == NULL) {
-        printf("Error: event is null!\n");
+        ESP_LOGE(TAG, "event is null!");
         return ESP_FAIL;
     }
 
-    WIFI_DEBUG("received event: ");
     switch (event->event_id) {
     case SYSTEM_EVENT_WIFI_READY: {
-        WIFI_DEBUG("SYSTEM_EVENT_WIFI_READY\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_WIFI_READY");
         break;
     }
     case SYSTEM_EVENT_SCAN_DONE: {
-        system_event_sta_scan_done_t *scan_done;
-        scan_done = &event->event_info.scan_done;
-        WIFI_DEBUG("SYSTEM_EVENT_SCAN_DONE\nstatus:%d, number:%d\n",  scan_done->status, scan_done->number);
+        system_event_sta_scan_done_t *scan_done = &event->event_info.scan_done;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_SCAN_DONE, status:%d, number:%d",  scan_done->status, scan_done->number);
         break;
     }
     case SYSTEM_EVENT_STA_START: {
-        WIFI_DEBUG("SYSTEM_EVENT_STA_START\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_START");
         break;
     }
     case SYSTEM_EVENT_STA_STOP: {
-        WIFI_DEBUG("SYSTEM_EVENT_STA_STOP\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_STOP");
         break;
     }
     case SYSTEM_EVENT_STA_CONNECTED: {
-        system_event_sta_connected_t *connected;
-        connected = &event->event_info.connected;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_CONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d\n", \
+        system_event_sta_connected_t *connected = &event->event_info.connected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d", \
                    connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \
                    connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode);
         break;
     }
     case SYSTEM_EVENT_STA_DISCONNECTED: {
-        system_event_sta_disconnected_t *disconnected;
-        disconnected = &event->event_info.disconnected;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_DISCONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d\n", \
+        system_event_sta_disconnected_t *disconnected = &event->event_info.disconnected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d", \
                    disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \
                    disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason);
         break;
     }
     case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: {
-        system_event_sta_authmode_change_t *auth_change;
-        auth_change = &event->event_info.auth_change;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_AUTHMODE_CHNAGE\nold_mode:%d, new_mode:%d\n", auth_change->old_mode, auth_change->new_mode);
+        system_event_sta_authmode_change_t *auth_change = &event->event_info.auth_change;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_AUTHMODE_CHNAGE, old_mode:%d, new_mode:%d", auth_change->old_mode, auth_change->new_mode);
         break;
     }
     case SYSTEM_EVENT_STA_GOT_IP: {
-        system_event_sta_got_ip_t *got_ip;
-        got_ip = &event->event_info.got_ip;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_GOTIP\n");
+        system_event_sta_got_ip_t *got_ip = &event->event_info.got_ip;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOTIP, ip:" IPSTR ", mask:" IPSTR ", gw:" IPSTR,
+            IP2STR(&got_ip->ip_info.ip),
+            IP2STR(&got_ip->ip_info.netmask),
+            IP2STR(&got_ip->ip_info.gw));
         break;
     }
     case SYSTEM_EVENT_AP_START: {
-        WIFI_DEBUG("SYSTEM_EVENT_AP_START\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
         break;
     }
     case SYSTEM_EVENT_AP_STOP: {
-        WIFI_DEBUG("SYSTEM_EVENT_AP_STOP\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STOP");
         break;
     }
     case SYSTEM_EVENT_AP_STACONNECTED: {
-        system_event_ap_staconnected_t *staconnected;
-        staconnected = &event->event_info.sta_connected;
-        WIFI_DEBUG("SYSTEM_EVENT_AP_STACONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
+        system_event_ap_staconnected_t *staconnected = &event->event_info.sta_connected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \
                    staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \
                    staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid);
         break;
     }
     case SYSTEM_EVENT_AP_STADISCONNECTED: {
-        system_event_ap_stadisconnected_t *stadisconnected;
-        stadisconnected = &event->event_info.sta_disconnected;
-        WIFI_DEBUG("SYSTEM_EVENT_AP_STADISCONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
+        system_event_ap_stadisconnected_t *stadisconnected = &event->event_info.sta_disconnected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \
                    stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \
                    stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid);
         break;
     }
     case SYSTEM_EVENT_AP_PROBEREQRECVED: {
-        system_event_ap_probe_req_rx_t *ap_probereqrecved;
-        ap_probereqrecved = &event->event_info.ap_probereqrecved;
-        WIFI_DEBUG("SYSTEM_EVENT_AP_PROBEREQRECVED\nrssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x\n", \
+        system_event_ap_probe_req_rx_t *ap_probereqrecved = &event->event_info.ap_probereqrecved;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x", \
                    ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \
                    ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]);
         break;
     }
     default: {
-        printf("Error: no such kind of event!\n");
+        ESP_LOGW(TAG, "no such kind of event!");
         break;
     }
     }
@@ -280,88 +259,23 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
     return ESP_OK;
 }
 
-static esp_err_t esp_system_event_handler(system_event_t *event)
+esp_err_t esp_event_process_default(system_event_t *event)
 {
     if (event == NULL) {
-        printf("Error: event is null!\n");
+        ESP_LOGE(TAG, "Error: event is null!");
         return ESP_FAIL;
     }
 
     esp_system_event_debug(event);
     if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)) {
         if (g_system_event_handle_table[event->event_id].event_handle) {
-            WIFI_DEBUG("enter default callback\n");
+            ESP_LOGV(TAG, "enter default callback");
             g_system_event_handle_table[event->event_id].event_handle(event);
-            WIFI_DEBUG("exit default callback\n");
+            ESP_LOGV(TAG, "exit default callback");
         }
     } else {
-        printf("mismatch or invalid event, id=%d\n", event->event_id);
-    }
-
-    return esp_wifi_post_event_to_user(event);
-}
-
-static void esp_system_event_task(void *pvParameters)
-{
-    system_event_t evt;
-    esp_err_t ret;
-
-    while (1) {
-        if (xQueueReceive(g_event_handler, &evt, portMAX_DELAY) == pdPASS) {
-            ret = esp_system_event_handler(&evt);
-            if (ret == ESP_FAIL) {
-                printf("esp wifi post event to user fail!\n");
-            }
-        }
-    }
-}
-
-system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx)
-{
-    system_event_cb_t old_cb = g_event_handler_cb;
-
-    g_event_handler_cb = cb;
-    g_event_ctx = ctx;
-
-    return old_cb;
-}
-
-esp_err_t esp_event_send(system_event_t *event)
-{
-    portBASE_TYPE ret;
-
-    ret = xQueueSendToBack((xQueueHandle)g_event_handler, event, 0);
-
-    if (pdPASS != ret) {
-        if (event) {
-            printf("e=%d f\n", event->event_id);
-        } else {
-            printf("e null\n");
-        }
-        return ESP_FAIL;
-    }
-
-    return ESP_OK;
-}
-
-void *esp_event_get_handler(void)
-{
-    return (void *)g_event_handler;
-}
-
-esp_err_t esp_event_init(system_event_cb_t cb, void *ctx)
-{
-    if (event_init_flag) {
+        ESP_LOGE(TAG, "mismatch or invalid event, id=%d", event->event_id);
         return ESP_FAIL;
     }
-
-    g_event_handler_cb = cb;
-    g_event_ctx = ctx;
-
-    g_event_handler = xQueueCreate(CONFIG_SYSTEM_EVENT_QUEUE_SIZE, sizeof(system_event_t));
-
-    xTaskCreatePinnedToCore(esp_system_event_task, "eventTask", ESP_TASKD_EVENT_STACK, NULL, ESP_TASKD_EVENT_PRIO, NULL, 0);
     return ESP_OK;
 }
-
-#endif

+ 107 - 0
components/esp32/event_loop.c

@@ -0,0 +1,107 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "esp_err.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "esp_event_loop.h"
+#include "esp_task.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+
+#include "esp_log.h"
+#include "sdkconfig.h"
+
+
+static const char* TAG = "event";
+static bool s_event_init_flag = false;
+static QueueHandle_t s_event_queue = NULL;
+static system_event_cb_t s_event_handler_cb = NULL;
+static void *s_event_ctx = NULL;
+
+static esp_err_t esp_event_post_to_user(system_event_t *event)
+{
+    if (s_event_handler_cb) {
+        return (*s_event_handler_cb)(s_event_ctx, event);
+    }
+    return ESP_OK;
+}
+
+static void esp_event_loop_task(void *pvParameters)
+{
+    while (1) {
+        system_event_t evt;
+        if (xQueueReceive(s_event_queue, &evt, portMAX_DELAY) == pdPASS) {
+            esp_err_t ret = esp_event_process_default(&evt);
+            if (ret != ESP_OK) {
+                ESP_LOGE(TAG, "default event handler failed!");
+            }
+            ret = esp_event_post_to_user(&evt);
+            if (ret != ESP_OK) {
+                ESP_LOGE(TAG, "post event to user fail!");
+            }
+        }
+    }
+}
+
+system_event_cb_t esp_event_loop_set_cb(system_event_cb_t cb, void *ctx)
+{
+    system_event_cb_t old_cb = s_event_handler_cb;
+    s_event_handler_cb = cb;
+    s_event_ctx = ctx;
+    return old_cb;
+}
+
+esp_err_t esp_event_send(system_event_t *event)
+{
+    portBASE_TYPE ret = xQueueSendToBack(s_event_queue, event, 0);
+    if (ret != pdPASS) {
+        if (event) {
+            ESP_LOGE(TAG, "e=%d f", event->event_id);
+        } else {
+            ESP_LOGE(TAG, "e null");
+        }
+        return ESP_FAIL;
+    }
+    return ESP_OK;
+}
+
+QueueHandle_t esp_event_loop_get_queue(void)
+{
+    return s_event_queue;
+}
+
+esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx)
+{
+    if (s_event_init_flag) {
+        return ESP_FAIL;
+    }
+    s_event_handler_cb = cb;
+    s_event_ctx = ctx;
+    s_event_queue = xQueueCreate(CONFIG_SYSTEM_EVENT_QUEUE_SIZE, sizeof(system_event_t));
+
+    xTaskCreatePinnedToCore(esp_event_loop_task, "eventTask",
+            ESP_TASKD_EVENT_STACK, NULL, ESP_TASKD_EVENT_PRIO, NULL, 0);
+
+    s_event_init_flag = true;
+    return ESP_OK;
+}
+

+ 14 - 2
components/esp32/include/esp_attr.h

@@ -17,8 +17,8 @@
 #define ROMFN_ATTR
 
 //Normally, the linker script will put all code and rodata in flash,
-//and all variables in shared RAM. This can be redirected to IRAM if
-//needed using these macros.
+//and all variables in shared RAM. These macros can be used to redirect
+//particular functions/variables to other memory regions.
 
 // Forces code into IRAM instead of flash
 #define IRAM_ATTR __attribute__((section(".iram1")))
@@ -26,4 +26,16 @@
 // Forces data into DRAM instead of flash
 #define DRAM_ATTR __attribute__((section(".dram1")))
 
+// Forces code into RTC fast memory
+#define RTC_IRAM_ATTR __attribute__((section(".rtc.text")))
+
+// Forces data into RTC slow memory
+// Any variable marked with this attribute will keep its value
+// during a deep sleep / wake cycle.
+#define RTC_DATA_ATTR __attribute__((section(".rtc.data")))
+
+// Forces read-only data into RTC slow memory
+// Makes constant data available to RTC wake stubs (see esp_deepsleep.h)
+#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata")))
+
 #endif /* __ESP_ATTR_H__ */

+ 137 - 0
components/esp32/include/esp_deepsleep.h

@@ -0,0 +1,137 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+#ifndef __ESP_DEEPSLEEP_H__
+#define __ESP_DEEPSLEEP_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup Deep_Sleep_API Deep Sleep API
+  * @brief API for putting device into deep sleep
+  */
+
+/** @addtogroup Deep_Sleep_API
+  * @{
+  */
+
+/**
+  * @brief     Set the chip to deep-sleep mode.
+  *
+  *            The device will automatically wake up after the deep-sleep time set
+  *            by the users. Upon waking up, the device boots up from user_init.
+  *
+  * @attention  The parameter time_in_us to be "uint64" is for further development.
+  *                  Only the low 32 bits of parameter time_in_us are avalable now.
+  *
+  * @param     uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond
+  *
+  * @return    null
+  */
+void system_deep_sleep(uint64_t time_in_us);
+
+/**
+ * @brief Default stub to run on wake from deep sleep.
+ *
+ * Allows for executing code immediately on wake from sleep, before
+ * the software bootloader or esp-idf app has started up.
+ *
+ * This function is weak-linked, so you can implement your own version
+ * to run code immediately when the chip wakes from
+ * sleep.
+ *
+ * For example:
+ * @code
+ * void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
+ *    esp_default_wake_deep_sleep();
+ *    // Add additional functionality here
+ * }
+ *
+ * (Implementing this function is not required for normal operation,
+ * in the usual case your app will start normally when waking from
+ * deep sleep.)
+ *
+ * esp_wake_deep_sleep() functionality is limited:
+ *
+ * - Runs immediately on wake, so most of the SoC is freshly reset -
+ *   flash is unmapped and hardware is otherwise uninitialised.
+ *
+ * - Can only call functions implemented in ROM, or marked RTC_IRAM_ATTR.
+ *
+ * - Static variables marked RTC_DATA_ATTR will have initial values on
+ *   cold boot, and maintain these values between sleep/wake cycles.
+ *
+ * - Read-only data should be marked RTC_RODATA_ATTR. Strings must be
+ *   declared as variables also using RTC_RODATA_ATTR, like this:
+ *   RTC_RODATA_ATTR const char message[] = "Hello from very early boot!\n";
+ *
+ * - Any other static memory will not be initialised (either to zero,
+ *   or to any predefined value).
+ *
+ *
+ * - If you implement your own stub, the first call the stub makes
+     should be to esp_default_wake_deep_sleep().
+ */
+void esp_wake_deep_sleep(void);
+
+/**
+ * @brief Function type for stub to run on wake from sleep.
+ *
+ */
+typedef void (*esp_deep_sleep_wake_stub_fn_t)(void);
+
+/**
+ * @brief Install a new stub at runtime to run on wake from deep sleep
+ *
+ * If implementing esp_wake_deep_sleep() then it is not necessary to
+ * call this function.
+ *
+ * However, it is possible to call this function to substitute a
+ * different deep sleep stub. Any function used as a deep sleep stub
+ * must be marked RTC_IRAM_ATTR, and must obey the same rules given
+ * for esp_wake_deep_sleep().
+ */
+void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub);
+
+/**
+ * @brief Return current wake from deep sleep stub, or NULL if
+ * no stub is installed.
+ */
+esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void);
+
+/* The default esp-idf-provided esp_wake_deep_sleep() stub.
+
+   If you replace esp_wake_deep_sleep() in your program, or use
+   esp_set_deep_sleep_wake_stub(), then it is recommended you call
+   esp_default_wake_deep_sleep() as the first function in your stub.
+*/
+void esp_default_wake_deep_sleep(void);
+
+/**
+  * @}
+  */
+
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_SYSTEM_H__ */

+ 7 - 0
components/esp32/include/esp_err.h

@@ -15,6 +15,7 @@
 #define __ESP_ERR_H__
 
 #include <stdint.h>
+#include <assert.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -31,6 +32,12 @@ typedef int32_t esp_err_t;
 #define ESP_ERR_INVALID_ARG     0x102
 #define ESP_ERR_INVALID_STATE   0x103
 
+/**
+ * Macro which can be used to check the error code,
+ * and terminate the program in case the code is not ESP_OK.
+ * Prints the failed statement to serial output.
+ */
+#define ESP_ERROR_CHECK(x)   do { esp_err_t rc = (x); if (rc != ESP_OK) { assert(0 && #x);} } while(0);
 
 #ifdef __cplusplus
 }

+ 12 - 43
components/esp32/include/esp_event.h

@@ -19,8 +19,7 @@
 #include <stdbool.h>
 
 #include "esp_err.h"
-#include "esp_wifi.h"
-
+#include "esp_wifi_types.h"
 #include "tcpip_adapter.h"
 
 #ifdef __cplusplus
@@ -101,33 +100,11 @@ typedef union {
 } system_event_info_t;
 
 typedef struct {
-    system_event_id_t     event_id;      /**< even ID */
+    system_event_id_t     event_id;      /**< event ID */
     system_event_info_t   event_info;    /**< event information */
 } system_event_t;
 
-/**
-  * @brief  Application specified event callback function
-  *
-  * @param  void *ctx : reserved for user
-  * @param  system_event_t *event : event type defined in this file
-  *
-  * @return ESP_OK : succeed
-  * @return others : fail
-  */
-typedef esp_err_t (*system_event_cb_t)(void *ctx, system_event_t *event);
-
-/**
-  * @brief  Set application specified event callback function
-  *
-  * @attention 1. If cb is NULL, means application don't need to handle
-  *               If cb is not NULL, it will be call when an event is received, after the default event callback is completed
-  *
-  * @param  system_event_cb_t cb : callback
-  * @param  void *ctx : reserved for user
-  *
-  * @return system_event_cb_t : old callback
-  */
-system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx);
+typedef esp_err_t (*system_event_handler_t)(system_event_t *event);
 
 /**
   * @brief  Send a event to event task
@@ -142,28 +119,20 @@ system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx);
 esp_err_t esp_event_send(system_event_t *event);
 
 /**
-  * @brief  Get the event handler
+  * @brief  Default event handler for system events
   *
-  * @attention : currently this API returns event queue handler, by this event queue,
-  *              users can notice when WiFi has done something like scanning done, connected to AP or disconnected from AP.
+  * This function performs default handling of system events.
+  * When using esp_event_loop APIs, it is called automatically before invoking the user-provided
+  * callback function.
   *
-  * @param  null
+  * Applications which implement a custom event loop must call this function
+  * as part of event processing.
   *
-  * @return void * : event queue pointer
+  * @param  event pointer to event to be handled
+  * @return ESP_OK if an event was handled successfully
   */
-void *esp_event_get_handler(void);
+esp_err_t esp_event_process_default(system_event_t *event);
 
-/**
-  * @brief  Init the event module
-  *         Create the event handler and task
-  *
-  * @param  system_event_cb_t cb : application specified event callback, it can be modified by call esp_event_set_cb
-  * @param  void *ctx : reserved for user
-  *
-  * @return ESP_OK : succeed
-  * @return others : fail
-  */
-esp_err_t esp_event_init(system_event_cb_t cb, void *ctx);
 
 #ifdef __cplusplus
 }

+ 81 - 0
components/esp32/include/esp_event_loop.h

@@ -0,0 +1,81 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+#ifndef __ESP_EVENT_LOOP_H__
+#define __ESP_EVENT_LOOP_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "esp_err.h"
+#include "esp_event.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+  * @brief  Application specified event callback function
+  *
+  * @param  void *ctx : reserved for user
+  * @param  system_event_t *event : event type defined in this file
+  *
+  * @return ESP_OK : succeed
+  * @return others : fail
+  */
+typedef esp_err_t (*system_event_cb_t)(void *ctx, system_event_t *event);
+
+/**
+  * @brief  Initialize event loop
+  *         Create the event handler and task
+  *
+  * @param  system_event_cb_t cb : application specified event callback, it can be modified by call esp_event_set_cb
+  * @param  void *ctx : reserved for user
+  *
+  * @return ESP_OK : succeed
+  * @return others : fail
+  */
+esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx);
+
+/**
+  * @brief  Set application specified event callback function
+  *
+  * @attention 1. If cb is NULL, means application don't need to handle
+  *               If cb is not NULL, it will be call when an event is received, after the default event callback is completed
+  *
+  * @param  system_event_cb_t cb : callback
+  * @param  void *ctx : reserved for user
+  *
+  * @return system_event_cb_t : old callback
+  */
+system_event_cb_t esp_event_loop_set_cb(system_event_cb_t cb, void *ctx);
+
+/**
+  * @brief  Get the queue used by event loop
+  *
+  * @attention : currently this API is used to initialize "q" parameter
+  * of wifi_init structure.
+  *
+  * @return QueueHandle_t : event queue handle
+  */
+QueueHandle_t esp_event_loop_get_queue(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_EVENT_LOOP_H__ */

+ 143 - 0
components/esp32/include/esp_smartconfig.h

@@ -0,0 +1,143 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+#ifndef __ESP_SMARTCONFIG_H__
+#define __ESP_SMARTCONFIG_H__
+#include <stdint.h>
+#include <esp_types.h>
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    SC_STATUS_WAIT = 0,             /**< waiting, do not start connection in this phase */
+    SC_STATUS_FIND_CHANNEL,         /**< find target channel, start connection by APP in this phase */
+    SC_STATUS_GETTING_SSID_PSWD,    /**< getting SSID and password of target AP */
+    SC_STATUS_LINK,                 /**< connecting to target AP */
+    SC_STATUS_LINK_OVER,            /**< got IP, connect to AP successfully */
+} smartconfig_status_t;
+
+typedef enum {
+    SC_TYPE_ESPTOUCH = 0,       /**< protocol: ESPTouch */
+    SC_TYPE_AIRKISS,            /**< protocol: AirKiss */
+    SC_TYPE_ESPTOUCH_AIRKISS,   /**< protocol: ESPTouch and AirKiss */
+} smartconfig_type_t;
+
+/**
+  * @brief  The callback of SmartConfig, executed when smart-config status changed.
+  *
+  * @param  smartconfig_status_t status : status of SmartConfig:
+  *    -  if status == SC_STATUS_GETTING_SSID_PSWD, parameter void *pdata is a pointer
+                       of smartconfig_type_t, means SmartConfig type: AirKiss or ESP-TOUCH.
+  *    -  if status == SC_STATUS_LINK, parameter void *pdata is a pointer of struct station_config;
+  *    -  if status == SC_STATUS_LINK_OVER, parameter void *pdata is a pointer of mobile
+  *                    phone's IP address, 4 bytes. This is only available in ESPTOUCH, otherwise,
+  *                    it is NULL.
+  *    -  otherwise, parameter void *pdata is NULL.
+  * @param  void *pdata : data of SmartConfig
+  *
+  * @return null
+  */
+typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata);
+
+/**
+  * @brief  Get the version of SmartConfig.
+  *
+  * @param  null
+  *
+  * @return SmartConfig version
+  */
+const char *esp_smartconfig_get_version(void);
+
+/**
+  * @brief     Start SmartConfig mode.
+  *
+  *            Start SmartConfig mode, to connect ESP32 station to AP, by sniffing
+  *            for special packets from the air, containing SSID and password of desired AP.
+  *            You need to broadcast the SSID and password (e.g. from mobile device or computer)
+  *            with the SSID and password encoded.
+  *
+  * @attention 1. This API can only be called in station mode.
+  * @attention 2. During SmartConfig, ESP32 station and soft-AP are disabled.
+  * @attention 3. Can not call esp_smartconfig_start twice before it finish, please call
+  *               esp_smartconfig_stop first.
+  * @attention 4. Don't call any other APIs during SmartConfig, please call esp_smartconfig_stop first.
+  *
+  * @param     sc_callback_t cb : SmartConfig callback; executed when SmartConfig status changed;
+  * @param     uint8 log : 1, UART output logs; otherwise, UART only outputs the result.
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_start(sc_callback_t cb, ...);
+
+/**
+  * @brief     Stop SmartConfig, free the buffer taken by esp_smartconfig_start.
+  *
+  * @attention Whether connect to AP succeed or not, this API should be called to free
+  *            memory taken by smartconfig_start.
+  *
+  * @param     null
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_stop(void);
+
+/**
+  * @brief     Set timeout of SmartConfig.
+  *
+  * @attention SmartConfig timeout start at SC_STATUS_FIND_CHANNEL, SmartConfig will
+  *            restart if timeout.
+  *
+  * @param     uint8 time_s : range 15s~255s, offset:45s.
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_esptouch_set_timeout(uint8_t time_s);
+
+/**
+  * @brief     Set protocol type of SmartConfig.
+  *
+  * @attention If users need to set the SmartConfig type, please set it before calling
+  *            esp_smartconfig_start.
+  *
+  * @param     smartconfig_type_t type : AirKiss, ESP-TOUCH or both.
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_set_type(smartconfig_type_t type);
+
+/**
+  * @brief     Set mode of SmartConfig. default normal mode.
+  *
+  * @attention If users need to set the SmartConfig mode, please set it before calling
+  *            esp_smartconfig_start. Different mode should match different APP(phone).
+  *
+  * @param     bool enable : false-disable(default); true-enable; 
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_fast_mode(bool enable);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 15
components/esp32/include/esp_system.h

@@ -18,6 +18,7 @@
 #include <stdint.h>
 
 #include "esp_err.h"
+#include "esp_deepsleep.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -62,21 +63,6 @@ void system_restore(void);
   */
 void system_restart(void);
 
-/**
-  * @brief     Set the chip to deep-sleep mode.
-  *
-  *            The device will automatically wake up after the deep-sleep time set
-  *            by the users. Upon waking up, the device boots up from user_init.
-  *
-  * @attention  The parameter time_in_us to be "uint64" is for further development. 
-  *                  Only the low 32 bits of parameter time_in_us are avalable now.
-  *
-  * @param     uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond
-  *
-  * @return    null
-  */
-void system_deep_sleep(uint64_t time_in_us);
-
 /**
   * @brief  Get system time, unit: microsecond.
   *

+ 6 - 7
components/esp32/include/esp_task.h

@@ -15,10 +15,10 @@
 /* Notes:
  * 1. Put all task priority and stack size definition in this file
  * 2. If the task priority is less than 10, use ESP_TASK_PRIO_MIN + X style,
- *    otherwise use ESP_TASK_PRIO_MIN - X style
- * 3. If this is a daemon task, the macro prifix is ESP_TASKD_, otherwise
+ *    otherwise use ESP_TASK_PRIO_MAX - X style
+ * 3. If this is a daemon task, the macro prefix is ESP_TASKD_, otherwise
  *    it's ESP_TASK_
- * 4. If the configMAX_PRIORITIES is modified, please make all prority are 
+ * 4. If the configMAX_PRIORITIES is modified, please make all priority are
  *    greater than 0
  * 5. Make sure esp_task.h is consistent between wifi lib and idf
  */
@@ -51,10 +51,9 @@
 /* idf task */
 #define ESP_TASKD_EVENT_PRIO          (ESP_TASK_PRIO_MAX - 5)
 #define ESP_TASKD_EVENT_STACK         CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE
-#define ESP_TASK_WIFI_STARTUP_PRIO    (ESP_TASK_PRIO_MAX - 7)
-#define ESP_TASK_WIFI_STARTUP_STACK   4096
 #define ESP_TASK_TCPIP_PRIO           (ESP_TASK_PRIO_MAX - 7)
 #define ESP_TASK_TCPIP_STACK          2048
-#define ESP_TASK_BT_INIT_PRIO         (ESP_TASK_PRIO_MAX - 7)
-#define ESP_TASK_BT_INIT_STACK        2048
+#define ESP_TASK_MAIN_PRIO            (ESP_TASK_PRIO_MIN + 1)
+#define ESP_TASK_MAIN_STACK           CONFIG_MAIN_TASK_STACK_SIZE
+
 #endif

+ 15 - 189
components/esp32/include/esp_wifi.h

@@ -59,113 +59,26 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-
-#include "esp_err.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
 #include "rom/queue.h"
+#include "esp_err.h"
+#include "esp_wifi_types.h"
+#include "esp_event.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef enum {
-    WIFI_MODE_NULL = 0,  /**< null mode */
-    WIFI_MODE_STA,       /**< WiFi station mode */
-    WIFI_MODE_AP,        /**< WiFi soft-AP mode */
-    WIFI_MODE_APSTA,     /**< WiFi station + soft-AP mode */
-    WIFI_MODE_MAX
-} wifi_mode_t;
-
-typedef enum {
-    WIFI_IF_STA = 0,     /**< ESP32 station interface */
-    WIFI_IF_AP,          /**< ESP32 soft-AP interface */
-    WIFI_IF_MAX
-} wifi_interface_t;
-
-typedef enum {
-    WIFI_COUNTRY_CN = 0, /**< country China, channel range [1, 14] */
-    WIFI_COUNTRY_JP,     /**< country Japan, channel range [1, 14] */
-    WIFI_COUNTRY_US,     /**< country USA, channel range [1, 11] */
-    WIFI_COUNTRY_EU,     /**< country Europe, channel range [1, 13] */
-    WIFI_COUNTRY_MAX
-} wifi_country_t;
-
-typedef enum {
-    WIFI_AUTH_OPEN = 0,      /**< authenticate mode : open */
-    WIFI_AUTH_WEP,           /**< authenticate mode : WEP */
-    WIFI_AUTH_WPA_PSK,       /**< authenticate mode : WPA_PSK */
-    WIFI_AUTH_WPA2_PSK,      /**< authenticate mode : WPA2_PSK */
-    WIFI_AUTH_WPA_WPA2_PSK,  /**< authenticate mode : WPA_WPA2_PSK */
-    WIFI_AUTH_MAX
-} wifi_auth_mode_t;
-
-enum {
-    WIFI_REASON_UNSPECIFIED              = 1,
-    WIFI_REASON_AUTH_EXPIRE              = 2,
-    WIFI_REASON_AUTH_LEAVE               = 3,
-    WIFI_REASON_ASSOC_EXPIRE             = 4,
-    WIFI_REASON_ASSOC_TOOMANY            = 5,
-    WIFI_REASON_NOT_AUTHED               = 6,
-    WIFI_REASON_NOT_ASSOCED              = 7,
-    WIFI_REASON_ASSOC_LEAVE              = 8,
-    WIFI_REASON_ASSOC_NOT_AUTHED         = 9,
-    WIFI_REASON_DISASSOC_PWRCAP_BAD      = 10,
-    WIFI_REASON_DISASSOC_SUPCHAN_BAD     = 11,
-    WIFI_REASON_IE_INVALID               = 13,
-    WIFI_REASON_MIC_FAILURE              = 14,
-    WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,
-    WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
-    WIFI_REASON_IE_IN_4WAY_DIFFERS       = 17,
-    WIFI_REASON_GROUP_CIPHER_INVALID     = 18,
-    WIFI_REASON_PAIRWISE_CIPHER_INVALID  = 19,
-    WIFI_REASON_AKMP_INVALID             = 20,
-    WIFI_REASON_UNSUPP_RSN_IE_VERSION    = 21,
-    WIFI_REASON_INVALID_RSN_IE_CAP       = 22,
-    WIFI_REASON_802_1X_AUTH_FAILED       = 23,
-    WIFI_REASON_CIPHER_SUITE_REJECTED    = 24,
-
-    WIFI_REASON_BEACON_TIMEOUT           = 200,
-    WIFI_REASON_NO_AP_FOUND              = 201,
-    WIFI_REASON_AUTH_FAIL                = 202,
-    WIFI_REASON_ASSOC_FAIL               = 203,
-    WIFI_REASON_HANDSHAKE_TIMEOUT        = 204,
-};
-
-typedef enum {
-    WIFI_SECOND_CHAN_NONE = 0,  /**< the channel width is HT20 */
-    WIFI_SECOND_CHAN_ABOVE,     /**< the channel width is HT40 and the second channel is above the primary channel */
-    WIFI_SECOND_CHAN_BELOW,     /**< the channel width is HT40 and the second channel is below the primary channel */
-} wifi_second_chan_t;
-
-/**
-  * @brief     startup WiFi driver and register application specific callback function
-  *
-  * @attention 1. This API should be called in application startup code to init WiFi driver
-  * @attention 2. The callback function is used to provide application specific WiFi configuration,
-  *               such as, set the WiFi mode, register the event callback, set AP SSID etc before
-  *               WiFi is startup
-  * @attention 3. Avoid to create application task in the callback, otherwise you may get wrong behavior
-  * @attention 4. If the callback return is not ESP_OK, the startup will fail!
-  * @attention 5. Before this API can be called, system_init()/esp_event_init()/tcpip_adapter_init() should
-  *               be called firstly
-  *
-  * @param  wifi_startup_cb_t cb : application specific callback function
-  * @param  void *ctx : reserved for user
-  *
-  * @return ESP_OK : succeed
-  * @return others : fail
-  */
-typedef esp_err_t (* wifi_startup_cb_t)(void *ctx);
-
-esp_err_t esp_wifi_startup(wifi_startup_cb_t cb, void *ctx);
-
 typedef struct {
-    void    *event_q;                 /**< WiFi event q handler, it's a freeRTOS queue */
-    uint8_t rx_ba_win;                /**< TBC */
-    uint8_t tx_ba_win;                /**< TBC */
-    uint8_t rx_buf_cnt;               /**< TBC */
-    uint8_t tx_buf_cnt;               /**< TBC */
+    system_event_handler_t event_handler;  /**< WiFi event handler */
 } wifi_init_config_t;
 
+
+#define WIFI_INIT_CONFIG_DEFAULT() { \
+    .event_handler = &esp_event_send, \
+};
+
 /**
   * @brief  Init WiFi
   *         Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer,
@@ -176,7 +89,6 @@ typedef struct {
   *               to this queue when event happens, such as, when station connects to WiFi, WiFi driver
   *               will post station connected event to this queue. If the queue is not initialized, WiFi
   *               will not post any events
-  * @attention 3. For other parameters, currently it's not ready, just ignore it.
   *
   * @param  wifi_init_config_t *config : provide WiFi init configuration
   *
@@ -288,13 +200,6 @@ esp_err_t esp_wifi_clear_fast_connect(void);
   */
 esp_err_t esp_wifi_kick_station(uint16_t aid);
 
-typedef struct {
-    char *ssid;          /**< SSID of AP */
-    uint8_t *bssid;      /**< MAC address of AP */
-    uint8_t channel;     /**< channel, scan the specific channel */
-    bool show_hidden;    /**< enable to scan AP whose SSID is hidden */
-} wifi_scan_config_t;
-
 /**
   * @brief     Scan all available APs.
   *
@@ -332,15 +237,6 @@ esp_err_t esp_wifi_scan_stop(void);
   */
 esp_err_t esp_wifi_get_ap_num(uint16_t *number);
 
-typedef struct {
-    uint8_t bssid[6];                     /**< MAC address of AP */
-    uint8_t ssid[32];                     /**< SSID of AP */
-    uint8_t primary;                      /**< channel of AP */
-    wifi_second_chan_t second;            /**< second channel of AP */
-    int8_t  rssi;                         /**< signal strength of AP */
-    wifi_auth_mode_t authmode;            /**< authmode of AP */
-} wifi_ap_list_t;
-
 /**
   * @brief     Get AP list found in last scan
   *
@@ -353,13 +249,6 @@ typedef struct {
   */
 esp_err_t esp_wifi_get_ap_list(uint16_t *number, wifi_ap_list_t *ap_list);
 
-typedef enum {
-    WIFI_PS_NONE,    /**< No power save */
-    WIFI_PS_MODEM,   /**< Modem power save */
-    WIFI_PS_LIGHT,   /**< Light power save */
-    WIFI_PS_MAC,     /**< MAC power save */
-} wifi_ps_type_t;
-
 /**
   * @brief     Set current power save type
   *
@@ -380,10 +269,6 @@ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
   */
 esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
 
-#define WIFI_PROTOCOL_11B         1
-#define WIFI_PROTOCOL_11G         2
-#define WIFI_PROTOCOL_11N         4
-
 /**
   * @brief     Set protocol type of specified interface
   *            The default protocol is (WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N)
@@ -409,11 +294,6 @@ esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
   */
 esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
 
-typedef enum {
-    WIFI_BW_HT20 = 0, /* Bandwidth is HT20 */
-    WIFI_BW_HT40,     /* Bandwidth is HT40 */
-} wifi_bandwidth_t;
-
 /**
   * @brief     Set the bandwidth of ESP32 specified interface
   *
@@ -542,45 +422,22 @@ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
 /**
   * @brief     Enable the promiscuous mode.
   *
-  * @param     uint8 promiscuous : 0 - disable / 1 - enable
+  * @param     bool promiscuous : false - disable / true - enable
   *
   * @return    ESP_OK : succeed
   * @return    others : fail
   */
-esp_err_t esp_wifi_set_promiscuous(uint8_t enable);
+esp_err_t esp_wifi_set_promiscuous(bool en);
 
 /**
   * @brief     Get the promiscuous mode.
   *
-  * @param     uint8 *enable : store the current status of promiscuous mode
+  * @param     bool *enable : store the current status of promiscuous mode
   *
   * @return    ESP_OK : succeed
   * @return    others : fail
   */
-esp_err_t esp_wifi_get_promiscuous(uint8_t *enable);
-
-typedef struct {
-    char ssid[32];              /**< SSID of ESP32 soft-AP */
-    char password[64];          /**< Password of ESP32 soft-AP */
-    uint8_t ssid_len;           /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */
-    uint8_t channel;            /**< Channel of ESP32 soft-AP */
-    wifi_auth_mode_t authmode;  /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
-    uint8_t ssid_hidden;        /**< Broadcast SSID or not, default 0, broadcast the SSID */
-    uint8_t max_connection;     /**< Max number of stations allowed to connect in, default 4, max 4 */
-    uint16_t beacon_interval;   /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */
-} wifi_ap_config_t;
-
-typedef struct {
-    char ssid[32];         /**< SSID of target AP*/
-    char password[64];     /**< password of target AP*/
-    bool bssid_set;        /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
-    uint8_t bssid[6];     /**< MAC address of target AP*/
-} wifi_sta_config_t;
-
-typedef union {
-    wifi_ap_config_t  ap;  /**< configuration of AP */
-    wifi_sta_config_t sta; /**< configuration of STA */
-} wifi_config_t;
+esp_err_t esp_wifi_get_promiscuous(bool *en);
 
 /**
   * @brief     Set the configuration of the ESP32 STA or AP
@@ -609,11 +466,6 @@ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
   */
 esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
 
-struct station_info {
-    STAILQ_ENTRY(station_info) next;
-    uint8_t bssid[6];
-};
-
 /**
   * @brief     Get STAs associated with soft-AP
   *
@@ -628,11 +480,6 @@ esp_err_t esp_wifi_get_station_list(struct station_info **station);
 
 esp_err_t esp_wifi_free_station_list(void);
 
-typedef enum {
-    WIFI_STORAGE_FLASH,  /**< all configuration will strore in both memory and flash */
-    WIFI_STORAGE_RAM,    /**< all configuration will only store in the memory */
-} wifi_storage_t;
-
 /**
   * @brief     Set the WiFi API configuration storage type
   *
@@ -689,27 +536,6 @@ esp_err_t esp_wifi_set_auto_connect(bool en);
   */
 esp_err_t esp_wifi_get_auto_connect(bool *en);
 
-/**
-  * @brief     Vendor IE type
-  *
-  */
-typedef enum {
-    WIFI_VND_IE_TYPE_BEACON,
-    WIFI_VND_IE_TYPE_PROBE_REQ,
-    WIFI_VND_IE_TYPE_PROBE_RESP,
-    WIFI_VND_IE_TYPE_ASSOC_REQ,
-    WIFI_VND_IE_TYPE_ASSOC_RESP,
-} wifi_vendor_ie_type_t;
-
-/**
-  * @brief     Vendor IE index
-  *
-  */
-typedef enum {
-    WIFI_VND_IE_ID_0,
-    WIFI_VND_IE_ID_1,
-} wifi_vendor_ie_id_t;
-
 /**
   * @brief     Set vendor specific element
   *

+ 190 - 0
components/esp32/include/esp_wifi_types.h

@@ -0,0 +1,190 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+
+#ifndef __ESP_WIFI_TYPES_H__
+#define __ESP_WIFI_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rom/queue.h"
+#include "esp_err.h"
+#include "esp_wifi_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    WIFI_MODE_NULL = 0,  /**< null mode */
+    WIFI_MODE_STA,       /**< WiFi station mode */
+    WIFI_MODE_AP,        /**< WiFi soft-AP mode */
+    WIFI_MODE_APSTA,     /**< WiFi station + soft-AP mode */
+    WIFI_MODE_MAX
+} wifi_mode_t;
+
+typedef enum {
+    WIFI_IF_STA = 0,     /**< ESP32 station interface */
+    WIFI_IF_AP,          /**< ESP32 soft-AP interface */
+    WIFI_IF_MAX
+} wifi_interface_t;
+
+typedef enum {
+    WIFI_COUNTRY_CN = 0, /**< country China, channel range [1, 14] */
+    WIFI_COUNTRY_JP,     /**< country Japan, channel range [1, 14] */
+    WIFI_COUNTRY_US,     /**< country USA, channel range [1, 11] */
+    WIFI_COUNTRY_EU,     /**< country Europe, channel range [1, 13] */
+    WIFI_COUNTRY_MAX
+} wifi_country_t;
+
+typedef enum {
+    WIFI_AUTH_OPEN = 0,      /**< authenticate mode : open */
+    WIFI_AUTH_WEP,           /**< authenticate mode : WEP */
+    WIFI_AUTH_WPA_PSK,       /**< authenticate mode : WPA_PSK */
+    WIFI_AUTH_WPA2_PSK,      /**< authenticate mode : WPA2_PSK */
+    WIFI_AUTH_WPA_WPA2_PSK,  /**< authenticate mode : WPA_WPA2_PSK */
+    WIFI_AUTH_MAX
+} wifi_auth_mode_t;
+
+enum {
+    WIFI_REASON_UNSPECIFIED              = 1,
+    WIFI_REASON_AUTH_EXPIRE              = 2,
+    WIFI_REASON_AUTH_LEAVE               = 3,
+    WIFI_REASON_ASSOC_EXPIRE             = 4,
+    WIFI_REASON_ASSOC_TOOMANY            = 5,
+    WIFI_REASON_NOT_AUTHED               = 6,
+    WIFI_REASON_NOT_ASSOCED              = 7,
+    WIFI_REASON_ASSOC_LEAVE              = 8,
+    WIFI_REASON_ASSOC_NOT_AUTHED         = 9,
+    WIFI_REASON_DISASSOC_PWRCAP_BAD      = 10,
+    WIFI_REASON_DISASSOC_SUPCHAN_BAD     = 11,
+    WIFI_REASON_IE_INVALID               = 13,
+    WIFI_REASON_MIC_FAILURE              = 14,
+    WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,
+    WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
+    WIFI_REASON_IE_IN_4WAY_DIFFERS       = 17,
+    WIFI_REASON_GROUP_CIPHER_INVALID     = 18,
+    WIFI_REASON_PAIRWISE_CIPHER_INVALID  = 19,
+    WIFI_REASON_AKMP_INVALID             = 20,
+    WIFI_REASON_UNSUPP_RSN_IE_VERSION    = 21,
+    WIFI_REASON_INVALID_RSN_IE_CAP       = 22,
+    WIFI_REASON_802_1X_AUTH_FAILED       = 23,
+    WIFI_REASON_CIPHER_SUITE_REJECTED    = 24,
+
+    WIFI_REASON_BEACON_TIMEOUT           = 200,
+    WIFI_REASON_NO_AP_FOUND              = 201,
+    WIFI_REASON_AUTH_FAIL                = 202,
+    WIFI_REASON_ASSOC_FAIL               = 203,
+    WIFI_REASON_HANDSHAKE_TIMEOUT        = 204,
+};
+
+typedef enum {
+    WIFI_SECOND_CHAN_NONE = 0,  /**< the channel width is HT20 */
+    WIFI_SECOND_CHAN_ABOVE,     /**< the channel width is HT40 and the second channel is above the primary channel */
+    WIFI_SECOND_CHAN_BELOW,     /**< the channel width is HT40 and the second channel is below the primary channel */
+} wifi_second_chan_t;
+
+typedef struct {
+    char *ssid;          /**< SSID of AP */
+    uint8_t *bssid;      /**< MAC address of AP */
+    uint8_t channel;     /**< channel, scan the specific channel */
+    bool show_hidden;    /**< enable to scan AP whose SSID is hidden */
+} wifi_scan_config_t;
+
+typedef struct {
+    uint8_t bssid[6];                     /**< MAC address of AP */
+    uint8_t ssid[32];                     /**< SSID of AP */
+    uint8_t primary;                      /**< channel of AP */
+    wifi_second_chan_t second;            /**< second channel of AP */
+    int8_t  rssi;                         /**< signal strength of AP */
+    wifi_auth_mode_t authmode;            /**< authmode of AP */
+} wifi_ap_list_t;
+
+typedef enum {
+    WIFI_PS_NONE,    /**< No power save */
+    WIFI_PS_MODEM,   /**< Modem power save */
+    WIFI_PS_LIGHT,   /**< Light power save */
+    WIFI_PS_MAC,     /**< MAC power save */
+} wifi_ps_type_t;
+
+#define WIFI_PROTOCOL_11B         1
+#define WIFI_PROTOCOL_11G         2
+#define WIFI_PROTOCOL_11N         4
+
+typedef enum {
+    WIFI_BW_HT20 = 0, /* Bandwidth is HT20 */
+    WIFI_BW_HT40,     /* Bandwidth is HT40 */
+} wifi_bandwidth_t;
+
+typedef struct {
+    char ssid[32];              /**< SSID of ESP32 soft-AP */
+    char password[64];          /**< Password of ESP32 soft-AP */
+    uint8_t ssid_len;           /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */
+    uint8_t channel;            /**< Channel of ESP32 soft-AP */
+    wifi_auth_mode_t authmode;  /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
+    uint8_t ssid_hidden;        /**< Broadcast SSID or not, default 0, broadcast the SSID */
+    uint8_t max_connection;     /**< Max number of stations allowed to connect in, default 4, max 4 */
+    uint16_t beacon_interval;   /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */
+} wifi_ap_config_t;
+
+typedef struct {
+    char ssid[32];         /**< SSID of target AP*/
+    char password[64];     /**< password of target AP*/
+    bool bssid_set;        /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
+    uint8_t bssid[6];     /**< MAC address of target AP*/
+} wifi_sta_config_t;
+
+typedef union {
+    wifi_ap_config_t  ap;  /**< configuration of AP */
+    wifi_sta_config_t sta; /**< configuration of STA */
+} wifi_config_t;
+
+struct station_info {
+    STAILQ_ENTRY(station_info) next;
+    uint8_t bssid[6];
+};
+
+typedef enum {
+    WIFI_STORAGE_FLASH,  /**< all configuration will strore in both memory and flash */
+    WIFI_STORAGE_RAM,    /**< all configuration will only store in the memory */
+} wifi_storage_t;
+
+/**
+  * @brief     Vendor IE type
+  *
+  */
+typedef enum {
+    WIFI_VND_IE_TYPE_BEACON,
+    WIFI_VND_IE_TYPE_PROBE_REQ,
+    WIFI_VND_IE_TYPE_PROBE_RESP,
+    WIFI_VND_IE_TYPE_ASSOC_REQ,
+    WIFI_VND_IE_TYPE_ASSOC_RESP,
+} wifi_vendor_ie_type_t;
+
+/**
+  * @brief     Vendor IE index
+  *
+  */
+typedef enum {
+    WIFI_VND_IE_ID_0,
+    WIFI_VND_IE_ID_1,
+} wifi_vendor_ie_id_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __ESP_WIFI_TYPES_H__ */

+ 0 - 131
components/esp32/include/esp_wps.h

@@ -1,131 +0,0 @@
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// 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.
-
-#ifndef __ESP_WPS_H__
-#define __ESP_WPS_H__
-
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** \defgroup WiFi_APIs WiFi Related APIs
-  * @brief WiFi APIs
-  */
-
-/** @addtogroup WiFi_APIs
-  * @{
-  */
-
-/** \defgroup WPS_APIs  WPS APIs
-  * @brief ESP32 WPS APIs
-  *
-  * WPS can only be used when ESP32 station is enabled.
-  *
-  */
-
-/** @addtogroup WPS_APIs
-  * @{
-  */
-
-typedef enum wps_type {
-    WPS_TYPE_DISABLE = 0,
-    WPS_TYPE_PBC,
-    WPS_TYPE_PIN,
-    WPS_TYPE_DISPLAY,
-    WPS_TYPE_MAX,
-} WPS_TYPE_t;
-
-enum wps_cb_status {
-    WPS_CB_ST_SUCCESS = 0,     /**< WPS succeed */
-    WPS_CB_ST_FAILED,          /**< WPS fail */
-    WPS_CB_ST_TIMEOUT,         /**< WPS timeout, fail */
-    WPS_CB_ST_WEP,             /**< WPS failed because that WEP is not supported */
-    WPS_CB_ST_SCAN_ERR,        /**< can not find the target WPS AP */
-};
-
-/**
-  * @brief     Enable Wi-Fi WPS function.
-  *
-  * @attention WPS can only be used when ESP32 station is enabled.
-  *
-  * @param     WPS_TYPE_t wps_type : WPS type, so far only WPS_TYPE_PBC is supported
-  *
-  * @return    true  : succeed
-  * @return    false : fail
-  */
-bool wifi_wps_enable(WPS_TYPE_t wps_type);
-
-/**
-  * @brief  Disable Wi-Fi WPS function and release resource it taken.
-  *
-  * @param  null
-  *
-  * @return true  : succeed
-  * @return false : fail
-  */
-bool wifi_wps_disable(void);
-
-/**
-  * @brief     WPS starts to work.
-  *
-  * @attention WPS can only be used when ESP32 station is enabled.
-  *
-  * @param     null
-  *
-  * @return    true  : WPS starts to work successfully, but does not mean WPS succeed.
-  * @return    false : fail
-  */
-bool wifi_wps_start(void);
-
-/**
-  * @brief  WPS callback.
-  *
-  * @param  int status : status of WPS, enum wps_cb_status.
-  *    -  If parameter status == WPS_CB_ST_SUCCESS in WPS callback, it means WPS got AP's
-  *       information, user can call wifi_wps_disable to disable WPS and release resource,
-  *       then call wifi_station_connect to connect to target AP.
-  *    -  Otherwise, it means that WPS fail, user can create a timer to retry WPS by
-  *       wifi_wps_start after a while, or call wifi_wps_disable to disable WPS and release resource.
-  *
-  * @return null
-  */
-typedef void (*wps_st_cb_t)(int status);
-
-/**
-  * @brief     Set WPS callback.
-  *
-  * @attention WPS can only be used when ESP32 station is enabled.
-  *
-  * @param     wps_st_cb_t cb : callback.
-  *
-  * @return    true  : WPS starts to work successfully, but does not mean WPS succeed.
-  * @return    false : fail
-  */
-bool wifi_set_wps_cb(wps_st_cb_t cb);
-
-/**
-  * @}
-  */
-
-/**
-  * @}
-  */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __ESP_WPS_H__ */

+ 13 - 13
components/esp32/include/rom/rtc.h

@@ -44,25 +44,25 @@ extern "C" {
   *************************************************************************************
   *     rtc memory addr         type    size            usage
   *     0x3ff61000(0x50000000)  Slow    SIZE_CP         Co-Processor code/Reset Entry
-  *     0x3ff61000+SIZE_CP      Slow    6144-SIZE_CP
-  *     0x3ff62800              Slow    2048            Reserved
+  *     0x3ff61000+SIZE_CP      Slow    4096-SIZE_CP
+  *     0x3ff62800              Slow    4096            Reserved
   *
   *     0x3ff80000(0x400c0000)  Fast    8192            deep sleep entry code
   *
   *************************************************************************************
   *     Rtc store registers     usage
-  *     RTC_STORE0
-  *     RTC_STORE1
-  *     RTC_STORE2
-  *     RTC_STORE3
-  *     RTC_STORE4              Reserved
-  *     RTC_STORE5              External Xtal Frequency
-  *     RTC_STORE6              FAST_RTC_MEMORY_ENTRY
-  *     RTC_STORE7              FAST_RTC_MEMORY_CRC
+  *     RTC_CNTL_STORE0_REG
+  *     RTC_CNTL_STORE1_REG
+  *     RTC_CNTL_STORE2_REG
+  *     RTC_CNTL_STORE3_REG
+  *     RTC_CNTL_STORE4_REG     Reserved
+  *     RTC_CNTL_STORE5_REG     External Xtal Frequency
+  *     RTC_CNTL_STORE6_REG     FAST_RTC_MEMORY_ENTRY
+  *     RTC_CNTL_STORE7_REG     FAST_RTC_MEMORY_CRC
   *************************************************************************************
   */
-#define RTC_ENTRY_ADDR RTC_STORE6
-#define RTC_MEMORY_CRC RTC_STORE7
+#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
+#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG
 
 
 typedef enum {
@@ -161,7 +161,7 @@ WAKEUP_REASON rtc_get_wakeup_cause(void);
   *
   * @param  uint32_t start_addr : 0 - 0x7ff for Fast RTC Memory.
   *
-  * @param  uint32_t crc_len : 0 - 0x7ff, 0 for 1 byte, 0x7ff for 0x800 byte.
+  * @param  uint32_t crc_len : 0 - 0x7ff, 0 for 4 byte, 0x7ff for 0x2000 byte.
   *
   * @return uint32_t : CRC32 result
   */

+ 126 - 124
components/esp32/include/soc/io_mux_reg.h

@@ -40,6 +40,8 @@
 #define PIN_PULLDWN_EN(PIN_NAME)              REG_SET_BIT(PIN_NAME, FUN_PD)
 #define PIN_FUNC_SELECT(PIN_NAME, FUNC)      REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC)
 
+#define PIN_FUNC_GPIO                               2
+
 #define PIN_CTRL                          (DR_REG_IO_MUX_BASE +0x00)
 #define CLK_OUT3                                    0xf
 #define CLK_OUT3_S                                  8
@@ -48,60 +50,86 @@
 #define CLK_OUT1                                    0xf
 #define CLK_OUT1_S                                  0
 
-#define PERIPHS_IO_MUX_GPIO36_U           (DR_REG_IO_MUX_BASE +0x04)
-#define FUNC_GPIO36_GPIO36                          2
-#define FUNC_GPIO36_GPIO36_0                        0
+#define PERIPHS_IO_MUX_GPIO0_U            (DR_REG_IO_MUX_BASE +0x44)
+#define FUNC_GPIO0_EMAC_TX_CLK                      5
+#define FUNC_GPIO0_GPIO0                            2
+#define FUNC_GPIO0_CLK_OUT1                         1
+#define FUNC_GPIO0_GPIO0_0                          0
 
-#define PERIPHS_IO_MUX_GPIO37_U           (DR_REG_IO_MUX_BASE +0x08)
-#define FUNC_GPIO37_GPIO37                          2
-#define FUNC_GPIO37_GPIO37_0                        0
+#define PERIPHS_IO_MUX_U0TXD_U            (DR_REG_IO_MUX_BASE +0x88)
+#define FUNC_U0TXD_EMAC_RXD2                        3
+#define FUNC_U0TXD_GPIO1                            2
+#define FUNC_U0TXD_CLK_OUT3                         1
+#define FUNC_U0TXD_U0TXD                            0
 
-#define PERIPHS_IO_MUX_GPIO38_U           (DR_REG_IO_MUX_BASE +0x0c)
-#define FUNC_GPIO38_GPIO38                          2
-#define FUNC_GPIO38_GPIO38_0                        0
+#define PERIPHS_IO_MUX_GPIO2_U            (DR_REG_IO_MUX_BASE +0x40)
+#define FUNC_GPIO2_SD_DATA0                         4
+#define FUNC_GPIO2_HS2_DATA0                        3
+#define FUNC_GPIO2_GPIO2                            2
+#define FUNC_GPIO2_HSPIWP                           1
+#define FUNC_GPIO2_GPIO2_0                          0
 
-#define PERIPHS_IO_MUX_GPIO39_U           (DR_REG_IO_MUX_BASE +0x10)
-#define FUNC_GPIO39_GPIO39                          2
-#define FUNC_GPIO39_GPIO39_0                        0
+#define PERIPHS_IO_MUX_U0RXD_U            (DR_REG_IO_MUX_BASE +0x84)
+#define FUNC_U0RXD_GPIO3                            2
+#define FUNC_U0RXD_CLK_OUT2                         1
+#define FUNC_U0RXD_U0RXD                            0
 
-#define PERIPHS_IO_MUX_GPIO34_U           (DR_REG_IO_MUX_BASE +0x14)
-#define FUNC_GPIO34_GPIO34                          2
-#define FUNC_GPIO34_GPIO34_0                        0
+#define PERIPHS_IO_MUX_GPIO4_U            (DR_REG_IO_MUX_BASE +0x48)
+#define FUNC_GPIO4_EMAC_TX_ER                       5
+#define FUNC_GPIO4_SD_DATA1                         4
+#define FUNC_GPIO4_HS2_DATA1                        3
+#define FUNC_GPIO4_GPIO4                            2
+#define FUNC_GPIO4_HSPIHD                           1
+#define FUNC_GPIO4_GPIO4_0                          0
 
-#define PERIPHS_IO_MUX_GPIO35_U           (DR_REG_IO_MUX_BASE +0x18)
-#define FUNC_GPIO35_GPIO35                          2
-#define FUNC_GPIO35_GPIO35_0                        0
+#define PERIPHS_IO_MUX_GPIO5_U            (DR_REG_IO_MUX_BASE +0x6c)
+#define FUNC_GPIO5_EMAC_RX_CLK                      5
+#define FUNC_GPIO5_HS1_DATA6                        3
+#define FUNC_GPIO5_GPIO5                            2
+#define FUNC_GPIO5_VSPICS0                          1
+#define FUNC_GPIO5_GPIO5_0                          0
 
-#define PERIPHS_IO_MUX_GPIO32_U           (DR_REG_IO_MUX_BASE +0x1c)
-#define FUNC_GPIO32_GPIO32                          2
-#define FUNC_GPIO32_GPIO32_0                        0
+#define PERIPHS_IO_MUX_SD_CLK_U           (DR_REG_IO_MUX_BASE +0x60)
+#define FUNC_SD_CLK_U1CTS                           4
+#define FUNC_SD_CLK_HS1_CLK                         3
+#define FUNC_SD_CLK_GPIO6                           2
+#define FUNC_SD_CLK_SPICLK                          1
+#define FUNC_SD_CLK_SD_CLK                          0
 
-#define PERIPHS_IO_MUX_GPIO33_U           (DR_REG_IO_MUX_BASE +0x20)
-#define FUNC_GPIO33_GPIO33                          2
-#define FUNC_GPIO33_GPIO33_0                        0
+#define PERIPHS_IO_MUX_SD_DATA0_U         (DR_REG_IO_MUX_BASE +0x64)
+#define FUNC_SD_DATA0_U2RTS                         4
+#define FUNC_SD_DATA0_HS1_DATA0                     3
+#define FUNC_SD_DATA0_GPIO7                         2
+#define FUNC_SD_DATA0_SPIQ                          1
+#define FUNC_SD_DATA0_SD_DATA0                      0
 
-#define PERIPHS_IO_MUX_GPIO25_U           (DR_REG_IO_MUX_BASE +0x24)
-#define FUNC_GPIO25_EMAC_RXD0                       5 
-#define FUNC_GPIO25_GPIO25                          2
-#define FUNC_GPIO25_GPIO25_0                        0
+#define PERIPHS_IO_MUX_SD_DATA1_U         (DR_REG_IO_MUX_BASE +0x68)
+#define FUNC_SD_DATA1_U2CTS                         4
+#define FUNC_SD_DATA1_HS1_DATA1                     3
+#define FUNC_SD_DATA1_GPIO8                         2
+#define FUNC_SD_DATA1_SPID                          1
+#define FUNC_SD_DATA1_SD_DATA1                      0
 
-#define PERIPHS_IO_MUX_GPIO26_U           (DR_REG_IO_MUX_BASE +0x28)
-#define FUNC_GPIO26_EMAC_RXD1                       5
-#define FUNC_GPIO26_GPIO26                          2
-#define FUNC_GPIO26_GPIO26_0                        0
+#define PERIPHS_IO_MUX_SD_DATA2_U         (DR_REG_IO_MUX_BASE +0x54)
+#define FUNC_SD_DATA2_U1RXD                         4
+#define FUNC_SD_DATA2_HS1_DATA2                     3
+#define FUNC_SD_DATA2_GPIO9                         2
+#define FUNC_SD_DATA2_SPIHD                         1
+#define FUNC_SD_DATA2_SD_DATA2                      0
 
-#define PERIPHS_IO_MUX_GPIO27_U           (DR_REG_IO_MUX_BASE +0x2c)
-#define FUNC_GPIO27_EMAC_RX_DV                      5
-#define FUNC_GPIO27_GPIO27                          2
-#define FUNC_GPIO27_GPIO27_0                        0
+#define PERIPHS_IO_MUX_SD_DATA3_U         (DR_REG_IO_MUX_BASE +0x58)
+#define FUNC_SD_DATA3_U1TXD                         4
+#define FUNC_SD_DATA3_HS1_DATA3                     3
+#define FUNC_SD_DATA3_GPIO10                        2
+#define FUNC_SD_DATA3_SPIWP                         1
+#define FUNC_SD_DATA3_SD_DATA3                      0
 
-#define PERIPHS_IO_MUX_MTMS_U             (DR_REG_IO_MUX_BASE +0x30)
-#define FUNC_MTMS_EMAC_TXD2                         5
-#define FUNC_MTMS_SD_CLK                            4
-#define FUNC_MTMS_HS2_CLk                           3
-#define FUNC_MTMS_GPIO14                            2
-#define FUNC_MTMS_HSPICLK                           1
-#define FUNC_MTMS_MTMS                              0
+#define PERIPHS_IO_MUX_SD_CMD_U           (DR_REG_IO_MUX_BASE +0x5c)
+#define FUNC_SD_CMD_U1RTS                           4
+#define FUNC_SD_CMD_HS1_CMD                         3
+#define FUNC_SD_CMD_GPIO11                          2
+#define FUNC_SD_CMD_SPICS0                          1
+#define FUNC_SD_CMD_SD_CMD                          0
 
 #define PERIPHS_IO_MUX_MTDI_U             (DR_REG_IO_MUX_BASE +0x34)
 #define FUNC_MTDI_EMAC_TXD3                         5
@@ -119,6 +147,14 @@
 #define FUNC_MTCK_HSPID                             1
 #define FUNC_MTCK_MTCK                              0
 
+#define PERIPHS_IO_MUX_MTMS_U             (DR_REG_IO_MUX_BASE +0x30)
+#define FUNC_MTMS_EMAC_TXD2                         5
+#define FUNC_MTMS_SD_CLK                            4
+#define FUNC_MTMS_HS2_CLk                           3
+#define FUNC_MTMS_GPIO14                            2
+#define FUNC_MTMS_HSPICLK                           1
+#define FUNC_MTMS_MTMS                              0
+
 #define PERIPHS_IO_MUX_MTDO_U             (DR_REG_IO_MUX_BASE +0x3c)
 #define FUNC_MTDO_EMAC_RXD3                         5
 #define FUNC_MTDO_SD_CMD                            4
@@ -127,27 +163,6 @@
 #define FUNC_MTDO_HSPICS0                           1
 #define FUNC_MTDO_MTDO                              0
 
-#define PERIPHS_IO_MUX_GPIO2_U            (DR_REG_IO_MUX_BASE +0x40)
-#define FUNC_GPIO2_SD_DATA0                         4
-#define FUNC_GPIO2_HS2_DATA0                        3
-#define FUNC_GPIO2_GPIO2                            2
-#define FUNC_GPIO2_HSPIWP                           1
-#define FUNC_GPIO2_GPIO2_0                          0
-
-#define PERIPHS_IO_MUX_GPIO0_U            (DR_REG_IO_MUX_BASE +0x44)
-#define FUNC_GPIO0_EMAC_TX_CLK                      5
-#define FUNC_GPIO0_GPIO0                            2
-#define FUNC_GPIO0_CLK_OUT1                         1
-#define FUNC_GPIO0_GPIO0_0                          0
-
-#define PERIPHS_IO_MUX_GPIO4_U            (DR_REG_IO_MUX_BASE +0x48)
-#define FUNC_GPIO4_EMAC_TX_ER                       5
-#define FUNC_GPIO4_SD_DATA1                         4
-#define FUNC_GPIO4_HS2_DATA1                        3
-#define FUNC_GPIO4_GPIO4                            2
-#define FUNC_GPIO4_HSPIHD                           1
-#define FUNC_GPIO4_GPIO4_0                          0
-
 #define PERIPHS_IO_MUX_GPIO16_U           (DR_REG_IO_MUX_BASE +0x4c)
 #define FUNC_GPIO16_EMAC_CLK_OUT                    5
 #define FUNC_GPIO16_U2RXD                           4
@@ -162,55 +177,6 @@
 #define FUNC_GPIO17_GPIO17                          2
 #define FUNC_GPIO17_GPIO17_0                        0
 
-#define PERIPHS_IO_MUX_SD_DATA2_U         (DR_REG_IO_MUX_BASE +0x54)
-#define FUNC_SD_DATA2_U1RXD                         4
-#define FUNC_SD_DATA2_HS1_DATA2                     3
-#define FUNC_SD_DATA2_GPIO9                         2
-#define FUNC_SD_DATA2_SPIHD                         1
-#define FUNC_SD_DATA2_SD_DATA2                      0
-
-#define PERIPHS_IO_MUX_SD_DATA3_U         (DR_REG_IO_MUX_BASE +0x58)
-#define FUNC_SD_DATA3_U1TXD                         4
-#define FUNC_SD_DATA3_HS1_DATA3                     3
-#define FUNC_SD_DATA3_GPIO10                        2
-#define FUNC_SD_DATA3_SPIWP                         1
-#define FUNC_SD_DATA3_SD_DATA3                      0
-
-#define PERIPHS_IO_MUX_SD_CMD_U           (DR_REG_IO_MUX_BASE +0x5c)
-#define FUNC_SD_CMD_U1RTS                           4
-#define FUNC_SD_CMD_HS1_CMD                         3
-#define FUNC_SD_CMD_GPIO11                          2
-#define FUNC_SD_CMD_SPICS0                          1
-#define FUNC_SD_CMD_SD_CMD                          0
-
-#define PERIPHS_IO_MUX_SD_CLK_U           (DR_REG_IO_MUX_BASE +0x60)
-#define FUNC_SD_CLK_U1CTS                           4
-#define FUNC_SD_CLK_HS1_CLK                         3
-#define FUNC_SD_CLK_GPIO6                           2
-#define FUNC_SD_CLK_SPICLK                          1
-#define FUNC_SD_CLK_SD_CLK                          0
-
-#define PERIPHS_IO_MUX_SD_DATA0_U         (DR_REG_IO_MUX_BASE +0x64)
-#define FUNC_SD_DATA0_U2RTS                         4
-#define FUNC_SD_DATA0_HS1_DATA0                     3
-#define FUNC_SD_DATA0_GPIO7                         2
-#define FUNC_SD_DATA0_SPIQ                          1
-#define FUNC_SD_DATA0_SD_DATA0                      0
-
-#define PERIPHS_IO_MUX_SD_DATA1_U         (DR_REG_IO_MUX_BASE +0x68)
-#define FUNC_SD_DATA1_U2CTS                         4
-#define FUNC_SD_DATA1_HS1_DATA1                     3
-#define FUNC_SD_DATA1_GPIO8                         2
-#define FUNC_SD_DATA1_SPID                          1
-#define FUNC_SD_DATA1_SD_DATA1                      0
-
-#define PERIPHS_IO_MUX_GPIO5_U            (DR_REG_IO_MUX_BASE +0x6c)
-#define FUNC_GPIO5_EMAC_RX_CLK                      5
-#define FUNC_GPIO5_HS1_DATA6                        3
-#define FUNC_GPIO5_GPIO5                            2
-#define FUNC_GPIO5_VSPICS0                          1
-#define FUNC_GPIO5_GPIO5_0                          0
-
 #define PERIPHS_IO_MUX_GPIO18_U           (DR_REG_IO_MUX_BASE +0x70)
 #define FUNC_GPIO18_HS1_DATA7                       3
 #define FUNC_GPIO18_GPIO18                          2
@@ -241,17 +207,6 @@
 #define FUNC_GPIO22_VSPIWP                          1
 #define FUNC_GPIO22_GPIO22_0                        0
 
-#define PERIPHS_IO_MUX_U0RXD_U            (DR_REG_IO_MUX_BASE +0x84)
-#define FUNC_U0RXD_GPIO3                            2
-#define FUNC_U0RXD_CLK_OUT2                         1
-#define FUNC_U0RXD_U0RXD                            0
-
-#define PERIPHS_IO_MUX_U0TXD_U            (DR_REG_IO_MUX_BASE +0x88)
-#define FUNC_U0TXD_EMAC_RXD2                        3
-#define FUNC_U0TXD_GPIO1                            2
-#define FUNC_U0TXD_CLK_OUT3                         1
-#define FUNC_U0TXD_U0TXD                            0
-
 #define PERIPHS_IO_MUX_GPIO23_U           (DR_REG_IO_MUX_BASE +0x8c)
 #define FUNC_GPIO23_HS1_STROBE                      3
 #define FUNC_GPIO23_GPIO23                          2
@@ -262,4 +217,51 @@
 #define FUNC_GPIO24_GPIO24                          2
 #define FUNC_GPIO24_GPIO24_0                        0
 
+#define PERIPHS_IO_MUX_GPIO25_U           (DR_REG_IO_MUX_BASE +0x24)
+#define FUNC_GPIO25_EMAC_RXD0                       5
+#define FUNC_GPIO25_GPIO25                          2
+#define FUNC_GPIO25_GPIO25_0                        0
+
+#define PERIPHS_IO_MUX_GPIO26_U           (DR_REG_IO_MUX_BASE +0x28)
+#define FUNC_GPIO26_EMAC_RXD1                       5
+#define FUNC_GPIO26_GPIO26                          2
+#define FUNC_GPIO26_GPIO26_0                        0
+
+#define PERIPHS_IO_MUX_GPIO27_U           (DR_REG_IO_MUX_BASE +0x2c)
+#define FUNC_GPIO27_EMAC_RX_DV                      5
+#define FUNC_GPIO27_GPIO27                          2
+#define FUNC_GPIO27_GPIO27_0                        0
+
+#define PERIPHS_IO_MUX_GPIO32_U           (DR_REG_IO_MUX_BASE +0x1c)
+#define FUNC_GPIO32_GPIO32                          2
+#define FUNC_GPIO32_GPIO32_0                        0
+
+#define PERIPHS_IO_MUX_GPIO33_U           (DR_REG_IO_MUX_BASE +0x20)
+#define FUNC_GPIO33_GPIO33                          2
+#define FUNC_GPIO33_GPIO33_0                        0
+
+#define PERIPHS_IO_MUX_GPIO34_U           (DR_REG_IO_MUX_BASE +0x14)
+#define FUNC_GPIO34_GPIO34                          2
+#define FUNC_GPIO34_GPIO34_0                        0
+
+#define PERIPHS_IO_MUX_GPIO35_U           (DR_REG_IO_MUX_BASE +0x18)
+#define FUNC_GPIO35_GPIO35                          2
+#define FUNC_GPIO35_GPIO35_0                        0
+
+#define PERIPHS_IO_MUX_GPIO36_U           (DR_REG_IO_MUX_BASE +0x04)
+#define FUNC_GPIO36_GPIO36                          2
+#define FUNC_GPIO36_GPIO36_0                        0
+
+#define PERIPHS_IO_MUX_GPIO37_U           (DR_REG_IO_MUX_BASE +0x08)
+#define FUNC_GPIO37_GPIO37                          2
+#define FUNC_GPIO37_GPIO37_0                        0
+
+#define PERIPHS_IO_MUX_GPIO38_U           (DR_REG_IO_MUX_BASE +0x0c)
+#define FUNC_GPIO38_GPIO38                          2
+#define FUNC_GPIO38_GPIO38_0                        0
+
+#define PERIPHS_IO_MUX_GPIO39_U           (DR_REG_IO_MUX_BASE +0x10)
+#define FUNC_GPIO39_GPIO39                          2
+#define FUNC_GPIO39_GPIO39_0                        0
+
 #endif /* _SOC_IO_MUX_REG_H_ */

+ 68 - 127
components/esp32/include/soc/ledc_struct.h

@@ -14,133 +14,74 @@
 #ifndef _SOC_LEDC_STRUCT_H_
 #define _SOC_LEDC_STRUCT_H_
 typedef volatile struct {
-    struct{
-        union {
-            struct {
-                uint32_t timer_sel:  2;              /*There are four high speed timers  the two bits are used to select one of them for high speed channel.  2'b00: seletc hstimer0.   2'b01: select hstimer1.  2'b10: select hstimer2.    2'b11: select hstimer3.*/
-                uint32_t sig_out_en: 1;              /*This is the output enable control bit for high speed channel*/
-                uint32_t idle_lv:    1;              /*This bit is used to control the output value when high speed channel is off.*/
-                uint32_t reserved4: 27;
-                uint32_t clk_en:     1;              /*This bit is clock gating control signal. when software configure LED_PWM internal registers  it controls the register clock.*/
-            };
-            uint32_t val;
-        } conf0;
-        union {
-            struct {
-                uint32_t hpoint:     20;             /*The output value changes to high when htimerx(x=[0 3]) selected by high speed channel has reached reg_hpoint_hsch0[19:0]*/
-                uint32_t reserved20: 12;
-            };
-            uint32_t val;
-        } hpoint;
-        union {
-            struct {
-                uint32_t duty:      25;              /*The register is used to control output duty. When hstimerx(x=[0 3]) chosen by high speed channel  has reached reg_lpoint_hsch0 the output signal changes to low. reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4])          (1)  reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4] +1)     (2)  The least four bits in this register represent the decimal part and determines when to choose (1) or (2)*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty;
-        union {
-            struct {
-                uint32_t duty_scale:10;              /*This register controls the increase or decrease step scale for high speed channel.*/
-                uint32_t duty_cycle:10;              /*This register is used to increase or decrease the duty every reg_duty_cycle_hsch0 cycles for high speed channel.*/
-                uint32_t duty_num:  10;              /*This register is used to control the number of increased or decreased times for high speed channel.*/
-                uint32_t duty_inc:   1;              /*This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel.*/
-                uint32_t duty_start: 1;              /*When reg_duty_num_hsch0 reg_duty_cycle_hsch0 and reg_duty_scale_hsch0 has been configured. these register won't take effect until set reg_duty_start_hsch0. this bit is automatically cleared by hardware.*/
-            };
-            uint32_t val;
-        } conf1;
-        union {
-            struct {
-                uint32_t duty_read: 25;              /*This register represents the current duty of the output signal for high speed channel.*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty_rd;
-    } high_speed_channel[8];
-    struct{
-        union {
-            struct {
-                uint32_t timer_sel:  2;              /*There are four low speed timers  the two bits are used to select one of them for low speed channel.  2'b00: seletc lstimer0.   2'b01: select lstimer1.  2'b10: select lstimer2.    2'b11: select lstimer3.*/
-                uint32_t sig_out_en: 1;              /*This is the output enable control bit for low speed channel.*/
-                uint32_t idle_lv:    1;              /*This bit is used to control the output value when low speed channel is off.*/
-                uint32_t para_up:    1;              /*This bit is used to update register LEDC_LSCH0_HPOINT and LEDC_LSCH0_DUTY for low speed channel.*/
-                uint32_t reserved5: 27;
-            };
-            uint32_t val;
-        } conf0;
-        union {
-            struct {
-                uint32_t hpoint:     20;             /*The output value changes to high when lstimerx(x=[0 3]) selected by low speed channel has reached reg_hpoint_lsch0[19:0]*/
-                uint32_t reserved20: 12;
-            };
-            uint32_t val;
-        } hpoint;
-        union {
-            struct {
-                uint32_t duty:      25;              /*The register is used to control output duty. When lstimerx(x=[0 3]) choosed by low speed channel has reached reg_lpoint_lsch0 the output signal changes to low. reg_lpoint_lsch0=(reg_hpoint_lsch0[19:0]+reg_duty_lsch0[24:4])          (1)  reg_lpoint_lsch0=(reg_hpoint_lsch0[19:0]+reg_duty_lsch0[24:4] +1)     (2)  The least four bits in this register represent the decimal part and determines when to choose (1) or (2)*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty;
-        union {
-            struct {
-                uint32_t duty_scale:10;              /*This register controls the increase or decrease step scale for low speed channel.*/
-                uint32_t duty_cycle:10;              /*This register is used to increase or decrease the duty every reg_duty_cycle_lsch0 cycles for low speed channel.*/
-                uint32_t duty_num:  10;              /*This register is used to control the num of increased or decreased times for low speed channel6.*/
-                uint32_t duty_inc:   1;              /*This register is used to increase the duty of output signal or decrease the duty of output signal for low speed channel6.*/
-                uint32_t duty_start: 1;              /*When reg_duty_num_hsch1 reg_duty_cycle_hsch1 and reg_duty_scale_hsch1 has been configured. these register won't take effect until set reg_duty_start_hsch1. this bit is automatically cleared by hardware.*/
-            };
-            uint32_t val;
-        } conf1;
-        union {
-            struct {
-                uint32_t duty_read: 25;              /*This register represents the current duty of the output signal for low speed channel.*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty_r;
-    } low_speed_channel[8];
-    struct{
-        union {
-            struct {
-                uint32_t timer_lim:  5;               /*This register controls the range of the counter in high speed timer. the counter range is [0 2**reg_hstimer0_lim] the max bit width for counter is 20.*/
-                uint32_t div_num:   18;               /*This register is used to configure parameter for divider in high speed timer the least significant eight bits represent the decimal part.*/
-                uint32_t pause:      1;               /*This bit is used to pause the counter in high speed timer*/
-                uint32_t rst:        1;               /*This bit is used to reset high speed timer the counter will be 0 after reset.*/
-                uint32_t tick_sel:   1;               /*This bit is used to choose apb_clk or ref_tick for high speed timer. 1'b1:apb_clk  0:ref_tick*/
-                uint32_t reserved26: 6;
-            };
-            uint32_t val;
-        } conf;
-        union {
-            struct {
-                uint32_t timer_cnt:  20;               /*software can read this register to get the current counter value in high speed timer*/
-                uint32_t reserved20: 12;
-            };
-            uint32_t val;
-        } value;
-    } high_speed_timer[4];
-    struct{
-        union {
-            struct {
-                uint32_t timer_lim:    5;              /*This register controls the range of the counter in low speed timer. the counter range is [0 2**reg_lstimer0_lim] the max bit width for counter is 20.*/
-                uint32_t div_num:     18;              /*This register is used to configure parameter for divider in low speed timer the least significant eight bits represent the decimal part.*/
-                uint32_t pause:        1;              /*This bit is used to pause the counter in low speed timer.*/
-                uint32_t rst:          1;              /*This bit is used to reset low speed timer the counter will be 0 after reset.*/
-                uint32_t tick_sel:     1;              /*This bit is used to choose slow_clk or ref_tick for low speed timer. 1'b1:slow_clk  0:ref_tick*/
-                uint32_t param_update: 1;              /*Set this bit  to update  reg_div_num_lstime0 and  reg_lstimer0_lim.*/
-                uint32_t reserved27:   5;
-            };
-            uint32_t val;
-        } conf;
-        union {
-            struct {
-                uint32_t timer_cnt:   20;              /*software can read this register to get the current counter value in low speed timer.*/
-                uint32_t reserved20:  12;
-            };
-            uint32_t val;
-        } value;
-    } low_speed_timer[4];
+    struct {
+        struct {
+            union {
+                struct {
+                    uint32_t timer_sel:  2;              /*There are four high speed timers  the two bits are used to select one of them for high speed channel.  2'b00: seletc hstimer0.   2'b01: select hstimer1.  2'b10: select hstimer2.    2'b11: select hstimer3.*/
+                    uint32_t sig_out_en: 1;              /*This is the output enable control bit for high speed channel*/
+                    uint32_t idle_lv:    1;              /*This bit is used to control the output value when high speed channel is off.*/
+                    uint32_t reserved4: 27;
+                    uint32_t clk_en:     1;              /*This bit is clock gating control signal. when software configure LED_PWM internal registers  it controls the register clock.*/
+                };
+                uint32_t val;
+            } conf0;
+            union {
+                struct {
+                    uint32_t hpoint:     20;             /*The output value changes to high when htimerx(x=[0 3]) selected by high speed channel has reached reg_hpoint_hsch0[19:0]*/
+                    uint32_t reserved20: 12;
+                };
+                uint32_t val;
+            } hpoint;
+            union {
+                struct {
+                    uint32_t duty:      25;              /*The register is used to control output duty. When hstimerx(x=[0 3]) chosen by high speed channel  has reached reg_lpoint_hsch0 the output signal changes to low. reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4])          (1)  reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4] +1)     (2)  The least four bits in this register represent the decimal part and determines when to choose (1) or (2)*/
+                    uint32_t reserved25: 7;
+                };
+                uint32_t val;
+            } duty;
+            union {
+                struct {
+                    uint32_t duty_scale:10;              /*This register controls the increase or decrease step scale for high speed channel.*/
+                    uint32_t duty_cycle:10;              /*This register is used to increase or decrease the duty every reg_duty_cycle_hsch0 cycles for high speed channel.*/
+                    uint32_t duty_num:  10;              /*This register is used to control the number of increased or decreased times for high speed channel.*/
+                    uint32_t duty_inc:   1;              /*This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel.*/
+                    uint32_t duty_start: 1;              /*When reg_duty_num_hsch0 reg_duty_cycle_hsch0 and reg_duty_scale_hsch0 has been configured. these register won't take effect until set reg_duty_start_hsch0. this bit is automatically cleared by hardware.*/
+                };
+                uint32_t val;
+            } conf1;
+            union {
+                struct {
+                    uint32_t duty_read: 25;              /*This register represents the current duty of the output signal for high speed channel.*/
+                    uint32_t reserved25: 7;
+                };
+                uint32_t val;
+            } duty_rd;
+        } channel[8];
+    } channel_group[2];                                /*two channel groups : 0: high-speed channels; 1: low-speed channels*/
+    struct {
+        struct {
+            union {
+                struct {
+                    uint32_t bit_num:  5;                 /*This register controls the range of the counter in high speed timer. the counter range is [0 2**reg_hstimer0_lim] the max bit width for counter is 20.*/
+                    uint32_t div_num:   18;               /*This register is used to configure parameter for divider in high speed timer the least significant eight bits represent the decimal part.*/
+                    uint32_t pause:      1;               /*This bit is used to pause the counter in high speed timer*/
+                    uint32_t rst:        1;               /*This bit is used to reset high speed timer the counter will be 0 after reset.*/
+                    uint32_t tick_sel:   1;               /*This bit is used to choose apb_clk or ref_tick for high speed timer. 1'b1:apb_clk  0:ref_tick*/
+                    uint32_t low_speed_update: 1;         /*This bit is only useful for low speed timer channels, reserved for high speed timers*/
+                    uint32_t reserved26: 5;
+                };
+                uint32_t val;
+            } conf;
+            union {
+                struct {
+                    uint32_t timer_cnt:  20;               /*software can read this register to get the current counter value in high speed timer*/
+                    uint32_t reserved20: 12;
+                };
+                uint32_t val;
+            } value;
+        } timer[4];
+    } timer_group[2];                                    /*two channel groups : 0: high-speed channels; 1: low-speed channels*/
     union {
         struct {
             uint32_t hstimer0_ovf:        1;           /*The interrupt raw bit for high speed channel0  counter overflow.*/

+ 0 - 14
components/esp32/ld/esp32.bt.ld

@@ -1,14 +0,0 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
-MEMORY
-{
-  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
-  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
-  are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFC0000, len = 0x40000   /* Shared RAM, minus rom bss/data/stack.*/
-  drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
-}
-
-_heap_end = 0x40000000;

+ 0 - 14
components/esp32/ld/esp32.bt.trace.ld

@@ -1,14 +0,0 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
-MEMORY
-{
-  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
-  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
-  are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFC0000, len = 0x38000   /* Shared RAM, minus rom bss/data/stack.*/
-  drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
-}
-
-_heap_end = 0x3FFF8000;

+ 15 - 3
components/esp32/ld/esp32.common.ld

@@ -1,5 +1,5 @@
 /*  Default entry point:  */
-ENTRY(call_user_start_cpu0);
+ENTRY(call_start_cpu0);
 
 SECTIONS
 {
@@ -102,7 +102,7 @@ SECTIONS
     _rodata_start = ABSOLUTE(.);
     *(.rodata)
     *(.rodata.*)
-	*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
     *(.gnu.linkonce.r.*)
     *(.rodata1)
     __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
@@ -132,7 +132,7 @@ SECTIONS
     *(.dynamic)
     *(.gnu.version_d)
     _rodata_end = ABSOLUTE(.);
-	/* Literals are also RO data. */
+    /* Literals are also RO data. */
     _lit4_start = ABSOLUTE(.);
     *(*.lit4)
     *(.lit4.*)
@@ -153,4 +153,16 @@ SECTIONS
     _text_end = ABSOLUTE(.);
     _etext = .;
   } >iram0_2_seg
+
+  .rtc.text :
+  {
+    . = ALIGN(4);
+    *(.rtc.literal .rtc.text)
+  } >rtc_iram_seg
+
+  .rtc.data :
+  {
+    *(.rtc.data)
+    *(.rtc.rodata)
+  } > rtc_slow_seg
 }

+ 47 - 6
components/esp32/ld/esp32.ld

@@ -1,14 +1,55 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
+/* ESP32 Linker Script Memory Layout
+
+   This file describes the memory layout (memory blocks) as virtual
+   memory addresses.
+
+   esp32.common.ld contains output sections to link compiler output
+   into these memory blocks.
+
+   ***
+
+   This linker script is passed through the C preprocessor to include
+   configuration options.
+
+   Please use preprocessor features sparingly! Restrict
+   to simple macros with numeric values, and/or #if/#endif blocks.
+*/
+#include "sdkconfig.h"
+
 MEMORY
 {
   /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
   of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
   are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFB0000, len = 0x50000   /* Shared RAM, minus rom bss/data/stack.*/
+
+  /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
+  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000
+
+  /* Even though the segment name is iram, it is actually mapped to flash */
+  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000
+
+  /* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
+
+     Enabling Bluetooth & Trace Memory features in menuconfig will decrease
+     the amount of RAM available.
+  */
+  dram0_0_seg (RW) :                 org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM,
+                                     len = 0x50000 - CONFIG_TRACEMEM_RESERVE_DRAM - CONFIG_BT_RESERVE_DRAM
+
+  /* Flash mapped constant data */
   drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
+
+  /* RTC fast memory (executable). Persists over deep sleep.
+   */
+  rtc_iram_seg(RWX) :                org = 0x400C0000, len = 0x2000
+
+  /* RTC slow memory (data accessible). Persists over deep sleep.
+
+     Start of RTC slow memory is reserved for ULP co-processor code + data, if enabled.
+  */
+  rtc_slow_seg(RW)  :                org = 0x50000000 + CONFIG_ULP_COPROC_RESERVE_MEM,
+                                     len = 0x1000 - CONFIG_ULP_COPROC_RESERVE_MEM
 }
 
-_heap_end = 0x40000000;
+/* Heap ends at top of dram0_0_seg */
+_heap_end = 0x40000000 - CONFIG_TRACEMEM_RESERVE_DRAM;

+ 5 - 1
components/esp32/ld/esp32.rom.ld

@@ -99,6 +99,10 @@ PROVIDE ( _data_end = 0x4000d5c8 );
 PROVIDE ( _data_end_btdm_rom = 0x4000d4f8 );
 PROVIDE ( _data_start = 0x4000d4f8 );
 PROVIDE ( _data_start_btdm_rom = 0x4000d4f4 );
+PROVIDE ( _data_start_btdm = 0x3ffae6e0);
+PROVIDE ( _data_end_btdm = 0x3ffaff10);
+PROVIDE ( _bss_start_btdm = 0x3ffb8000);
+PROVIDE ( _bss_end_btdm = 0x3ffbff70);
 PROVIDE ( _daylight = 0x3ffae0a4 );
 PROVIDE ( dbg_default_handler = 0x3ff97218 );
 PROVIDE ( dbg_state = 0x3ffb8d5d );
@@ -445,7 +449,6 @@ PROVIDE ( _lseek_r = 0x4000bd8c );
 PROVIDE ( __lshrdi3 = 0x4000c84c );
 PROVIDE ( __ltdf2 = 0x40063790 );
 PROVIDE ( __ltsf2 = 0x4006342c );
-PROVIDE ( main = 0x400076c4 );
 PROVIDE ( malloc = 0x4000bea0 );
 PROVIDE ( _malloc_r = 0x4000bbb4 );
 PROVIDE ( maxSecretKey_256 = 0x3ff97448 );
@@ -1378,6 +1381,7 @@ PROVIDE ( rom_iq_est_disable = 0x40005590 );
 PROVIDE ( rom_iq_est_enable = 0x40005514 );
 PROVIDE ( rom_linear_to_db = 0x40005f64 );
 PROVIDE ( rom_loopback_mode_en = 0x400030f8 );
+PROVIDE ( rom_main = 0x400076c4 );
 PROVIDE ( rom_meas_tone_pwr_db = 0x40006004 );
 PROVIDE ( rom_mhz2ieee = 0x4000404c );
 PROVIDE ( rom_noise_floor_auto_set = 0x40003bdc );

+ 0 - 14
components/esp32/ld/esp32.trace.ld

@@ -1,14 +0,0 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
-MEMORY
-{
-  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
-  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
-  are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFB0000, len = 0x48000   /* Shared RAM, minus rom bss/data/stack.*/
-  drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
-}
-
-_heap_end = 0x3FFF8000;

+ 1 - 1
components/esp32/lib

@@ -1 +1 @@
-Subproject commit f6d558367a08b6c9b18c2de515bd0a6740d2c45c
+Subproject commit a1e5f8b953c7934677ba7a6ed0a6dd2da0e6bd0f

+ 4 - 5
components/esp32/syscalls.c

@@ -143,7 +143,7 @@ int _open_r(struct _reent *r, const char * path, int flags, int mode) {
 }
 
 ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
-    const char* p = (const char*) data;
+    const char *data_c = (const char *)data;
     if (fd == STDOUT_FILENO) {
         static _lock_t stdout_lock; /* lazily initialised */
         /* Even though newlib does stream locking on stdout, we need
@@ -160,14 +160,13 @@ ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
            which aren't fully valid.)
         */
         _lock_acquire_recursive(&stdout_lock);
-        while(size--) {
+        for (size_t i = 0; i < size; i++) {
 #if CONFIG_NEWLIB_STDOUT_ADDCR
-            if (*p=='\n') {
+            if (data_c[i]=='\n') {
                 uart_tx_one_char('\r');
             }
 #endif
-            uart_tx_one_char(*p);
-            ++p;
+            uart_tx_one_char(data_c[i]);
         }
         _lock_release_recursive(&stdout_lock);
     }

+ 0 - 115
components/esp32/wifi.c

@@ -1,115 +0,0 @@
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// 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.
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "esp_err.h"
-#include "esp_wifi.h"
-#include "esp_event.h"
-#include "esp_task.h"
-
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "freertos/queue.h"
-#include "freertos/semphr.h"
-
-#if CONFIG_WIFI_ENABLED
-
-static bool wifi_startup_flag = false;
-
-static wifi_startup_cb_t startup_cb;
-static void *startup_ctx;
-
-#define WIFI_DEBUG(...)
-#define WIFI_API_CALL_CHECK(info, api_call, ret) \
-do{\
-    esp_err_t __err = (api_call);\
-    if ((ret) != __err) {\
-        WIFI_DEBUG("%s %d %s ret=%d\n", __FUNCTION__, __LINE__, (info), __err);\
-        return __err;\
-    }\
-} while(0)
-
-
-
-static void esp_wifi_task(void *pvParameters)
-{
-    esp_err_t err;
-    wifi_init_config_t cfg;
-    cfg.event_q = (xQueueHandle)esp_event_get_handler();
-
-    do {
-        err = esp_wifi_init(&cfg);
-        if (err != ESP_OK) {
-            WIFI_DEBUG("esp_wifi_init fail, ret=%d\n", err);
-            break;
-        }
-
-        if (startup_cb) {
-            err = (*startup_cb)(startup_ctx);
-            if (err != ESP_OK) {
-                WIFI_DEBUG("startup_cb fail, ret=%d\n", err);
-                break;
-            }
-        }
-
-        err = esp_wifi_start();
-        if (err != ESP_OK) {
-            WIFI_DEBUG("esp_wifi_start fail, ret=%d\n", err);
-            break;
-        }
-
-#if CONFIG_WIFI_AUTO_CONNECT
-        wifi_mode_t mode;
-        bool auto_connect;
-        err = esp_wifi_get_mode(&mode);
-        if (err != ESP_OK) {
-            WIFI_DEBUG("esp_wifi_get_mode fail, ret=%d\n", err);
-        }
-
-        err = esp_wifi_get_auto_connect(&auto_connect);
-        if ((mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) && auto_connect) {
-            err = esp_wifi_connect();
-            if (err != ESP_OK) {
-                WIFI_DEBUG("esp_wifi_connect fail, ret=%d\n", err);
-                break;
-            }
-        }
-#endif
-    } while (0);
-
-    if (err != ESP_OK) {
-        WIFI_DEBUG("wifi startup fail, deinit\n");
-        esp_wifi_deinit();
-    }
-
-    vTaskDelete(NULL);
-}
-
-esp_err_t esp_wifi_startup(wifi_startup_cb_t cb, void *ctx)
-{
-    if (wifi_startup_flag) {
-        return ESP_FAIL;
-    }
-
-    startup_cb = cb;
-    startup_ctx = ctx;
-
-    xTaskCreatePinnedToCore(esp_wifi_task, "wifiTask", ESP_TASK_WIFI_STARTUP_STACK, NULL, ESP_TASK_WIFI_STARTUP_PRIO, NULL, 0);
-
-    return ESP_OK;
-}
-#endif

+ 1 - 1
components/esptool_py/Makefile.projbuild

@@ -16,7 +16,7 @@ ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
 
 # the no-stub argument is temporary until esptool.py fully supports compressed uploads
-ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) $(if $(CONFIG_ESPTOOLPY_COMPRESSED),--no-stub) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ)
+ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ)
 
 ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
 

+ 1 - 1
components/esptool_py/esptool

@@ -1 +1 @@
-Subproject commit 7c84dd433512bac80e4c01c569e42b4fe76646a7
+Subproject commit 197ba605fe0c05e16bf4c5ec07b726adc8d86abc

+ 1 - 1
components/expat/component.mk

@@ -10,6 +10,6 @@ COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
 
 COMPONENT_SRCDIRS := library port
 
-CFLAGS += -Wno-error=address -Waddress -DHAVE_EXPAT_CONFIG_H
+CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
 
 include $(IDF_PATH)/make/component_common.mk

+ 22 - 0
components/expat/expat.rst

@@ -0,0 +1,22 @@
+The Expat XML Parse Instruction
+=============================
+
+Expat is an XML parser library written in C which be used for parse XML documents.
+
+It is a stream-oriented parser in which an application registers handlers for things the parser might find in the XML document.
+
+It can parse some larger files.
+
+-   Expat XML Parser support many different processor, but for the most part function you only need the following functions:
+
+    **XML_ParserCreate**: Create a new parser object
+
+    **XML_SetElementHandler**: Set handlers for start and end tags
+
+    **XML_SetCharacterDataHandler**: Set handler for text
+
+    **XML_Parse**: Pass a buffer full of document to the parser
+
+More information about Expat library can be found on http://expat.sourceforge.net
+
+An introductory article on using Expat is available on http://xml.com

+ 132 - 124
components/freertos/Kconfig

@@ -2,192 +2,200 @@ menu "FreeRTOS"
 
 # This is actually also handled in the ESP32 startup code, not only in FreeRTOS.
 config FREERTOS_UNICORE
-	bool "Run FreeRTOS only on first core"
-	default n
-	help
-		This version of FreeRTOS normally takes control of all cores of 
-		the CPU. Select this if you only want to start it on the first core.
-		This is needed when e.g. another process needs complete control
-		over the second core.
+    bool "Run FreeRTOS only on first core"
+    default n
+    help
+        This version of FreeRTOS normally takes control of all cores of 
+        the CPU. Select this if you only want to start it on the first core.
+        This is needed when e.g. another process needs complete control
+        over the second core.
 
 
 choice FREERTOS_CORETIMER
-	prompt "Xtensa timer to use as the FreeRTOS tick source"
-	default CONFIG_FREERTOS_CORETIMER_0
-	help
-		FreeRTOS needs a timer with an associated interrupt to use as
-		the main tick source to increase counters, run timers and do
-		pre-emptive multitasking with. There are multiple timers available
-		to do this, with different interrupt priorities. Check 
+    prompt "Xtensa timer to use as the FreeRTOS tick source"
+    default CONFIG_FREERTOS_CORETIMER_0
+    help
+        FreeRTOS needs a timer with an associated interrupt to use as
+        the main tick source to increase counters, run timers and do
+        pre-emptive multitasking with. There are multiple timers available
+        to do this, with different interrupt priorities. Check 
 
 config FREERTOS_CORETIMER_0
-	bool "Timer 0 (int 6, level 1)"
-	help
-		Select this to use timer 0
+    bool "Timer 0 (int 6, level 1)"
+    help
+        Select this to use timer 0
 
 config FREERTOS_CORETIMER_1
-	bool "Timer 1 (int 15, level 3)"
-	help
-		Select this to use timer 1
+    bool "Timer 1 (int 15, level 3)"
+    help
+        Select this to use timer 1
 
 config FREERTOS_CORETIMER_2
-	bool "Timer 2 (int 16, level 5)"
-	help
-		Select this to use timer 2
+    bool "Timer 2 (int 16, level 5)"
+    help
+        Select this to use timer 2
 
 endchoice
 
 config FREERTOS_HZ
-	int "Tick rate (Hz)"
-	range 1 10000
-	default 100
+    int "Tick rate (Hz)"
+    range 1 10000
+    default 100
+    help
+        Select the tick rate at which FreeRTOS does pre-emptive context switching.
+
+config FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
+	bool "Halt when an SMP-untested function is called"
+	default y
 	help
-		Select the tick rate at which FreeRTOS does pre-emptive context switching.
+		Some functions in FreeRTOS have not been thoroughly tested yet when moving to
+		the SMP implementation of FreeRTOS. When this option is enabled, these fuctions
+		will throw an assert().
 
 choice FREERTOS_CHECK_STACKOVERFLOW
-	prompt "Check for stack overflow"
-	default FREERTOS_CHECK_STACKOVERFLOW_QUICK
-	help
-		FreeRTOS can check for stack overflows in threads and trigger an user function
-		called vApplicationStackOverflowHook when this happens.
+    prompt "Check for stack overflow"
+    default FREERTOS_CHECK_STACKOVERFLOW_QUICK
+    help
+        FreeRTOS can check for stack overflows in threads and trigger an user function
+        called vApplicationStackOverflowHook when this happens.
 
 config FREERTOS_CHECK_STACKOVERFLOW_NONE
-	bool "No checking"
-	help
-		Do not check for stack overflows (configCHECK_FOR_STACK_OVERFLOW=0)
+    bool "No checking"
+    help
+        Do not check for stack overflows (configCHECK_FOR_STACK_OVERFLOW=0)
 
 config FREERTOS_CHECK_STACKOVERFLOW_PTRVAL
-	bool "Check by stack pointer value"
-	help
-		Check for stack overflows on each context switch by checking if
-		the stack pointer is in a valid range. Quick but does not detect
-		stack overflows that happened between context switches
-		(configCHECK_FOR_STACK_OVERFLOW=1)
+    bool "Check by stack pointer value"
+    help
+        Check for stack overflows on each context switch by checking if
+        the stack pointer is in a valid range. Quick but does not detect
+        stack overflows that happened between context switches
+        (configCHECK_FOR_STACK_OVERFLOW=1)
 
 config FREERTOS_CHECK_STACKOVERFLOW_CANARY
-	bool "Check using canary bytes"
-	help
-		Places some magic bytes at the end of the stack area and on each 
-		context switch, check if these bytes are still intact. More thorough
-		than just checking the pointer, but also slightly slower.
-		(configCHECK_FOR_STACK_OVERFLOW=2)
+    bool "Check using canary bytes"
+    help
+        Places some magic bytes at the end of the stack area and on each 
+        context switch, check if these bytes are still intact. More thorough
+        than just checking the pointer, but also slightly slower.
+        (configCHECK_FOR_STACK_OVERFLOW=2)
 endchoice
 
 config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
-	int "Amount of thread local storage pointers"
-	range 0 256 if !WIFI_ENABLED
-	range 1 256 if WIFI_ENABLED
-	default 1
-	help
-		FreeRTOS has the ability to store per-thread pointers in the task
-		control block. This controls the amount of pointers available;
-		0 turns off this functionality.
+    int "Amount of thread local storage pointers"
+    range 0 256 if !WIFI_ENABLED
+    range 1 256 if WIFI_ENABLED
+    default 1
+    help
+        FreeRTOS has the ability to store per-thread pointers in the task
+        control block. This controls the amount of pointers available;
+        0 turns off this functionality.
 
-		If using the WiFi stack, this value must be at least 1.
+        If using the WiFi stack, this value must be at least 1.
 
 #This still needs to be implemented.
 choice FREERTOS_PANIC
-	prompt "Panic handler behaviour"
-	default FREERTOS_PANIC_PRINT_REBOOT
-	help
-		If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is 
-		invoked. Configure the panic handlers action here.
+    prompt "Panic handler behaviour"
+    default FREERTOS_PANIC_PRINT_REBOOT
+    help
+        If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is 
+        invoked. Configure the panic handlers action here.
 
 config FREERTOS_PANIC_PRINT_HALT
-	bool "Print registers and halt"
-	help
-		Outputs the relevant registers over the serial port and halt the 
-		processor. Needs a manual reset to restart.
+    bool "Print registers and halt"
+    help
+        Outputs the relevant registers over the serial port and halt the 
+        processor. Needs a manual reset to restart.
 
 config FREERTOS_PANIC_PRINT_REBOOT
-	bool "Print registers and reboot"
-	help
-		Outputs the relevant registers over the serial port and immediately
-		reset the processor.
+    bool "Print registers and reboot"
+    help
+        Outputs the relevant registers over the serial port and immediately
+        reset the processor.
 
 config FREERTOS_PANIC_SILENT_REBOOT
-	bool "Silent reboot"
-	help
-		Just resets the processor without outputting anything
+    bool "Silent reboot"
+    help
+        Just resets the processor without outputting anything
 
 config FREERTOS_PANIC_GDBSTUB
-	bool "Invoke GDBStub"
-	help
-		Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
-		of the crash.
+    bool "Invoke GDBStub"
+    help
+        Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
+        of the crash.
 endchoice
 
 config FREERTOS_DEBUG_OCDAWARE
-	bool "Make exception and panic handlers JTAG/OCD aware"
-	default y
-	help
-		The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
-		instead of panicking, have the debugger stop on the offending instruction.
+    bool "Make exception and panic handlers JTAG/OCD aware"
+    default y
+    help
+        The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
+        instead of panicking, have the debugger stop on the offending instruction.
 
 choice FREERTOS_ASSERT
-	prompt "FreeRTOS assertions"
-	default FREERTOS_ASSERT_FAIL_ABORT
-	help
-		Failed FreeRTOS configASSERT() assertions can be configured to
-		behave in different ways.
+    prompt "FreeRTOS assertions"
+    default FREERTOS_ASSERT_FAIL_ABORT
+    help
+        Failed FreeRTOS configASSERT() assertions can be configured to
+        behave in different ways.
 
 config FREERTOS_ASSERT_FAIL_ABORT
-	bool "abort() on failed assertions"
-	help
-		If a FreeRTOS configASSERT() fails, FreeRTOS will abort() and
-		halt execution. The panic handler can be configured to handle
-		the outcome of an abort() in different ways.
+    bool "abort() on failed assertions"
+    help
+        If a FreeRTOS configASSERT() fails, FreeRTOS will abort() and
+        halt execution. The panic handler can be configured to handle
+        the outcome of an abort() in different ways.
 
 config FREERTOS_ASSERT_FAIL_PRINT_CONTINUE
-	bool "Print and continue failed assertions"
-	help
-		If a FreeRTOS assertion fails, print it out and continue.
+    bool "Print and continue failed assertions"
+    help
+        If a FreeRTOS assertion fails, print it out and continue.
 
 config FREERTOS_ASSERT_DISABLE
-	bool "Disable FreeRTOS assertions"
-	help
-		FreeRTOS configASSERT() will not be compiled into the binary.
+    bool "Disable FreeRTOS assertions"
+    help
+        FreeRTOS configASSERT() will not be compiled into the binary.
 
 endchoice
 
 config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
-	bool "Stop program on scheduler start when JTAG/OCD is detected"
-	depends on FREERTOS_DEBUG_OCDAWARE
-	default y
-	help
-		If JTAG/OCD is connected, stop execution when the scheduler is started and the first
-		task is executed.
+    bool "Stop program on scheduler start when JTAG/OCD is detected"
+    depends on FREERTOS_DEBUG_OCDAWARE
+    default y
+    help
+        If JTAG/OCD is connected, stop execution when the scheduler is started and the first
+        task is executed.
 
 menuconfig ENABLE_MEMORY_DEBUG
-	bool "Enable heap memory debug"
-	default n
-	help
-		Enable this option to show malloc heap block and memory crash detect
+    bool "Enable heap memory debug"
+    default n
+    help
+        Enable this option to show malloc heap block and memory crash detect
 
 menuconfig FREERTOS_DEBUG_INTERNALS
-	bool "Debug FreeRTOS internals"
-	default n
-	help
-		Enable this option to show the menu with internal FreeRTOS debugging features.
-		This option does not change any code by itself, it just shows/hides some options.
+    bool "Debug FreeRTOS internals"
+    default n
+    help
+        Enable this option to show the menu with internal FreeRTOS debugging features.
+        This option does not change any code by itself, it just shows/hides some options.
 
 if FREERTOS_DEBUG_INTERNALS
 
 config FREERTOS_PORTMUX_DEBUG
-	bool "Debug portMUX portENTER_CRITICAL/portEXIT_CRITICAL"
-	depends on FREERTOS_DEBUG_INTERNALS
-	default n
-	help
-		If enabled, debug information (including integrity checks) will be printed
-	 	to UART for the port-specific MUX implementation.
+    bool "Debug portMUX portENTER_CRITICAL/portEXIT_CRITICAL"
+    depends on FREERTOS_DEBUG_INTERNALS
+    default n
+    help
+        If enabled, debug information (including integrity checks) will be printed
+        to UART for the port-specific MUX implementation.
 
 config FREERTOS_PORTMUX_DEBUG_RECURSIVE
-	bool "Debug portMUX Recursion"
-	depends on FREERTOS_PORTMUX_DEBUG
-	default n
-	help
-		If enabled, additional debug information will be printed for recursive
-		portMUX usage.
+    bool "Debug portMUX Recursion"
+    depends on FREERTOS_PORTMUX_DEBUG
+    default n
+    help
+        If enabled, additional debug information will be printed for recursive
+        portMUX usage.
 
 endif # FREERTOS_DEBUG_INTERNALS
 

+ 1 - 0
components/freertos/croutine.c

@@ -143,6 +143,7 @@ BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPri
 BaseType_t xReturn;
 CRCB_t *pxCoRoutine;
 
+	UNTESTED_FUNCTION(); //Actually, coroutines are entirely unsupported
 	/* Allocate the memory that will store the co-routine control block. */
 	pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
 	if( pxCoRoutine )

+ 0 - 7
components/freertos/event_groups.c

@@ -124,7 +124,6 @@ typedef struct xEventGroupDefinition
 
 /* Again: one mux for all events. Maybe this can be made more granular. ToDo: look into that. -JD */
 static portMUX_TYPE xEventGroupMux = portMUX_INITIALIZER_UNLOCKED;
-static BaseType_t xMuxInitialized = pdFALSE;
 
 
 /*-----------------------------------------------------------*/
@@ -145,12 +144,6 @@ EventGroupHandle_t xEventGroupCreate( void )
 {
 EventGroup_t *pxEventBits;
 
-	//Initialize mux, if needed
-	if ( xMuxInitialized == pdFALSE ) {
-		vPortCPUInitializeMutex( & xEventGroupMux );
-		xMuxInitialized = pdTRUE;
-	}
-	
 	pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) );
 	if( pxEventBits != NULL )
 	{

+ 12 - 0
components/freertos/include/freertos/FreeRTOSConfig.h

@@ -124,6 +124,16 @@
         abort();                                                        \
         }
 #endif
+
+#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
+#include <stdlib.h>
+#include "rom/ets_sys.h"
+#define UNTESTED_FUNCTION() { ets_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
+#else
+#define UNTESTED_FUNCTION()
+#endif
+
+
 #endif /* def __ASSEMBLER__ */
 
 
@@ -263,5 +273,7 @@
 #define configXT_SIMULATOR					0
 
 
+
+
 #endif /* FREERTOS_CONFIG_H */
 

+ 206 - 0
components/freertos/include/freertos/ringbuf.h

@@ -0,0 +1,206 @@
+#ifndef FREERTOS_RINGBUF_H
+#define FREERTOS_RINGBUF_H
+
+/*
+Header definitions for a FreeRTOS ringbuffer object
+
+A ringbuffer instantiated by these functions essentially acts like a FreeRTOS queue, with the
+difference that it's strictly FIFO and with the main advantage that you can put in randomly-sized
+items. The capacity, accordingly, isn't measured in the amount of items, but the amount of memory
+that is used for storing the items. Dependent on the size of the items, more or less of them will 
+fit in the ring buffer.
+
+This ringbuffer tries to be efficient with memory: when inserting an item, the item data will
+be copied to the ringbuffer memory. When retrieving an item, however, a reference to ringbuffer
+memory will be returned. The returned memory is guaranteed to be 32-bit aligned and contiguous.
+The application can use this memory, but as long as it does, ringbuffer writes that would write
+to this bit of memory will block.
+
+The requirement for items to be contiguous is slightly problematic when the only way to place
+the next item would involve a wraparound from the end to the beginning of the ringbuffer. This can
+be solved in two ways:
+- allow_split_items = pdTRUE: The insertion code will split the item in two items; one which fits
+in the space left at the end of the ringbuffer, one that contains the remaining data which is placed
+in the beginning. Two xRingbufferReceive calls will be needed to retrieve the data.
+- allow_split_items = pdFALSE: The insertion code will leave the room at the end of the ringbuffer
+unused and instead will put the entire item at the start of the ringbuffer, as soon as there is 
+enough free space.
+
+The maximum size of an item will be affected by this decision. When split items are allowed, it's
+acceptable to push items of (buffer_size)-16 bytes into the buffer. When it's not allowed, the
+maximum size is (buffer_size/2)-8 bytes.
+*/
+
+//An opaque handle for a ringbuff object.
+typedef void * RingbufHandle_t;
+
+
+/**
+ * @brief  Create a ring buffer
+ *
+ * @param  buf_length : Length of circular buffer, in bytes. Each entry will take up its own length, plus a header
+ *                      that at the moment is equal to sizeof(size_t).
+ * @param allow_split_items : pdTRUE if it is acceptable that item data is inserted as two
+ *                            items instead of one.
+ *
+ * @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
+ */
+RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items);
+
+
+/**
+ * @brief  Delete a ring buffer
+ *
+ * @param  ringbuf - Ring buffer to delete
+ *
+ * @return void
+ */
+void vRingbufferDelete(RingbufHandle_t ringbuf);
+
+
+/**
+ * @brief  Get maximum size of an item that can be placed in the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to query
+ *
+ * @return Maximum size, in bytes, of an item that can be placed in a ring buffer.
+ */
+size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf);
+
+
+/**
+ * @brief  Insert an item into the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to insert the item into
+ * @param  data - Pointer to data to insert. NULL is allowed if data_size is 0.
+ * @param  data_size - Size of data to insert. A value of 0 is allowed.
+ * @param  xTicksToWait - Ticks to wait for room in the ringbuffer.
+ *
+ * @return pdTRUE if succeeded, pdFALSE on time-out or when the buffer is larger 
+ *         than indicated by xRingbufferGetMaxItemSize(ringbuf).
+ */
+BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t data_size, TickType_t ticks_to_wait);
+
+
+/**
+ * @brief  Insert an item into the ring buffer from an ISR
+ *
+ * @param  ringbuf - Ring buffer to insert the item into
+ * @param  data - Pointer to data to insert. NULL is allowed if data_size is 0.
+ * @param  data_size - Size of data to insert. A value of 0 is allowed.
+ * @param  higher_prio_task_awoken - Value pointed to will be set to pdTRUE if the push woke up a higher
+ *                                     priority task.
+ *
+ * @return pdTRUE if succeeded, pdFALSE when the ring buffer does not have space.
+ */
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t data_size, BaseType_t *higher_prio_task_awoken);
+
+/**
+ * @brief  Retrieve an item from the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to retrieve the item from
+ * @param  item_size - Pointer to a variable to which the size of the retrieved item will be written.
+ * @param  xTicksToWait - Ticks to wait for items in the ringbuffer.
+ *
+ * @return Pointer to the retrieved item on success; *item_size filled with the length of the 
+ *         item. NULL on timeout, *item_size is untouched in that case.
+ */
+void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait);
+
+
+/**
+ * @brief  Retrieve an item from the ring buffer from an ISR
+ *
+ * @param  ringbuf - Ring buffer to retrieve the item from
+ * @param  item_size - Pointer to a variable to which the size of the retrieved item will be written.
+ *
+ * @return Pointer to the retrieved item on success; *item_size filled with the length of the 
+ *         item. NULL when the ringbuffer is empty, *item_size is untouched in that case.
+ */
+void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size);
+
+
+/**
+ * @brief  Return a previously-retrieved item to the ringbuffer
+ *
+ * @param  ringbuf - Ring buffer the item was retrieved from
+ * @param  item - Item that was received earlier
+ *
+ * @return void
+ */
+void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item);
+
+
+
+/**
+ * @brief  Return a previously-retrieved item to the ringbuffer from an ISR
+ *
+ * @param  ringbuf - Ring buffer the item was retrieved from
+ * @param  item - Item that was received earlier
+ * @param  higher_prio_task_awoken - Value pointed to will be set to pdTRUE if the push woke up a higher
+ *                                     priority task.
+ *
+ * @return void
+ */
+void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_t *higher_prio_task_awoken);
+
+
+/**
+ * @brief  Add the ringbuffer to a queue set. This specifically adds the semaphore that indicates
+ *         more space has become available in the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to add to the queue set
+ * @param  xQueueSet - Queue set to add the ringbuffer to
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Add the ringbuffer to a queue set. This specifically adds the semaphore that indicates
+ *         something has been written into the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to add to the queue set
+ * @param  xQueueSet - Queue set to add the ringbuffer to
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Remove the ringbuffer from a queue set. This specifically removes the semaphore that indicates
+ *         more space has become available in the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to remove from the queue set
+ * @param  xQueueSet - Queue set to remove the ringbuffer from
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Remove the ringbuffer from a queue set. This specifically removes the semaphore that indicates
+ *         something has been written to the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to remove from the queue set
+ * @param  xQueueSet - Queue set to remove the ringbuffer from
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Debugging function to print the internal pointers in the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to show
+ *
+ * @return void
+ */
+void xRingbufferPrintInfo(RingbufHandle_t ringbuf);
+
+
+#endif

+ 6 - 0
components/freertos/include/freertos/task.h

@@ -1979,6 +1979,12 @@ BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcN
  */
 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
 
+
+/*
+ * Get the current core affinity of a task
+ */
+BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
+
 /*
  * Set the uxTaskNumber of the task referenced by the xTask parameter to
  * uxHandle.

+ 2 - 2
components/freertos/panic.c

@@ -81,7 +81,7 @@ int xPortGetCoreID();
 void  __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
 	panicPutStr("***ERROR*** A stack overflow in task");
 	panicPutStr((char*)pcTaskName);
-	panicPutStr("has been detected.\n");
+	panicPutStr("has been detected.\r\n");
 }
 
 static const char *edesc[]={
@@ -160,7 +160,7 @@ void xt_unhandled_exception(XtExcFrame *frame) {
 	panicPutStr("Guru Meditation Error of type ");
 	x=regs[20];
 	if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown");
-	panicPutStr(" occured on core ");
+	panicPutStr(" occurred on core ");
 	panicPutDec(xPortGetCoreID());
 	if (inOCDMode()) {
 		panicPutStr(" at pc=");

+ 90 - 304
components/freertos/queue.c

@@ -100,11 +100,6 @@ header files above, but not in this file, in order to generate the correct
 privileged Vs unprivileged linkage and placement. */
 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
 
-
-/* Constants used with the xRxLock and xTxLock structure members. */
-#define queueUNLOCKED					( ( BaseType_t ) -1 )
-#define queueLOCKED_UNMODIFIED			( ( BaseType_t ) 0 )
-
 /* When the Queue_t structure is used to represent a base queue its pcHead and
 pcTail members are used as pointers into the queue storage area.  When the
 Queue_t structure is used to represent a mutex pcHead and pcTail pointers are
@@ -163,9 +158,6 @@ typedef struct QueueDefinition
 	UBaseType_t uxLength;			/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
 	UBaseType_t uxItemSize;			/*< The size of each items that the queue will hold. */
 
-	volatile BaseType_t xRxLock;	/*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
-	volatile BaseType_t xTxLock;	/*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
-
 	#if ( configUSE_TRACE_FACILITY == 1 )
 		UBaseType_t uxQueueNumber;
 		uint8_t ucQueueType;
@@ -212,15 +204,6 @@ typedef xQUEUE Queue_t;
 
 #endif /* configQUEUE_REGISTRY_SIZE */
 
-/*
- * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not
- * prevent an ISR from adding or removing items to the queue, but does prevent
- * an ISR from removing tasks from the queue event lists.  If an ISR finds a
- * queue is locked it will instead increment the appropriate queue lock count
- * to indicate that a task may require unblocking.  When the queue in unlocked
- * these lock counts are inspected, and the appropriate action taken.
- */
-static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
 
 /*
  * Uses a critical section to determine if there is any data in a queue.
@@ -255,27 +238,6 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer
 	static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION;
 #endif
 
-/*-----------------------------------------------------------*/
-
-/*
- * Macro to mark a queue as locked.  Locking a queue prevents an ISR from
- * accessing the queue event lists.
- */
-#define prvLockQueue( pxQueue )								\
-	taskENTER_CRITICAL(&pxQueue->mux);									\
-	{														\
-		if( ( pxQueue )->xRxLock == queueUNLOCKED )			\
-		{													\
-			( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED;	\
-		}													\
-		if( ( pxQueue )->xTxLock == queueUNLOCKED )			\
-		{													\
-			( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED;	\
-		}													\
-	}														\
-	taskEXIT_CRITICAL(&pxQueue->mux)
-/*-----------------------------------------------------------*/
-
 BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
 {
 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
@@ -292,8 +254,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
 		pxQueue->pcWriteTo = pxQueue->pcHead;
 		pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
-		pxQueue->xRxLock = queueUNLOCKED;
-		pxQueue->xTxLock = queueUNLOCKED;
 
 		if( xNewQueue == pdFALSE )
 		{
@@ -441,8 +401,6 @@ int8_t *pcAllocatedBuffer;
 			pxNewQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
 			pxNewQueue->uxLength = ( UBaseType_t ) 1U;
 			pxNewQueue->uxItemSize = ( UBaseType_t ) 0U;
-			pxNewQueue->xRxLock = queueUNLOCKED;
-			pxNewQueue->xTxLock = queueUNLOCKED;
 
 			#if ( configUSE_TRACE_FACILITY == 1 )
 			{
@@ -787,7 +745,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		now the critical section has been exited. */
 
 		taskENTER_CRITICAL(&pxQueue->mux);
-//		prvLockQueue( pxQueue );
 
 		/* Update the timeout state to see if it has expired yet. */
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@@ -797,13 +754,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				traceBLOCKING_ON_QUEUE_SEND( pxQueue );
 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
 
-				/* Unlocking the queue means queue events can effect the
-				event list.  It is possible	that interrupts occurring now
-				remove this task from the event	list again - but as the
-				scheduler is suspended the task will go onto the pending
-				ready last instead of the actual ready list. */
-//				prvUnlockQueue( pxQueue );
-
 
 				/* Resuming the scheduler will move tasks from the pending
 				ready list into the ready list - so it is feasible that this
@@ -816,14 +766,12 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			else
 			{
 				/* Try again. */
-//				prvUnlockQueue( pxQueue );
 				taskEXIT_CRITICAL(&pxQueue->mux);
 			}
 		}
 		else
 		{
 			/* The timeout has expired. */
-//			prvUnlockQueue( pxQueue );
 			taskEXIT_CRITICAL(&pxQueue->mux);
 
 			/* Return to the original privilege level before exiting the
@@ -940,7 +888,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 		configASSERT( pxQueue );
 		configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
-		ets_printf("Not Supported: %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		for( ;; )
 		{
 			taskENTER_CRITICAL();
@@ -1129,27 +1077,18 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			disinheritance here or to clear the mutex holder TCB member. */
 			( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
 
-			/* The event list is not altered if the queue is locked.  This will
-			be done when the queue is unlocked later. */
-			if( pxQueue->xTxLock == queueUNLOCKED )
+			#if ( configUSE_QUEUE_SETS == 1 )
 			{
-				#if ( configUSE_QUEUE_SETS == 1 )
+				if( pxQueue->pxQueueSetContainer != NULL )
 				{
-					if( pxQueue->pxQueueSetContainer != NULL )
+					if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )
 					{
-						if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )
+						/* The queue is a member of a queue set, and posting
+						to the queue set caused a higher priority task to
+						unblock.  A context switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
 						{
-							/* The queue is a member of a queue set, and posting
-							to the queue set caused a higher priority task to
-							unblock.  A context switch is required. */
-							if( pxHigherPriorityTaskWoken != NULL )
-							{
-								*pxHigherPriorityTaskWoken = pdTRUE;
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
+							*pxHigherPriorityTaskWoken = pdTRUE;
 						}
 						else
 						{
@@ -1158,40 +1097,17 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 					}
 					else
 					{
-						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-						{
-							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-							{
-								/* The task waiting has a higher priority so
-								record that a context switch is required. */
-								if( pxHigherPriorityTaskWoken != NULL )
-								{
-									*pxHigherPriorityTaskWoken = pdTRUE;
-								}
-								else
-								{
-									mtCOVERAGE_TEST_MARKER();
-								}
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						mtCOVERAGE_TEST_MARKER();
 					}
 				}
-				#else /* configUSE_QUEUE_SETS */
+				else
 				{
 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
 					{
 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
 						{
-							/* The task waiting has a higher priority so record that a
-							context	switch is required. */
+							/* The task waiting has a higher priority so
+							record that a context switch is required. */
 							if( pxHigherPriorityTaskWoken != NULL )
 							{
 								*pxHigherPriorityTaskWoken = pdTRUE;
@@ -1211,15 +1127,35 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 						mtCOVERAGE_TEST_MARKER();
 					}
 				}
-				#endif /* configUSE_QUEUE_SETS */
 			}
-			else
+			#else /* configUSE_QUEUE_SETS */
 			{
-				/* Increment the lock count so the task that unlocks the queue
-				knows that data was posted while it was locked. */
-				++( pxQueue->xTxLock );
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+				{
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+					{
+						/* The task waiting has a higher priority so record that a
+						context	switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
+						{
+							*pxHigherPriorityTaskWoken = pdTRUE;
+						}
+						else
+						{
+							mtCOVERAGE_TEST_MARKER();
+						}
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
 			}
-
+			#endif /* configUSE_QUEUE_SETS */
 			xReturn = pdPASS;
 		}
 		else
@@ -1285,27 +1221,18 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 			++( pxQueue->uxMessagesWaiting );
 
-			/* The event list is not altered if the queue is locked.  This will
-			be done when the queue is unlocked later. */
-			if( pxQueue->xTxLock == queueUNLOCKED )
+			#if ( configUSE_QUEUE_SETS == 1 )
 			{
-				#if ( configUSE_QUEUE_SETS == 1 )
+				if( pxQueue->pxQueueSetContainer != NULL )
 				{
-					if( pxQueue->pxQueueSetContainer != NULL )
+					if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
 					{
-						if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
+						/* The semaphore is a member of a queue set, and
+						posting	to the queue set caused a higher priority
+						task to	unblock.  A context switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
 						{
-							/* The semaphore is a member of a queue set, and
-							posting	to the queue set caused a higher priority
-							task to	unblock.  A context switch is required. */
-							if( pxHigherPriorityTaskWoken != NULL )
-							{
-								*pxHigherPriorityTaskWoken = pdTRUE;
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
+							*pxHigherPriorityTaskWoken = pdTRUE;
 						}
 						else
 						{
@@ -1314,40 +1241,17 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 					}
 					else
 					{
-						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-						{
-							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-							{
-								/* The task waiting has a higher priority so
-								record that a context switch is required. */
-								if( pxHigherPriorityTaskWoken != NULL )
-								{
-									*pxHigherPriorityTaskWoken = pdTRUE;
-								}
-								else
-								{
-									mtCOVERAGE_TEST_MARKER();
-								}
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						mtCOVERAGE_TEST_MARKER();
 					}
 				}
-				#else /* configUSE_QUEUE_SETS */
+				else
 				{
 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
 					{
 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
 						{
-							/* The task waiting has a higher priority so record that a
-							context	switch is required. */
+							/* The task waiting has a higher priority so
+							record that a context switch is required. */
 							if( pxHigherPriorityTaskWoken != NULL )
 							{
 								*pxHigherPriorityTaskWoken = pdTRUE;
@@ -1367,14 +1271,35 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 						mtCOVERAGE_TEST_MARKER();
 					}
 				}
-				#endif /* configUSE_QUEUE_SETS */
 			}
-			else
+			#else /* configUSE_QUEUE_SETS */
 			{
-				/* Increment the lock count so the task that unlocks the queue
-				knows that data was posted while it was locked. */
-				++( pxQueue->xTxLock );
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+				{
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+					{
+						/* The task waiting has a higher priority so record that a
+						context	switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
+						{
+							*pxHigherPriorityTaskWoken = pdTRUE;
+						}
+						else
+						{
+							mtCOVERAGE_TEST_MARKER();
+						}
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
 			}
+			#endif /* configUSE_QUEUE_SETS */
 
 			xReturn = pdPASS;
 		}
@@ -1525,7 +1450,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		now the critical section has been exited. */
 
 		taskENTER_CRITICAL(&pxQueue->mux);
-//		prvLockQueue( pxQueue );
 
 		/* Update the timeout state to see if it has expired yet. */
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@@ -1548,20 +1472,17 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				#endif
 
 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
-//				prvUnlockQueue( pxQueue );
 				taskEXIT_CRITICAL(&pxQueue->mux);
 				portYIELD_WITHIN_API();
 			}
 			else
 			{
 				/* Try again. */
-//				prvUnlockQueue( pxQueue );
 				taskEXIT_CRITICAL(&pxQueue->mux);
 			}
 		}
 		else
 		{
-//			prvUnlockQueue( pxQueue );
 			taskEXIT_CRITICAL(&pxQueue->mux);
 			traceQUEUE_RECEIVE_FAILED( pxQueue );
 			return errQUEUE_EMPTY;
@@ -1606,26 +1527,15 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			prvCopyDataFromQueue( pxQueue, pvBuffer );
 			--( pxQueue->uxMessagesWaiting );
 
-			/* If the queue is locked the event list will not be modified.
-			Instead update the lock count so the task that unlocks the queue
-			will know that an ISR has removed data while the queue was
-			locked. */
-			if( pxQueue->xRxLock == queueUNLOCKED )
+			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
 			{
-				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
 				{
-					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+					/* The task waiting has a higher priority than us so
+					force a context switch. */
+					if( pxHigherPriorityTaskWoken != NULL )
 					{
-						/* The task waiting has a higher priority than us so
-						force a context switch. */
-						if( pxHigherPriorityTaskWoken != NULL )
-						{
-							*pxHigherPriorityTaskWoken = pdTRUE;
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						*pxHigherPriorityTaskWoken = pdTRUE;
 					}
 					else
 					{
@@ -1639,9 +1549,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			}
 			else
 			{
-				/* Increment the lock count so the task that unlocks the queue
-				knows that data was removed while it was locked. */
-				++( pxQueue->xRxLock );
+				mtCOVERAGE_TEST_MARKER();
 			}
 
 			xReturn = pdPASS;
@@ -1902,129 +1810,7 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer
 		( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports.  Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */
 	}
 }
-/*-----------------------------------------------------------*/
-
-static void prvUnlockQueue( Queue_t * const pxQueue )
-{
-	/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
 
-	/* The lock counts contains the number of extra data items placed or
-	removed from the queue while the queue was locked.  When a queue is
-	locked items can be added or removed, but the event lists cannot be
-	updated. */
-	taskENTER_CRITICAL(&pxQueue->mux);
-	{
-		/* See if data was added to the queue while it was locked. */
-		while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )
-		{
-			/* Data was posted while the queue was locked.  Are any tasks
-			blocked waiting for data to become available? */
-			#if ( configUSE_QUEUE_SETS == 1 )
-			{
-				if( pxQueue->pxQueueSetContainer != NULL )
-				{
-					if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
-					{
-						/* The queue is a member of a queue set, and posting to
-						the queue set caused a higher priority task to unblock.
-						A context switch is required. */
-						taskEXIT_CRITICAL(&pxQueue->mux); //ToDo: Is aquire/release needed around any of the bTaskMissedYield calls?
-						vTaskMissedYield();
-						taskENTER_CRITICAL(&pxQueue->mux);
-					}
-					else
-					{
-						mtCOVERAGE_TEST_MARKER();
-					}
-				}
-				else
-				{
-					/* Tasks that are removed from the event list will get added to
-					the pending ready list as the scheduler is still suspended. */
-					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-					{
-						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-						{
-							/* The task waiting has a higher priority so record that a
-							context	switch is required. */
-							taskEXIT_CRITICAL(&pxQueue->mux);
-							vTaskMissedYield();
-							taskENTER_CRITICAL(&pxQueue->mux);
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
-					}
-					else
-					{
-						break;
-					}
-				}
-			}
-			#else /* configUSE_QUEUE_SETS */
-			{
-				/* Tasks that are removed from the event list will get added to
-				the pending ready list as the scheduler is still suspended. */
-				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-				{
-					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-					{
-						/* The task waiting has a higher priority so record that a
-						context	switch is required. */
-						taskEXIT_CRITICAL(&pxQueue->mux);
-						vTaskMissedYield();
-						taskENTER_CRITICAL(&pxQueue->mux);
-					}
-					else
-					{
-						mtCOVERAGE_TEST_MARKER();
-					}
-				}
-				else
-				{
-					break;
-				}
-			}
-			#endif /* configUSE_QUEUE_SETS */
-
-			--( pxQueue->xTxLock );
-		}
-
-		pxQueue->xTxLock = queueUNLOCKED;
-	}
-	taskEXIT_CRITICAL(&pxQueue->mux);
-
-	/* Do the same for the Rx lock. */
-	taskENTER_CRITICAL(&pxQueue->mux);
-	{
-		while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )
-		{
-			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
-			{
-				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
-				{
-					taskEXIT_CRITICAL(&pxQueue->mux);
-					vTaskMissedYield();
-					taskENTER_CRITICAL(&pxQueue->mux);
-				}
-				else
-				{
-					mtCOVERAGE_TEST_MARKER();
-				}
-
-				--( pxQueue->xRxLock );
-			}
-			else
-			{
-				break;
-			}
-		}
-
-		pxQueue->xRxLock = queueUNLOCKED;
-	}
-	taskEXIT_CRITICAL(&pxQueue->mux);
-}
 /*-----------------------------------------------------------*/
 
 static BaseType_t prvIsQueueEmpty( Queue_t *pxQueue )
@@ -2117,6 +1903,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 	BaseType_t xReturn;
 	Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
+		UNTESTED_FUNCTION();
 		/* If the queue is already full we may have to block.  A critical section
 		is required to prevent an interrupt removing something from the queue
 		between the check to see if the queue is full and blocking on the queue. */
@@ -2390,7 +2177,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 	void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 	{
 	UBaseType_t ux;
-
+		
+		UNTESTED_FUNCTION();
 		/* See if there is an empty space in the registry.  A NULL name denotes
 		a free slot. */
 		for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ )
@@ -2458,10 +2246,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		/* Only do anything if there are no messages in the queue.  This function
 		will not actually cause the task to block, just place it on a blocked
 		list.  It will not block until the scheduler is unlocked - at which
-		time a yield will be performed.  If an item is added to the queue while
-		the queue is locked, and the calling task blocks on the queue, then the
-		calling task will be immediately unblocked when the queue is unlocked. */
-//		prvLockQueue( pxQueue );
+		time a yield will be performed.  */
+		taskENTER_CRITICAL(&pxQueue->mux);
 		if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
 		{
 			/* There is nothing in the queue, block for the specified period. */
@@ -2471,7 +2257,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		{
 			mtCOVERAGE_TEST_MARKER();
 		}
-//		prvUnlockQueue( pxQueue );
+		taskEXIT_CRITICAL(&pxQueue->mux);
 	}
 
 #endif /* configUSE_TIMERS */

+ 474 - 0
components/freertos/ringbuf.c

@@ -0,0 +1,474 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// 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.
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/ringbuf.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef enum {
+    flag_allowsplit = 1,
+} rbflag_t;
+
+typedef enum {
+    iflag_free = 1,             //Buffer is not read and given back by application, free to overwrite
+    iflag_dummydata = 2,        //Data from here to end of ringbuffer is dummy. Restart reading at start of ringbuffer.
+} itemflag_t;
+
+
+//The ringbuffer structure
+typedef struct {
+    SemaphoreHandle_t free_space_sem;           //Binary semaphore, wakes up writing threads when there's more free space
+    SemaphoreHandle_t items_buffered_sem;       //Binary semaphore, indicates there are new packets in the circular buffer. See remark.
+    size_t size;                                //Size of the data storage
+    uint8_t *write_ptr;                         //Pointer where the next item is written
+    uint8_t *read_ptr;                          //Pointer from where the next item is read
+    uint8_t *free_ptr;                          //Pointer to the last block that hasn't been given back to the ringbuffer yet
+    uint8_t *data;                              //Data storage
+    portMUX_TYPE mux;                           //Spinlock for actual data/ptr/struct modification
+    rbflag_t flags;
+} ringbuf_t;
+
+
+
+/*
+Remark: A counting semaphore for items_buffered_sem would be more logical, but counting semaphores in
+FreeRTOS need a maximum count, and allocate more memory the larger the maximum count is. Here, we
+would need to set the maximum to the maximum amount of times a null-byte unit firs in the buffer,
+which is quite high and so would waste a fair amount of memory.
+*/
+
+
+//The header prepended to each ringbuffer entry. Size is assumed to be a multiple of 32bits.
+typedef struct {
+    size_t len;
+    itemflag_t flags;
+} buf_entry_hdr_t;
+
+
+//Calculate space free in the buffer
+static int ringbufferFreeMem(ringbuf_t *rb) 
+{
+    int free_size = rb->free_ptr-rb->write_ptr;
+    if (free_size <= 0) free_size += rb->size;
+    //Reserve one byte. If we do not do this and the entire buffer is filled, we get a situation 
+    //where read_ptr == free_ptr, messing up the next calculation.
+    return free_size-1;
+}
+
+//Copies a single item to the ring buffer. Assumes there is space in the ringbuffer and
+//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
+//success, pdFALSE if it can't make the item fit and the calling routine needs to retry
+//later or fail.
+//This function by itself is not threadsafe, always call from within a muxed section.
+static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) 
+{
+    size_t rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value
+    configASSERT(((int)rb->write_ptr&3)==0); //write_ptr needs to be 32-bit aligned
+    configASSERT(rb->write_ptr-(rb->data+rb->size) >= sizeof(buf_entry_hdr_t)); //need to have at least the size 
+                                            //of a header to the end of the ringbuff
+    size_t rem_len=(rb->data + rb->size) - rb->write_ptr; //length remaining until end of ringbuffer
+    
+    //See if we have enough contiguous space to write the buffer.
+    if (rem_len < rbuffer_size + sizeof(buf_entry_hdr_t)) {
+        //The buffer can't be contiguously written to the ringbuffer, but needs special handling. Do
+        //that depending on how the ringbuffer is configured.
+        //The code here is also expected to check if the buffer, mangled in whatever way is implemented,
+        //will still fit, and return pdFALSE if that is not the case.
+        if (rb->flags & flag_allowsplit) {
+            //Buffer plus header is not going to fit in the room from wr_pos to the end of the 
+            //ringbuffer... we need to split the write in two.
+            //First, see if this will fit at all.
+            if (ringbufferFreeMem(rb) < (sizeof(buf_entry_hdr_t)*2)+rbuffer_size) {
+                //Will not fit.
+                return pdFALSE;
+            }
+            //Because the code at the end of the function makes sure we always have 
+            //room for a header, this should never assert.
+            configASSERT(rem_len>=sizeof(buf_entry_hdr_t));
+            //Okay, it should fit. Write everything.
+            //First, place bit of buffer that does fit. Write header first...
+            buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
+            hdr->flags=0;
+            hdr->len=rem_len-sizeof(buf_entry_hdr_t);
+            rb->write_ptr+=sizeof(buf_entry_hdr_t);
+            rem_len-=sizeof(buf_entry_hdr_t);
+            if (rem_len!=0) {
+                //..then write the data bit that fits.
+                memcpy(rb->write_ptr, buffer, rem_len);
+                //Update vars so the code later on will write the rest of the data.
+                buffer+=rem_len;
+                rbuffer_size-=rem_len;
+                buffer_size-=rem_len;
+            } else {
+                //Huh, only the header fit. Mark as dummy so the receive function doesn't receive
+                //an useless zero-byte packet.
+                hdr->flags|=iflag_dummydata;
+            }
+            rb->write_ptr=rb->data;
+        } else {
+            //Buffer plus header is not going to fit in the room from wr_pos to the end of the 
+            //ringbuffer... but we're not allowed to split the buffer. We need to fill the 
+            //rest of the ringbuffer with a dummy item so we can place the data at the _start_ of
+            //the ringbuffer..
+            //First, find out if we actually have enough space at the start of the ringbuffer to
+            //make this work (Again, we need 4 bytes extra because otherwise read_ptr==free_ptr)
+            if (rb->free_ptr-rb->data < rbuffer_size+sizeof(buf_entry_hdr_t)+4) {
+                //Will not fit.
+                return pdFALSE;
+            }
+            //If the read buffer hasn't wrapped around yet, there's no way this will work either.
+            if (rb->free_ptr > rb->write_ptr) {
+                //No luck.
+                return pdFALSE;
+            }
+
+            //Okay, it will fit. Mark the rest of the ringbuffer space with a dummy packet.
+            buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
+            hdr->flags=iflag_dummydata;
+            //Reset the write pointer to the start of the ringbuffer so the code later on can
+            //happily write the data.
+            rb->write_ptr=rb->data;
+        }
+    } else {
+        //No special handling needed. Checking if it's gonna fit probably still is a good idea.
+        if (ringbufferFreeMem(rb) < sizeof(buf_entry_hdr_t)+rbuffer_size) {
+            //Buffer is not going to fit, period.
+            return pdFALSE;
+        }
+    }
+
+    //If we are here, the buffer is guaranteed to fit in the space starting at the write pointer.
+    buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
+    hdr->len=buffer_size;
+    hdr->flags=0;
+    rb->write_ptr+=sizeof(buf_entry_hdr_t);
+    memcpy(rb->write_ptr, buffer, buffer_size);
+    rb->write_ptr+=rbuffer_size;
+
+    //The buffer will wrap around if we don't have room for a header anymore.
+    if ((rb->data+rb->size)-rb->write_ptr < sizeof(buf_entry_hdr_t)) {
+        //'Forward' the write buffer until we are at the start of the ringbuffer.
+        //The read pointer will always be at the start of a full header, which cannot 
+        //exist at the point of the current write pointer, so there's no chance of overtaking
+        //that.
+        rb->write_ptr=rb->data;
+    }
+    return pdTRUE;
+}
+
+//Retrieves a pointer to the data of the next item, or NULL if this is not possible.
+//This function by itself is not threadsafe, always call from within a muxed section.
+static uint8_t *getItemFromRingbuf(ringbuf_t *rb, size_t *length)
+{
+    uint8_t *ret;
+    configASSERT(((int)rb->read_ptr&3)==0);
+    if (rb->read_ptr == rb->write_ptr) {
+        //No data available.
+        return NULL;
+    }
+    //The item written at the point of the read pointer may be a dummy item.
+    //We need to skip past it first, if that's the case.
+    buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->read_ptr;
+    configASSERT((hdr->len < rb->size) || (hdr->flags & iflag_dummydata));
+    if (hdr->flags & iflag_dummydata) {
+        //Hdr is dummy data. Reset to start of ringbuffer.
+        rb->read_ptr=rb->data;
+        //Get real header
+        hdr=(buf_entry_hdr_t *)rb->read_ptr;
+        configASSERT(hdr->len < rb->size);
+        //No need to re-check if the ringbuffer is empty: the write routine will
+        //always write a dummy item plus the real data item in one go, so now we must
+        //be at the real data item by definition.
+    }
+    //Okay, pass the data back.
+    ret=rb->read_ptr+sizeof(buf_entry_hdr_t);
+    *length=hdr->len;
+    //...and move the read pointer past the data.
+    rb->read_ptr+=sizeof(buf_entry_hdr_t)+((hdr->len+3)&~3);
+    //The buffer will wrap around if we don't have room for a header anymore.
+    if ((rb->data + rb->size) - rb->read_ptr < sizeof(buf_entry_hdr_t)) {
+        rb->read_ptr=rb->data;
+    }
+    return ret;
+}
+
+//Returns an item to the ringbuffer. Will mark the item as free, and will see if the free pointer
+//can be increase.
+//This function by itself is not threadsafe, always call from within a muxed section.
+static void returnItemToRingbuf(ringbuf_t *rb, void *item) {
+    uint8_t *data=(uint8_t*)item;
+    configASSERT(((int)rb->free_ptr&3)==0);
+    configASSERT(data >= rb->data);
+    configASSERT(data < rb->data+rb->size);
+    //Grab the buffer entry that preceeds the buffer
+    buf_entry_hdr_t *hdr=(buf_entry_hdr_t*)(data-sizeof(buf_entry_hdr_t));
+    configASSERT(hdr->len < rb->size);
+    configASSERT((hdr->flags & iflag_dummydata)==0);
+    configASSERT((hdr->flags & iflag_free)==0);
+    //Mark the buffer as free.
+    hdr->flags|=iflag_free;
+
+    //Do a cleanup pass.
+    hdr=(buf_entry_hdr_t *)rb->free_ptr;
+    //basically forward free_ptr until we run into either a block that is still in use or the write pointer.
+    while (((hdr->flags & iflag_free) || (hdr->flags & iflag_dummydata)) && rb->free_ptr != rb->write_ptr) {
+        if (hdr->flags & iflag_dummydata) {
+            //Rest is dummy data. Reset to start of ringbuffer.
+            rb->free_ptr=rb->data;
+        } else {
+            //Skip past item
+            size_t len=(hdr->len+3)&~3;
+            rb->free_ptr+=len+sizeof(buf_entry_hdr_t);
+            configASSERT(rb->free_ptr<=rb->data+rb->size);
+        }
+        //The buffer will wrap around if we don't have room for a header anymore.
+        if ((rb->data+rb->size)-rb->free_ptr < sizeof(buf_entry_hdr_t)) {
+            rb->free_ptr=rb->data;
+        }
+        //Next header
+        hdr=(buf_entry_hdr_t *)rb->free_ptr;
+    }
+}
+
+
+void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    ets_printf("Rb size %d free %d rptr %d freeptr %d wptr %d\n",
+            rb->size, ringbufferFreeMem(rb), rb->read_ptr-rb->data, rb->free_ptr-rb->data, rb->write_ptr-rb->data);
+}
+
+
+
+RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items)
+{
+    ringbuf_t *rb = malloc(sizeof(ringbuf_t));
+    if (rb==NULL) goto err;
+    memset(rb, 0, sizeof(ringbuf_t));
+    rb->data = malloc(buf_length);
+    if (rb->data == NULL) goto err;
+    rb->size = buf_length;
+    rb->free_ptr = rb->data;
+    rb->read_ptr = rb->data;
+    rb->write_ptr = rb->data;
+    rb->free_space_sem = xSemaphoreCreateBinary();
+    rb->items_buffered_sem = xSemaphoreCreateBinary();
+    rb->flags=0;
+    if (allow_split_items) rb->flags|=flag_allowsplit;
+    if (rb->free_space_sem == NULL || rb->items_buffered_sem == NULL) goto err;
+    vPortCPUInitializeMutex(&rb->mux);
+    return (RingbufHandle_t)rb;
+
+err:
+    //Some error has happened. Free/destroy all allocated things and return NULL.
+    if (rb) {
+        free(rb->data);
+        if (rb->free_space_sem) vSemaphoreDelete(rb->free_space_sem);
+        if (rb->items_buffered_sem) vSemaphoreDelete(rb->items_buffered_sem);
+    }
+    free(rb);
+    return NULL;
+}
+
+void vRingbufferDelete(RingbufHandle_t ringbuf) {
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    if (rb) {
+        free(rb->data);
+        if (rb->free_space_sem) vSemaphoreDelete(rb->free_space_sem);
+        if (rb->items_buffered_sem) vSemaphoreDelete(rb->items_buffered_sem);
+    }
+    free(rb);
+}
+
+size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    //In both cases, we return 4 bytes less than what we actually can have. If the ringbuffer is
+    //indeed entirely filled, read_ptr==free_ptr, which throws off the free space calculation.
+    if (rb->flags & flag_allowsplit) {
+        //Worst case, we need to split an item into two, which means two headers of overhead.
+        return rb->size-(sizeof(buf_entry_hdr_t)*2)-4;
+    } else {
+        //Worst case, we have the write ptr in such a position that we are lacking four bytes of free
+        //memory to put an item into the rest of the memory. If this happens, we have to dummy-fill
+        //(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill
+        //with the real item. (item size being header+data)
+        return (rb->size/2)-sizeof(buf_entry_hdr_t)-4;
+    }
+}
+
+BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    size_t needed_size=dataSize+sizeof(buf_entry_hdr_t);
+    BaseType_t done=pdFALSE;
+    portTickType ticks_end=xTaskGetTickCount() + ticks_to_wait;
+
+    configASSERT(rb);
+
+    if (dataSize > xRingbufferGetMaxItemSize(ringbuf)) {
+        //Data will never ever fit in the queue.
+        return pdFALSE;
+    }
+
+    while (!done) {
+        //Check if there is enough room in the buffer. If not, wait until there is.
+        do {
+            if (ringbufferFreeMem(rb) < needed_size) {
+                //Data does not fit yet. Wait until the free_space_sem is given, then re-evaluate.
+
+                BaseType_t r = xSemaphoreTake(rb->free_space_sem, ticks_to_wait);
+                if (r == pdFALSE) {
+                    //Timeout.
+                    return pdFALSE;
+                }
+                //Adjust ticks_to_wait; we may have waited less than that and in the case the free memory still is not enough,
+                //we will need to wait some more.
+                ticks_to_wait = ticks_end - xTaskGetTickCount();
+            }
+        } while (ringbufferFreeMem(rb) < needed_size && ticks_to_wait>=0);
+        
+        //Lock the mux in order to make sure no one else is messing with the ringbuffer and do the copy.
+        portENTER_CRITICAL(&rb->mux);
+        //Another thread may have been able to sneak its write first. Check again now we locked the ringbuff, and retry
+        //everything if this is the case. Otherwise, we can write and are done.
+        done=copyItemToRingbuf(rb, data, dataSize);
+        portEXIT_CRITICAL(&rb->mux);
+    }
+    xSemaphoreGive(rb->items_buffered_sem);
+    return pdTRUE;
+}
+
+
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t dataSize, BaseType_t *higher_prio_task_awoken) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    BaseType_t write_succeeded;
+    configASSERT(rb);
+    size_t needed_size=dataSize+sizeof(buf_entry_hdr_t);
+    portENTER_CRITICAL_ISR(&rb->mux);
+    if (needed_size>ringbufferFreeMem(rb)) {
+        //Does not fit in the remaining space in the ringbuffer.
+        write_succeeded=pdFALSE;
+    } else {
+        copyItemToRingbuf(rb, data, dataSize);
+        write_succeeded=pdTRUE;
+    }
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    if (write_succeeded) {
+        xSemaphoreGiveFromISR(rb->items_buffered_sem, higher_prio_task_awoken);
+    }
+    return write_succeeded;
+}
+
+
+void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    uint8_t *itemData;
+    BaseType_t done=pdFALSE;
+    configASSERT(rb);
+    while(!done) {
+        //See if there's any data available. If not, wait until there is.
+        while (rb->read_ptr == rb->write_ptr) {
+            BaseType_t r=xSemaphoreTake(rb->items_buffered_sem, ticks_to_wait);
+            if (r == pdFALSE) {
+                //Timeout.
+                return NULL;
+            }
+        }
+        //Okay, we seem to have data in the buffer. Grab the mux and copy it out if it's still there.
+        portENTER_CRITICAL(&rb->mux);
+        itemData=getItemFromRingbuf(rb, item_size);
+        portEXIT_CRITICAL(&rb->mux);
+        if (itemData) {
+            //We managed to get an item.
+            done=pdTRUE;
+        }
+    }
+    return (void*)itemData;
+}
+
+
+void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    uint8_t *itemData;
+    configASSERT(rb);
+    portENTER_CRITICAL_ISR(&rb->mux);
+    itemData=getItemFromRingbuf(rb, item_size);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    return (void*)itemData;
+}
+
+
+void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    portENTER_CRITICAL_ISR(&rb->mux);
+    returnItemToRingbuf(rb, item);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    xSemaphoreGive(rb->free_space_sem);
+}
+
+
+void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_t *higher_prio_task_awoken) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    portENTER_CRITICAL_ISR(&rb->mux);
+    returnItemToRingbuf(rb, item);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    xSemaphoreGiveFromISR(rb->free_space_sem, higher_prio_task_awoken);
+}
+
+
+BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueAddToSet(rb->items_buffered_sem, xQueueSet);
+}
+
+
+BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueAddToSet(rb->free_space_sem, xQueueSet);
+}
+
+
+BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueRemoveFromSet(rb->items_buffered_sem, xQueueSet);
+}
+
+BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueRemoveFromSet(rb->free_space_sem, xQueueSet);
+}
+

+ 33 - 28
components/freertos/tasks.c

@@ -129,6 +129,9 @@ functions but without including stdio.h here. */
 					} while(0)
 #endif
 
+
+
+
 /* Value that can be assigned to the eNotifyState member of the TCB. */
 typedef enum
 {
@@ -157,7 +160,7 @@ typedef struct tskTaskControlBlock
 	StackType_t			*pxStack;			/*< Points to the start of the stack. */
 	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 	BaseType_t			xCoreID;			/*< Core this task is pinned to */
-
+											/* If this moves around (other than pcTaskName size changes), please change the define in xtensa_vectors.S as well. */
 	#if ( portSTACK_GROWTH > 0 )
 		StackType_t		*pxEndOfStack;		/*< Points to the end of the stack on architectures where the stack grows up from low memory. */
 	#endif
@@ -275,9 +278,7 @@ when the scheduler is unsuspended.  The pending ready list itself can only be
 accessed from a critical section. */
 PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended[ portNUM_PROCESSORS ]	= { ( UBaseType_t ) pdFALSE };
 
-/* Muxes used in the task code */
-PRIVILEGED_DATA static portBASE_TYPE xMutexesInitialised = pdFALSE;
-/* For now, we use just one mux for all the critical sections. ToDo: give evrything a bit more granularity;
+/* For now, we use just one mux for all the critical sections. ToDo: give everything a bit more granularity;
   that could improve performance by not needlessly spinning in spinlocks for unrelated resources. */
 PRIVILEGED_DATA static portMUX_TYPE xTaskQueueMutex = portMUX_INITIALIZER_UNLOCKED;
 PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCKED;
@@ -577,15 +578,6 @@ static void prvResetNextTaskUnblockTime( void );
 
 #endif
 
-/*-----------------------------------------------------------*/
-
-
-static void vTaskInitializeLocalMuxes( void )
-{
-	vPortCPUInitializeMutex(&xTaskQueueMutex);
-	vPortCPUInitializeMutex(&xTickCountMutex);
-	xMutexesInitialised = pdTRUE;
-}
 
 /*-----------------------------------------------------------*/
 
@@ -595,10 +587,6 @@ BaseType_t xReturn;
 TCB_t * pxNewTCB;
 StackType_t *pxTopOfStack;
 BaseType_t i;
-	
-	/* Initialize mutexes, if they're not already initialized. */
-	if (xMutexesInitialised == pdFALSE) vTaskInitializeLocalMuxes();
-	
 	configASSERT( pxTaskCode );
 	configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
 	configASSERT( (xCoreID>=0 && xCoreID<portNUM_PROCESSORS) || (xCoreID==tskNO_AFFINITY) );
@@ -873,7 +861,7 @@ BaseType_t i;
 	TickType_t xTimeToWake;
 	BaseType_t xAlreadyYielded=pdFALSE, xShouldDelay = pdFALSE;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		configASSERT( pxPreviousWakeTime );
 		configASSERT( ( xTimeIncrement > 0U ) );
 		configASSERT( uxSchedulerSuspended[ xPortGetCoreID() ] == 0 );
@@ -1043,7 +1031,7 @@ BaseType_t i;
 	List_t *pxStateList;
 	const TCB_t * const pxTCB = ( TCB_t * ) xTask;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		configASSERT( pxTCB );
 
 		if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
@@ -1113,7 +1101,7 @@ BaseType_t i;
 	TCB_t *pxTCB;
 	UBaseType_t uxReturn;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 			/* If null is passed in here then we are changing the
@@ -1321,7 +1309,7 @@ BaseType_t i;
 	{
 	TCB_t *pxTCB;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 			/* If null is passed in here then it is the running task that is
@@ -1462,7 +1450,7 @@ BaseType_t i;
 	{
 	TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		/* It does not make sense to resume the calling task. */
 		configASSERT( xTaskToResume );
 
@@ -1725,10 +1713,6 @@ BaseType_t xAlreadyYielded = pdFALSE;
 	scheduler has been resumed it is safe to move all the pending ready
 	tasks from this list into their appropriate ready list. */
 
-	//This uses a mux, but can be called before tasks are scheduled. Make sure muxes are inited.
-	/* Initialize mutexes, if they're not already initialized. */
-	if (xMutexesInitialised == pdFALSE) vTaskInitializeLocalMuxes();
-
 	taskENTER_CRITICAL(&xTaskQueueMutex);
 	{
 		--uxSchedulerSuspended[ xPortGetCoreID() ];
@@ -1868,7 +1852,7 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
 	{
 	UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		vTaskSuspendAll(); //WARNING: This only suspends one CPU. ToDo: suspend others as well. Mux using taskQueueMutex maybe?
 		{
 			/* Is there a space in the array for each task in the system? */
@@ -3154,7 +3138,7 @@ UBaseType_t x;
 	{
 	TCB_t *pxTCB;
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		/* If null is passed in here then we are deleting ourselves. */
 		pxTCB = prvGetTCBFromHandle( xTaskToModify );
 
@@ -3355,6 +3339,18 @@ TCB_t *pxNewTCB;
 }
 /*-----------------------------------------------------------*/
 
+BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
+{
+	TCB_t *pxTCB;
+	UBaseType_t uxReturn;
+
+	pxTCB = prvGetTCBFromHandle( xTask );
+
+	return pxTCB->xCoreID;
+}
+/*-----------------------------------------------------------*/
+
+
 #if ( configUSE_TRACE_FACILITY == 1 )
 
 	static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
@@ -3362,6 +3358,7 @@ TCB_t *pxNewTCB;
 	volatile TCB_t *pxNextTCB, *pxFirstTCB;
 	UBaseType_t uxTask = 0;
 
+		UNTESTED_FUNCTION();
 		if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
 		{
 			listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
@@ -3468,6 +3465,7 @@ TCB_t *pxNewTCB;
 	uint8_t *pucEndOfStack;
 	UBaseType_t uxReturn;
 
+		UNTESTED_FUNCTION();
 		pxTCB = prvGetTCBFromHandle( xTask );
 
 		#if portSTACK_GROWTH < 0
@@ -3899,6 +3897,7 @@ scheduler will re-enable the interrupts instead. */
 	TaskStatus_t *pxTaskStatusArray;
 	volatile UBaseType_t uxArraySize, x;
 	char cStatus;
+		UNTESTED_FUNCTION();
 
 		/*
 		 * PLEASE NOTE:
@@ -3992,6 +3991,7 @@ scheduler will re-enable the interrupts instead. */
 	volatile UBaseType_t uxArraySize, x;
 	uint32_t ulTotalTime, ulStatsAsPercentage;
 
+		UNTESTED_FUNCTION();
 		#if( configUSE_TRACE_FACILITY != 1 )
 		{
 			#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
@@ -4149,6 +4149,7 @@ TickType_t uxReturn;
 	TickType_t xTimeToWake;
 	uint32_t ulReturn;
 
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 			/* Only block if the notification count is not already non-zero. */
@@ -4259,6 +4260,7 @@ TickType_t uxReturn;
 	TickType_t xTimeToWake;
 	BaseType_t xReturn;
 
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 			/* Only block if a notification is not already pending. */
@@ -4381,6 +4383,7 @@ TickType_t uxReturn;
 	eNotifyValue eOriginalNotifyState;
 	BaseType_t xReturn = pdPASS;
 
+		UNTESTED_FUNCTION();
 		configASSERT( xTaskToNotify );
 		pxTCB = ( TCB_t * ) xTaskToNotify;
 
@@ -4465,6 +4468,7 @@ TickType_t uxReturn;
 	eNotifyValue eOriginalNotifyState;
 	BaseType_t xReturn = pdPASS;
 
+		UNTESTED_FUNCTION();
 		configASSERT( xTaskToNotify );
 
 		pxTCB = ( TCB_t * ) xTaskToNotify;
@@ -4558,6 +4562,7 @@ TickType_t uxReturn;
 	TCB_t * pxTCB;
 	eNotifyValue eOriginalNotifyState;
 
+		UNTESTED_FUNCTION();
 		configASSERT( xTaskToNotify );
 
 

+ 20 - 0
components/freertos/xtensa_vectors.S

@@ -92,6 +92,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #include "xtensa_rtos.h"
 
+/*
+  Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used.
+  Please change this when the tcb structure is changed
+*/
+#define TASKTCB_XCOREID_OFFSET (0x3C+configMAX_TASK_NAME_LEN+3)&~3
+.extern pxCurrentTCB
 
 /* Enable stack backtrace across exception/interrupt - see below */
 #define XT_DEBUG_BACKTRACE    0
@@ -892,6 +898,20 @@ _xt_coproc_exc:
     addx4   a0, a5, a0                      /* a0 = &_xt_coproc_mask[n] */
     l32i    a0, a0, 0                       /* a0 = (n << 16) | (1 << n) */
 
+    /* TODO: Remove this as soon as coprocessor state moving works across cores - JD */
+    /* FPU operations are incompatible with non-pinned tasks. If we have a FPU operation
+       here, to keep the entire thing from crashing, it's better to pin the task to whatever
+       core we're running on now. */
+    movi    a2, pxCurrentTCB
+    getcoreid a3
+    slli    a3,  a3, 2
+    add     a2,  a2, a3
+    l32i    a2, a2, 0                       /* a2 = start of pxCurrentTCB[cpuid] */
+    addi    a2, a2, TASKTCB_XCOREID_OFFSET  /* offset to xCoreID in tcb struct */
+    getcoreid a3
+    s32i    a3, a2, 0                       /* store current cpuid */
+
+	/* Grab correct xt_coproc_owner_sa for this core */
 	getcoreid a2
 	movi    a3, XCHAL_CP_MAX << 2
 	mull    a2, a2, a3

+ 7 - 7
components/log/Kconfig

@@ -28,13 +28,13 @@ config LOG_DEFAULT_LEVEL_VERBOSE
 endchoice
 
 config LOG_DEFAULT_LEVEL
-	int
-	default 0 if LOG_DEFAULT_LEVEL_NONE
-	default 1 if LOG_DEFAULT_LEVEL_ERROR
-	default 2 if LOG_DEFAULT_LEVEL_WARN
-	default 3 if LOG_DEFAULT_LEVEL_INFO
-	default 4 if LOG_DEFAULT_LEVEL_DEBUG
-	default 5 if LOG_DEFAULT_LEVEL_VERBOSE
+    int
+    default 0 if LOG_DEFAULT_LEVEL_NONE
+    default 1 if LOG_DEFAULT_LEVEL_ERROR
+    default 2 if LOG_DEFAULT_LEVEL_WARN
+    default 3 if LOG_DEFAULT_LEVEL_INFO
+    default 4 if LOG_DEFAULT_LEVEL_DEBUG
+    default 5 if LOG_DEFAULT_LEVEL_VERBOSE
 
 config LOG_COLORS
    bool "Use ANSI terminal colors in log output"

+ 17 - 17
components/lwip/Kconfig

@@ -1,27 +1,27 @@
 menu "LWIP"
 
 config LWIP_MAX_SOCKETS
-	int "Max number of open sockets"
-	range 1 16
-	default 4
-	help
-		Sockets take up a certain amount of memory, and allowing fewer
-		sockets to be open at the same time conserves memory. Specify
-		the maximum amount of sockets here.
+    int "Max number of open sockets"
+    range 1 16
+    default 4
+    help
+        Sockets take up a certain amount of memory, and allowing fewer
+        sockets to be open at the same time conserves memory. Specify
+        the maximum amount of sockets here.
 
 config LWIP_THREAD_LOCAL_STORAGE_INDEX
-	int "Index for thread-local-storage pointer for lwip"
-	default 0
-	help
-		Specify the thread-local-storage-pointer index for lwip
-		use.
+    int "Index for thread-local-storage pointer for lwip"
+    default 0
+    help
+        Specify the thread-local-storage-pointer index for lwip
+        use.
 
 config LWIP_SO_REUSE
-	bool "Enable SO_REUSEADDR option"
-	default 0
-	help
-		Enabling this option allows binding to a port which remains in 
-		TIME_WAIT.
+    bool "Enable SO_REUSEADDR option"
+    default 0
+    help
+        Enabling this option allows binding to a port which remains in
+        TIME_WAIT.
 
 endmenu
 

+ 1 - 1
components/lwip/component.mk

@@ -6,6 +6,6 @@ COMPONENT_ADD_INCLUDEDIRS := include/lwip include/lwip/port include/lwip/posix
 
 COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/freertos port/netif port
 
-CFLAGS += -Wno-error=address -Waddress
+CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
 
 include $(IDF_PATH)/make/component_common.mk

+ 11 - 1
components/lwip/include/lwip/port/arch/sys_arch.h

@@ -38,6 +38,11 @@
 #include "freertos/queue.h"
 #include "freertos/semphr.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 typedef xSemaphoreHandle sys_sem_t;
 typedef xSemaphoreHandle sys_mutex_t;
 typedef xTaskHandle sys_thread_t;
@@ -67,6 +72,11 @@ uint32_t system_get_time(void);
 void sys_delay_ms(uint32_t ms);
 sys_sem_t* sys_thread_sem_init(void);
 void sys_thread_sem_deinit(void);
-sys_sem_t* sys_thread_sem_get(void);
+sys_sem_t* sys_thread_sem_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __SYS_ARCH_H__ */
 

+ 8 - 0
components/lwip/include/lwip/port/netif/wlanif.h

@@ -10,6 +10,10 @@
 
 #include "lwip/err.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 err_t wlanif_init(struct netif *netif);
 
 void wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb);
@@ -20,4 +24,8 @@ wifi_interface_t wifi_get_interface(void *dev);
 
 void netif_reg_addr_change_cb(void* cb);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*  _WLAN_LWIP_IF_H_ */

+ 37 - 0
components/mbedtls/Kconfig

@@ -0,0 +1,37 @@
+menu "mbedTLS"
+
+config MBEDTLS_SSL_MAX_CONTENT_LEN
+    int "TLS maximum message content length"
+    default 16384
+    range 512 16384
+    help
+        Maximum TLS message length (in bytes) supported by mbedTLS.
+        
+        16384 is the default and this value is required to comply
+        fully with TLS standards.
+        
+        However you can set a lower value in order to save RAM. This
+        is safe if the other end of the connection supports Maximum
+        Fragment Length Negotiation Extension (max_fragment_length,
+        see RFC6066) or you know for certain that it will never send a
+        message longer than a certain number of bytes.
+        
+        If the value is set too low, symptoms are a failed TLS
+        handshake or a return value of MBEDTLS_ERR_SSL_INVALID_RECORD
+        (-0x7200).
+
+config MBEDTLS_DEBUG
+   bool "Enable mbedTLS debugging"
+   default "no"
+   help
+       Enable mbedTLS debugging functions.
+       
+       If this option is enabled, use the mbedtls_debug_set_threshold()
+       and mbedtls_ssl_conf_dbg() functions to obtain debugging output
+       from mbedTLS.
+       
+       Note thatm mbedTLS debugging is not related to the ESP logging
+       functionality. See the "https_request_main" example for a
+       sample function which connects the two together.
+
+endmenu

+ 5 - 1
components/mbedtls/port/include/mbedtls/esp_config.h

@@ -27,6 +27,8 @@
 #ifndef MBEDTLS_CONFIG_H
 #define MBEDTLS_CONFIG_H
 
+#include "sdkconfig.h"
+
 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
 #define _CRT_SECURE_NO_DEPRECATE 1
 #endif
@@ -1659,7 +1661,9 @@
  *
  * This module provides debugging functions.
  */
+#if CONFIG_MBEDTLS_DEBUG
 #define MBEDTLS_DEBUG_C
+#endif
 
 /**
  * \def MBEDTLS_DES_C
@@ -2481,7 +2485,7 @@
 
 /* SSL options */
 
-#define MBEDTLS_SSL_MAX_CONTENT_LEN             5120 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
+#define MBEDTLS_SSL_MAX_CONTENT_LEN             CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
 //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME     86400 /**< Lifetime of session tickets (if enabled) */
 //#define MBEDTLS_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
 //#define MBEDTLS_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */

+ 23 - 0
components/nghttp/COPYING

@@ -0,0 +1,23 @@
+The MIT License
+
+Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
+Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
+
+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.

+ 1 - 0
components/nghttp/LICENSE

@@ -0,0 +1 @@
+See COPYING

+ 17 - 0
components/nghttp/Makefile

@@ -0,0 +1,17 @@
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, 
+# this will take the sources in this directory, compile them and link them into 
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+COMPONENT_ADD_INCLUDEDIRS := port/include include
+
+COMPONENT_SRCDIRS := library port
+
+#EXTRA_CFLAGS += -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"'
+
+EXTRA_CFLAGS := -Wno-error=address -Waddress -DHAVE_CONFIG_H
+
+include $(IDF_PATH)/make/component.mk

+ 4 - 0
components/nghttp/Makefile.projbuild

@@ -0,0 +1,4 @@
+# Anyone compiling mbedTLS code needs the name of the
+# alternative config file
+
+CFLAGS += -DHAVE_CONFIG_H

+ 1 - 0
components/nghttp/README

@@ -0,0 +1 @@
+See README.rst

+ 9 - 0
components/nghttp/component.mk

@@ -0,0 +1,9 @@
+#
+# Component Makefile
+#
+
+COMPONENT_ADD_INCLUDEDIRS := port/include include
+
+COMPONENT_SRCDIRS := library port
+
+include $(IDF_PATH)/make/component_common.mk

+ 5030 - 0
components/nghttp/include/nghttp2/nghttp2.h

@@ -0,0 +1,5030 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013, 2014 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.
+ */
+#ifndef NGHTTP2_H
+#define NGHTTP2_H
+
+/* Define WIN32 when build target is Win32 API (borrowed from
+   libcurl) */
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#define WIN32
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+/* MSVC < 2013 does not have inttypes.h because it is not C99
+   compliant.  See compiler macros and version number in
+   https://sourceforge.net/p/predef/wiki/Compilers/ */
+#include <stdint.h>
+#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
+#include <inttypes.h>
+#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
+#include <sys/types.h>
+
+#include <nghttp2/nghttp2ver.h>
+
+#ifdef NGHTTP2_STATICLIB
+#define NGHTTP2_EXTERN
+#elif defined(WIN32)
+#ifdef BUILDING_NGHTTP2
+#define NGHTTP2_EXTERN __declspec(dllexport)
+#else /* !BUILDING_NGHTTP2 */
+#define NGHTTP2_EXTERN __declspec(dllimport)
+#endif /* !BUILDING_NGHTTP2 */
+#else  /* !defined(WIN32) */
+#ifdef BUILDING_NGHTTP2
+#define NGHTTP2_EXTERN __attribute__((visibility("default")))
+#else /* !BUILDING_NGHTTP2 */
+#define NGHTTP2_EXTERN
+#endif /* !BUILDING_NGHTTP2 */
+#endif /* !defined(WIN32) */
+
+/**
+ * @macro
+ *
+ * The protocol version identification string of this library
+ * supports.  This identifier is used if HTTP/2 is used over TLS.
+ */
+#define NGHTTP2_PROTO_VERSION_ID "h2"
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_PROTO_VERSION_ID`.
+ */
+#define NGHTTP2_PROTO_VERSION_ID_LEN 2
+
+/**
+ * @macro
+ *
+ * The serialized form of ALPN protocol identifier this library
+ * supports.  Notice that first byte is the length of following
+ * protocol identifier.  This is the same wire format of `TLS ALPN
+ * extension <https://tools.ietf.org/html/rfc7301>`_.  This is useful
+ * to process incoming ALPN tokens in wire format.
+ */
+#define NGHTTP2_PROTO_ALPN "\x2h2"
+
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_PROTO_ALPN`.
+ */
+#define NGHTTP2_PROTO_ALPN_LEN (sizeof(NGHTTP2_PROTO_ALPN) - 1)
+
+/**
+ * @macro
+ *
+ * The protocol version identification string of this library
+ * supports.  This identifier is used if HTTP/2 is used over cleartext
+ * TCP.
+ */
+#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c"
+
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_CLEARTEXT_PROTO_VERSION_ID`.
+ */
+#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 3
+
+struct nghttp2_session;
+/**
+ * @struct
+ *
+ * The primary structure to hold the resources needed for a HTTP/2
+ * session.  The details of this structure are intentionally hidden
+ * from the public API.
+ */
+typedef struct nghttp2_session nghttp2_session;
+
+/**
+ * @macro
+ *
+ * The age of :type:`nghttp2_info`
+ */
+#define NGHTTP2_VERSION_AGE 1
+
+/**
+ * @struct
+ *
+ * This struct is what `nghttp2_version()` returns.  It holds
+ * information about the particular nghttp2 version.
+ */
+typedef struct {
+  /**
+   * Age of this struct.  This instance of nghttp2 sets it to
+   * :macro:`NGHTTP2_VERSION_AGE` but a future version may bump it and
+   * add more struct fields at the bottom
+   */
+  int age;
+  /**
+   * the :macro:`NGHTTP2_VERSION_NUM` number (since age ==1)
+   */
+  int version_num;
+  /**
+   * points to the :macro:`NGHTTP2_VERSION` string (since age ==1)
+   */
+  const char *version_str;
+  /**
+   * points to the :macro:`NGHTTP2_PROTO_VERSION_ID` string this
+   * instance implements (since age ==1)
+   */
+  const char *proto_str;
+  /* -------- the above fields all exist when age == 1 */
+} nghttp2_info;
+
+/**
+ * @macro
+ *
+ * The default weight of stream dependency.
+ */
+#define NGHTTP2_DEFAULT_WEIGHT 16
+
+/**
+ * @macro
+ *
+ * The maximum weight of stream dependency.
+ */
+#define NGHTTP2_MAX_WEIGHT 256
+
+/**
+ * @macro
+ *
+ * The minimum weight of stream dependency.
+ */
+#define NGHTTP2_MIN_WEIGHT 1
+
+/**
+ * @macro
+ *
+ * The maximum window size
+ */
+#define NGHTTP2_MAX_WINDOW_SIZE ((int32_t)((1U << 31) - 1))
+
+/**
+ * @macro
+ *
+ * The initial window size for stream level flow control.
+ */
+#define NGHTTP2_INITIAL_WINDOW_SIZE ((1 << 16) - 1)
+/**
+ * @macro
+ *
+ * The initial window size for connection level flow control.
+ */
+#define NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ((1 << 16) - 1)
+
+/**
+ * @macro
+ *
+ * The default header table size.
+ */
+#define NGHTTP2_DEFAULT_HEADER_TABLE_SIZE (1 << 12)
+
+/**
+ * @macro
+ *
+ * The client magic string, which is the first 24 bytes byte string of
+ * client connection preface.
+ */
+#define NGHTTP2_CLIENT_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_CLIENT_MAGIC`.
+ */
+#define NGHTTP2_CLIENT_MAGIC_LEN 24
+
+/**
+ * @enum
+ *
+ * Error codes used in this library.  The code range is [-999, -500],
+ * inclusive. The following values are defined:
+ */
+typedef enum {
+  /**
+   * Invalid argument passed.
+   */
+  NGHTTP2_ERR_INVALID_ARGUMENT = -501,
+  /**
+   * Out of buffer space.
+   */
+  NGHTTP2_ERR_BUFFER_ERROR = -502,
+  /**
+   * The specified protocol version is not supported.
+   */
+  NGHTTP2_ERR_UNSUPPORTED_VERSION = -503,
+  /**
+   * Used as a return value from :type:`nghttp2_send_callback`,
+   * :type:`nghttp2_recv_callback` and
+   * :type:`nghttp2_send_data_callback` to indicate that the operation
+   * would block.
+   */
+  NGHTTP2_ERR_WOULDBLOCK = -504,
+  /**
+   * General protocol error
+   */
+  NGHTTP2_ERR_PROTO = -505,
+  /**
+   * The frame is invalid.
+   */
+  NGHTTP2_ERR_INVALID_FRAME = -506,
+  /**
+   * The peer performed a shutdown on the connection.
+   */
+  NGHTTP2_ERR_EOF = -507,
+  /**
+   * Used as a return value from
+   * :func:`nghttp2_data_source_read_callback` to indicate that data
+   * transfer is postponed.  See
+   * :func:`nghttp2_data_source_read_callback` for details.
+   */
+  NGHTTP2_ERR_DEFERRED = -508,
+  /**
+   * Stream ID has reached the maximum value.  Therefore no stream ID
+   * is available.
+   */
+  NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE = -509,
+  /**
+   * The stream is already closed; or the stream ID is invalid.
+   */
+  NGHTTP2_ERR_STREAM_CLOSED = -510,
+  /**
+   * RST_STREAM has been added to the outbound queue.  The stream is
+   * in closing state.
+   */
+  NGHTTP2_ERR_STREAM_CLOSING = -511,
+  /**
+   * The transmission is not allowed for this stream (e.g., a frame
+   * with END_STREAM flag set has already sent).
+   */
+  NGHTTP2_ERR_STREAM_SHUT_WR = -512,
+  /**
+   * The stream ID is invalid.
+   */
+  NGHTTP2_ERR_INVALID_STREAM_ID = -513,
+  /**
+   * The state of the stream is not valid (e.g., DATA cannot be sent
+   * to the stream if response HEADERS has not been sent).
+   */
+  NGHTTP2_ERR_INVALID_STREAM_STATE = -514,
+  /**
+   * Another DATA frame has already been deferred.
+   */
+  NGHTTP2_ERR_DEFERRED_DATA_EXIST = -515,
+  /**
+   * Starting new stream is not allowed (e.g., GOAWAY has been sent
+   * and/or received).
+   */
+  NGHTTP2_ERR_START_STREAM_NOT_ALLOWED = -516,
+  /**
+   * GOAWAY has already been sent.
+   */
+  NGHTTP2_ERR_GOAWAY_ALREADY_SENT = -517,
+  /**
+   * The received frame contains the invalid header block (e.g., There
+   * are duplicate header names; or the header names are not encoded
+   * in US-ASCII character set and not lower cased; or the header name
+   * is zero-length string; or the header value contains multiple
+   * in-sequence NUL bytes).
+   */
+  NGHTTP2_ERR_INVALID_HEADER_BLOCK = -518,
+  /**
+   * Indicates that the context is not suitable to perform the
+   * requested operation.
+   */
+  NGHTTP2_ERR_INVALID_STATE = -519,
+  /**
+   * The user callback function failed due to the temporal error.
+   */
+  NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE = -521,
+  /**
+   * The length of the frame is invalid, either too large or too small.
+   */
+  NGHTTP2_ERR_FRAME_SIZE_ERROR = -522,
+  /**
+   * Header block inflate/deflate error.
+   */
+  NGHTTP2_ERR_HEADER_COMP = -523,
+  /**
+   * Flow control error
+   */
+  NGHTTP2_ERR_FLOW_CONTROL = -524,
+  /**
+   * Insufficient buffer size given to function.
+   */
+  NGHTTP2_ERR_INSUFF_BUFSIZE = -525,
+  /**
+   * Callback was paused by the application
+   */
+  NGHTTP2_ERR_PAUSE = -526,
+  /**
+   * There are too many in-flight SETTING frame and no more
+   * transmission of SETTINGS is allowed.
+   */
+  NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527,
+  /**
+   * The server push is disabled.
+   */
+  NGHTTP2_ERR_PUSH_DISABLED = -528,
+  /**
+   * DATA or HEADERS frame for a given stream has been already
+   * submitted and has not been fully processed yet.  Application
+   * should wait for the transmission of the previously submitted
+   * frame before submitting another.
+   */
+  NGHTTP2_ERR_DATA_EXIST = -529,
+  /**
+   * The current session is closing due to a connection error or
+   * `nghttp2_session_terminate_session()` is called.
+   */
+  NGHTTP2_ERR_SESSION_CLOSING = -530,
+  /**
+   * Invalid HTTP header field was received and stream is going to be
+   * closed.
+   */
+  NGHTTP2_ERR_HTTP_HEADER = -531,
+  /**
+   * Violation in HTTP messaging rule.
+   */
+  NGHTTP2_ERR_HTTP_MESSAGING = -532,
+  /**
+   * Stream was refused.
+   */
+  NGHTTP2_ERR_REFUSED_STREAM = -533,
+  /**
+   * Unexpected internal error, but recovered.
+   */
+  NGHTTP2_ERR_INTERNAL = -534,
+  /**
+   * Indicates that a processing was canceled.
+   */
+  NGHTTP2_ERR_CANCEL = -535,
+  /**
+   * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
+   * under unexpected condition and processing was terminated (e.g.,
+   * out of memory).  If application receives this error code, it must
+   * stop using that :type:`nghttp2_session` object and only allowed
+   * operation for that object is deallocate it using
+   * `nghttp2_session_del()`.
+   */
+  NGHTTP2_ERR_FATAL = -900,
+  /**
+   * Out of memory.  This is a fatal error.
+   */
+  NGHTTP2_ERR_NOMEM = -901,
+  /**
+   * The user callback function failed.  This is a fatal error.
+   */
+  NGHTTP2_ERR_CALLBACK_FAILURE = -902,
+  /**
+   * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was
+   * received and further processing is not possible.
+   */
+  NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903,
+  /**
+   * Possible flooding by peer was detected in this HTTP/2 session.
+   * Flooding is measured by how many PING and SETTINGS frames with
+   * ACK flag set are queued for transmission.  These frames are
+   * response for the peer initiated frames, and peer can cause memory
+   * exhaustion on server side to send these frames forever and does
+   * not read network.
+   */
+  NGHTTP2_ERR_FLOODED = -904
+} nghttp2_error;
+
+/**
+ * @struct
+ *
+ * The object representing single contiguous buffer.
+ */
+typedef struct {
+  /**
+   * The pointer to the buffer.
+   */
+  uint8_t *base;
+  /**
+   * The length of the buffer.
+   */
+  size_t len;
+} nghttp2_vec;
+
+struct nghttp2_rcbuf;
+
+/**
+ * @struct
+ *
+ * The object representing reference counted buffer.  The details of
+ * this structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_rcbuf nghttp2_rcbuf;
+
+/**
+ * @function
+ *
+ * Increments the reference count of |rcbuf| by 1.
+ */
+NGHTTP2_EXTERN void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf);
+
+/**
+ * @function
+ *
+ * Decrements the reference count of |rcbuf| by 1.  If the reference
+ * count becomes zero, the object pointed by |rcbuf| will be freed.
+ * In this case, application must not use |rcbuf| again.
+ */
+NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf);
+
+/**
+ * @function
+ *
+ * Returns the underlying buffer managed by |rcbuf|.
+ */
+NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf);
+
+/**
+ * @enum
+ *
+ * The flags for header field name/value pair.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_NV_FLAG_NONE = 0,
+  /**
+   * Indicates that this name/value pair must not be indexed ("Literal
+   * Header Field never Indexed" representation must be used in HPACK
+   * encoding).  Other implementation calls this bit as "sensitive".
+   */
+  NGHTTP2_NV_FLAG_NO_INDEX = 0x01,
+  /**
+   * This flag is set solely by application.  If this flag is set, the
+   * library does not make a copy of header field name.  This could
+   * improve performance.
+   */
+  NGHTTP2_NV_FLAG_NO_COPY_NAME = 0x02,
+  /**
+   * This flag is set solely by application.  If this flag is set, the
+   * library does not make a copy of header field value.  This could
+   * improve performance.
+   */
+  NGHTTP2_NV_FLAG_NO_COPY_VALUE = 0x04
+} nghttp2_nv_flag;
+
+/**
+ * @struct
+ *
+ * The name/value pair, which mainly used to represent header fields.
+ */
+typedef struct {
+  /**
+   * The |name| byte string.  If this struct is presented from library
+   * (e.g., :type:`nghttp2_on_frame_recv_callback`), |name| is
+   * guaranteed to be NULL-terminated.  For some callbacks
+   * (:type:`nghttp2_before_frame_send_callback`,
+   * :type:`nghttp2_on_frame_send_callback`, and
+   * :type:`nghttp2_on_frame_not_send_callback`), it may not be
+   * NULL-terminated if header field is passed from application with
+   * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`).  When application
+   * is constructing this struct, |name| is not required to be
+   * NULL-terminated.
+   */
+  uint8_t *name;
+  /**
+   * The |value| byte string.  If this struct is presented from
+   * library (e.g., :type:`nghttp2_on_frame_recv_callback`), |value|
+   * is guaranteed to be NULL-terminated.  For some callbacks
+   * (:type:`nghttp2_before_frame_send_callback`,
+   * :type:`nghttp2_on_frame_send_callback`, and
+   * :type:`nghttp2_on_frame_not_send_callback`), it may not be
+   * NULL-terminated if header field is passed from application with
+   * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`).  When
+   * application is constructing this struct, |value| is not required
+   * to be NULL-terminated.
+   */
+  uint8_t *value;
+  /**
+   * The length of the |name|, excluding terminating NULL.
+   */
+  size_t namelen;
+  /**
+   * The length of the |value|, excluding terminating NULL.
+   */
+  size_t valuelen;
+  /**
+   * Bitwise OR of one or more of :type:`nghttp2_nv_flag`.
+   */
+  uint8_t flags;
+} nghttp2_nv;
+
+/**
+ * @enum
+ *
+ * The frame types in HTTP/2 specification.
+ */
+typedef enum {
+  /**
+   * The DATA frame.
+   */
+  NGHTTP2_DATA = 0,
+  /**
+   * The HEADERS frame.
+   */
+  NGHTTP2_HEADERS = 0x01,
+  /**
+   * The PRIORITY frame.
+   */
+  NGHTTP2_PRIORITY = 0x02,
+  /**
+   * The RST_STREAM frame.
+   */
+  NGHTTP2_RST_STREAM = 0x03,
+  /**
+   * The SETTINGS frame.
+   */
+  NGHTTP2_SETTINGS = 0x04,
+  /**
+   * The PUSH_PROMISE frame.
+   */
+  NGHTTP2_PUSH_PROMISE = 0x05,
+  /**
+   * The PING frame.
+   */
+  NGHTTP2_PING = 0x06,
+  /**
+   * The GOAWAY frame.
+   */
+  NGHTTP2_GOAWAY = 0x07,
+  /**
+   * The WINDOW_UPDATE frame.
+   */
+  NGHTTP2_WINDOW_UPDATE = 0x08,
+  /**
+   * The CONTINUATION frame.  This frame type won't be passed to any
+   * callbacks because the library processes this frame type and its
+   * preceding HEADERS/PUSH_PROMISE as a single frame.
+   */
+  NGHTTP2_CONTINUATION = 0x09,
+  /**
+   * The ALTSVC frame, which is defined in `RFC 7383
+   * <https://tools.ietf.org/html/rfc7838#section-4>`_.
+   */
+  NGHTTP2_ALTSVC = 0x0a
+} nghttp2_frame_type;
+
+/**
+ * @enum
+ *
+ * The flags for HTTP/2 frames.  This enum defines all flags for all
+ * frames.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_FLAG_NONE = 0,
+  /**
+   * The END_STREAM flag.
+   */
+  NGHTTP2_FLAG_END_STREAM = 0x01,
+  /**
+   * The END_HEADERS flag.
+   */
+  NGHTTP2_FLAG_END_HEADERS = 0x04,
+  /**
+   * The ACK flag.
+   */
+  NGHTTP2_FLAG_ACK = 0x01,
+  /**
+   * The PADDED flag.
+   */
+  NGHTTP2_FLAG_PADDED = 0x08,
+  /**
+   * The PRIORITY flag.
+   */
+  NGHTTP2_FLAG_PRIORITY = 0x20
+} nghttp2_flag;
+
+/**
+ * @enum
+ * The SETTINGS ID.
+ */
+typedef enum {
+  /**
+   * SETTINGS_HEADER_TABLE_SIZE
+   */
+  NGHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0x01,
+  /**
+   * SETTINGS_ENABLE_PUSH
+   */
+  NGHTTP2_SETTINGS_ENABLE_PUSH = 0x02,
+  /**
+   * SETTINGS_MAX_CONCURRENT_STREAMS
+   */
+  NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 0x03,
+  /**
+   * SETTINGS_INITIAL_WINDOW_SIZE
+   */
+  NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 0x04,
+  /**
+   * SETTINGS_MAX_FRAME_SIZE
+   */
+  NGHTTP2_SETTINGS_MAX_FRAME_SIZE = 0x05,
+  /**
+   * SETTINGS_MAX_HEADER_LIST_SIZE
+   */
+  NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06
+} nghttp2_settings_id;
+/* Note: If we add SETTINGS, update the capacity of
+   NGHTTP2_INBOUND_NUM_IV as well */
+
+/**
+ * @macro
+ *
+ * .. warning::
+ *
+ *   Deprecated.  The initial max concurrent streams is 0xffffffffu.
+ *
+ * Default maximum number of incoming concurrent streams.  Use
+ * `nghttp2_submit_settings()` with
+ * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
+ * maximum number of incoming concurrent streams.
+ *
+ * .. note::
+ *
+ *   The maximum number of outgoing concurrent streams is 100 by
+ *   default.
+ */
+#define NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
+
+/**
+ * @enum
+ * The status codes for the RST_STREAM and GOAWAY frames.
+ */
+typedef enum {
+  /**
+   * No errors.
+   */
+  NGHTTP2_NO_ERROR = 0x00,
+  /**
+   * PROTOCOL_ERROR
+   */
+  NGHTTP2_PROTOCOL_ERROR = 0x01,
+  /**
+   * INTERNAL_ERROR
+   */
+  NGHTTP2_INTERNAL_ERROR = 0x02,
+  /**
+   * FLOW_CONTROL_ERROR
+   */
+  NGHTTP2_FLOW_CONTROL_ERROR = 0x03,
+  /**
+   * SETTINGS_TIMEOUT
+   */
+  NGHTTP2_SETTINGS_TIMEOUT = 0x04,
+  /**
+   * STREAM_CLOSED
+   */
+  NGHTTP2_STREAM_CLOSED = 0x05,
+  /**
+   * FRAME_SIZE_ERROR
+   */
+  NGHTTP2_FRAME_SIZE_ERROR = 0x06,
+  /**
+   * REFUSED_STREAM
+   */
+  NGHTTP2_REFUSED_STREAM = 0x07,
+  /**
+   * CANCEL
+   */
+  NGHTTP2_CANCEL = 0x08,
+  /**
+   * COMPRESSION_ERROR
+   */
+  NGHTTP2_COMPRESSION_ERROR = 0x09,
+  /**
+   * CONNECT_ERROR
+   */
+  NGHTTP2_CONNECT_ERROR = 0x0a,
+  /**
+   * ENHANCE_YOUR_CALM
+   */
+  NGHTTP2_ENHANCE_YOUR_CALM = 0x0b,
+  /**
+   * INADEQUATE_SECURITY
+   */
+  NGHTTP2_INADEQUATE_SECURITY = 0x0c,
+  /**
+   * HTTP_1_1_REQUIRED
+   */
+  NGHTTP2_HTTP_1_1_REQUIRED = 0x0d
+} nghttp2_error_code;
+
+/**
+ * @struct
+ * The frame header.
+ */
+typedef struct {
+  /**
+   * The length field of this frame, excluding frame header.
+   */
+  size_t length;
+  /**
+   * The stream identifier (aka, stream ID)
+   */
+  int32_t stream_id;
+  /**
+   * The type of this frame.  See `nghttp2_frame_type`.
+   */
+  uint8_t type;
+  /**
+   * The flags.
+   */
+  uint8_t flags;
+  /**
+   * Reserved bit in frame header.  Currently, this is always set to 0
+   * and application should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_frame_hd;
+
+/**
+ * @union
+ *
+ * This union represents the some kind of data source passed to
+ * :type:`nghttp2_data_source_read_callback`.
+ */
+typedef union {
+  /**
+   * The integer field, suitable for a file descriptor.
+   */
+  int fd;
+  /**
+   * The pointer to an arbitrary object.
+   */
+  void *ptr;
+} nghttp2_data_source;
+
+/**
+ * @enum
+ *
+ * The flags used to set in |data_flags| output parameter in
+ * :type:`nghttp2_data_source_read_callback`.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_DATA_FLAG_NONE = 0,
+  /**
+   * Indicates EOF was sensed.
+   */
+  NGHTTP2_DATA_FLAG_EOF = 0x01,
+  /**
+   * Indicates that END_STREAM flag must not be set even if
+   * NGHTTP2_DATA_FLAG_EOF is set.  Usually this flag is used to send
+   * trailer fields with `nghttp2_submit_request()` or
+   * `nghttp2_submit_response()`.
+   */
+  NGHTTP2_DATA_FLAG_NO_END_STREAM = 0x02,
+  /**
+   * Indicates that application will send complete DATA frame in
+   * :type:`nghttp2_send_data_callback`.
+   */
+  NGHTTP2_DATA_FLAG_NO_COPY = 0x04
+} nghttp2_data_flag;
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the library wants to read data from
+ * the |source|.  The read data is sent in the stream |stream_id|.
+ * The implementation of this function must read at most |length|
+ * bytes of data from |source| (or possibly other places) and store
+ * them in |buf| and return number of data stored in |buf|.  If EOF is
+ * reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|.
+ *
+ * Sometime it is desirable to avoid copying data into |buf| and let
+ * application to send data directly.  To achieve this, set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly
+ * other flags, just like when we do copy), and return the number of
+ * bytes to send without copying data into |buf|.  The library, seeing
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
+ * :type:`nghttp2_send_data_callback`.  The application must send
+ * complete DATA frame in that callback.
+ *
+ * If this callback is set by `nghttp2_submit_request()`,
+ * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and
+ * `nghttp2_submit_data()` with flag parameter
+ * :enum:`NGHTTP2_FLAG_END_STREAM` set, and
+ * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA
+ * frame will have END_STREAM flag set.  Usually, this is expected
+ * behaviour and all are fine.  One exception is send trailer fields.
+ * You cannot send trailer fields after sending frame with END_STREAM
+ * set.  To avoid this problem, one can set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with
+ * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set
+ * END_STREAM in DATA frame.  Then application can use
+ * `nghttp2_submit_trailer()` to send trailer fields.
+ * `nghttp2_submit_trailer()` can be called inside this callback.
+ *
+ * If the application wants to postpone DATA frames (e.g.,
+ * asynchronous I/O, or reading data blocks for long time), it is
+ * achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
+ * any data in this invocation.  The library removes DATA frame from
+ * the outgoing queue temporarily.  To move back deferred DATA frame
+ * to outgoing queue, call `nghttp2_session_resume_data()`.  In case
+ * of error, there are 2 choices. Returning
+ * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
+ * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Returning
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
+ * failure.
+ */
+typedef ssize_t (*nghttp2_data_source_read_callback)(
+    nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,
+    uint32_t *data_flags, nghttp2_data_source *source, void *user_data);
+
+/**
+ * @struct
+ *
+ * This struct represents the data source and the way to read a chunk
+ * of data from it.
+ */
+typedef struct {
+  /**
+   * The data source.
+   */
+  nghttp2_data_source source;
+  /**
+   * The callback function to read a chunk of data from the |source|.
+   */
+  nghttp2_data_source_read_callback read_callback;
+} nghttp2_data_provider;
+
+/**
+ * @struct
+ *
+ * The DATA frame.  The received data is delivered via
+ * :type:`nghttp2_on_data_chunk_recv_callback`.
+ */
+typedef struct {
+  nghttp2_frame_hd hd;
+  /**
+   * The length of the padding in this frame.  This includes PAD_HIGH
+   * and PAD_LOW.
+   */
+  size_t padlen;
+} nghttp2_data;
+
+/**
+ * @enum
+ *
+ * The category of HEADERS, which indicates the role of the frame.  In
+ * HTTP/2 spec, request, response, push response and other arbitrary
+ * headers (e.g., trailer fields) are all called just HEADERS.  To
+ * give the application the role of incoming HEADERS frame, we define
+ * several categories.
+ */
+typedef enum {
+  /**
+   * The HEADERS frame is opening new stream, which is analogous to
+   * SYN_STREAM in SPDY.
+   */
+  NGHTTP2_HCAT_REQUEST = 0,
+  /**
+   * The HEADERS frame is the first response headers, which is
+   * analogous to SYN_REPLY in SPDY.
+   */
+  NGHTTP2_HCAT_RESPONSE = 1,
+  /**
+   * The HEADERS frame is the first headers sent against reserved
+   * stream.
+   */
+  NGHTTP2_HCAT_PUSH_RESPONSE = 2,
+  /**
+   * The HEADERS frame which does not apply for the above categories,
+   * which is analogous to HEADERS in SPDY.  If non-final response
+   * (e.g., status 1xx) is used, final response HEADERS frame will be
+   * categorized here.
+   */
+  NGHTTP2_HCAT_HEADERS = 3
+} nghttp2_headers_category;
+
+/**
+ * @struct
+ *
+ * The structure to specify stream dependency.
+ */
+typedef struct {
+  /**
+   * The stream ID of the stream to depend on.  Specifying 0 makes
+   * stream not depend any other stream.
+   */
+  int32_t stream_id;
+  /**
+   * The weight of this dependency.
+   */
+  int32_t weight;
+  /**
+   * nonzero means exclusive dependency
+   */
+  uint8_t exclusive;
+} nghttp2_priority_spec;
+
+/**
+ * @struct
+ *
+ * The HEADERS frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The length of the padding in this frame.  This includes PAD_HIGH
+   * and PAD_LOW.
+   */
+  size_t padlen;
+  /**
+   * The priority specification
+   */
+  nghttp2_priority_spec pri_spec;
+  /**
+   * The name/value pairs.
+   */
+  nghttp2_nv *nva;
+  /**
+   * The number of name/value pairs in |nva|.
+   */
+  size_t nvlen;
+  /**
+   * The category of this HEADERS frame.
+   */
+  nghttp2_headers_category cat;
+} nghttp2_headers;
+
+/**
+ * @struct
+ *
+ * The PRIORITY frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The priority specification.
+   */
+  nghttp2_priority_spec pri_spec;
+} nghttp2_priority;
+
+/**
+ * @struct
+ *
+ * The RST_STREAM frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The error code.  See :type:`nghttp2_error_code`.
+   */
+  uint32_t error_code;
+} nghttp2_rst_stream;
+
+/**
+ * @struct
+ *
+ * The SETTINGS ID/Value pair.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The SETTINGS ID.  See :type:`nghttp2_settings_id`.
+   */
+  int32_t settings_id;
+  /**
+   * The value of this entry.
+   */
+  uint32_t value;
+} nghttp2_settings_entry;
+
+/**
+ * @struct
+ *
+ * The SETTINGS frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The number of SETTINGS ID/Value pairs in |iv|.
+   */
+  size_t niv;
+  /**
+   * The pointer to the array of SETTINGS ID/Value pair.
+   */
+  nghttp2_settings_entry *iv;
+} nghttp2_settings;
+
+/**
+ * @struct
+ *
+ * The PUSH_PROMISE frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The length of the padding in this frame.  This includes PAD_HIGH
+   * and PAD_LOW.
+   */
+  size_t padlen;
+  /**
+   * The name/value pairs.
+   */
+  nghttp2_nv *nva;
+  /**
+   * The number of name/value pairs in |nva|.
+   */
+  size_t nvlen;
+  /**
+   * The promised stream ID
+   */
+  int32_t promised_stream_id;
+  /**
+   * Reserved bit.  Currently this is always set to 0 and application
+   * should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_push_promise;
+
+/**
+ * @struct
+ *
+ * The PING frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The opaque data
+   */
+  uint8_t opaque_data[8];
+} nghttp2_ping;
+
+/**
+ * @struct
+ *
+ * The GOAWAY frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The last stream stream ID.
+   */
+  int32_t last_stream_id;
+  /**
+   * The error code.  See :type:`nghttp2_error_code`.
+   */
+  uint32_t error_code;
+  /**
+   * The additional debug data
+   */
+  uint8_t *opaque_data;
+  /**
+   * The length of |opaque_data| member.
+   */
+  size_t opaque_data_len;
+  /**
+   * Reserved bit.  Currently this is always set to 0 and application
+   * should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_goaway;
+
+/**
+ * @struct
+ *
+ * The WINDOW_UPDATE frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The window size increment.
+   */
+  int32_t window_size_increment;
+  /**
+   * Reserved bit.  Currently this is always set to 0 and application
+   * should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_window_update;
+
+/**
+ * @struct
+ *
+ * The extension frame.  It has following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The pointer to extension payload.  The exact pointer type is
+   * determined by hd.type.
+   *
+   * Currently, no extension is supported.  This is a place holder for
+   * the future extensions.
+   */
+  void *payload;
+} nghttp2_extension;
+
+/**
+ * @union
+ *
+ * This union includes all frames to pass them to various function
+ * calls as nghttp2_frame type.  The CONTINUATION frame is omitted
+ * from here because the library deals with it internally.
+ */
+typedef union {
+  /**
+   * The frame header, which is convenient to inspect frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The DATA frame.
+   */
+  nghttp2_data data;
+  /**
+   * The HEADERS frame.
+   */
+  nghttp2_headers headers;
+  /**
+   * The PRIORITY frame.
+   */
+  nghttp2_priority priority;
+  /**
+   * The RST_STREAM frame.
+   */
+  nghttp2_rst_stream rst_stream;
+  /**
+   * The SETTINGS frame.
+   */
+  nghttp2_settings settings;
+  /**
+   * The PUSH_PROMISE frame.
+   */
+  nghttp2_push_promise push_promise;
+  /**
+   * The PING frame.
+   */
+  nghttp2_ping ping;
+  /**
+   * The GOAWAY frame.
+   */
+  nghttp2_goaway goaway;
+  /**
+   * The WINDOW_UPDATE frame.
+   */
+  nghttp2_window_update window_update;
+  /**
+   * The extension frame.
+   */
+  nghttp2_extension ext;
+} nghttp2_frame;
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when |session| wants to send data to the
+ * remote peer.  The implementation of this function must send at most
+ * |length| bytes of data stored in |data|.  The |flags| is currently
+ * not used and always 0. It must return the number of bytes sent if
+ * it succeeds.  If it cannot send any single byte without blocking,
+ * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`.  For other errors,
+ * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * This callback is required if the application uses
+ * `nghttp2_session_send()` to send data to the remote endpoint.  If
+ * the application uses solely `nghttp2_session_mem_send()` instead,
+ * this callback function is unnecessary.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_send_callback()`.
+ *
+ * .. note::
+ *
+ *   The |length| may be very small.  If that is the case, and
+ *   application disables Nagle algorithm (``TCP_NODELAY``), then just
+ *   writing |data| to the network stack leads to very small packet,
+ *   and it is very inefficient.  An application should be responsible
+ *   to buffer up small chunks of data as necessary to avoid this
+ *   situation.
+ */
+typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
+                                         const uint8_t *data, size_t length,
+                                         int flags, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
+ * used in :type:`nghttp2_data_source_read_callback` to send complete
+ * DATA frame.
+ *
+ * The |frame| is a DATA frame to send.  The |framehd| is the
+ * serialized frame header (9 bytes). The |length| is the length of
+ * application data to send (this does not include padding).  The
+ * |source| is the same pointer passed to
+ * :type:`nghttp2_data_source_read_callback`.
+ *
+ * The application first must send frame header |framehd| of length 9
+ * bytes.  If ``frame->data.padlen > 0``, send 1 byte of value
+ * ``frame->data.padlen - 1``.  Then send exactly |length| bytes of
+ * application data.  Finally, if ``frame->data.padlen > 1``, send
+ * ``frame->data.padlen - 1`` bytes of zero as padding.
+ *
+ * The application has to send complete DATA frame in this callback.
+ * If all data were written successfully, return 0.
+ *
+ * If it cannot send any data at all, just return
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback
+ * with the same parameters later (It is recommended to send complete
+ * DATA frame at once in this function to deal with error; if partial
+ * frame data has already sent, it is impossible to send another data
+ * in that state, and all we can do is tear down connection).  When
+ * data is fully processed, but application wants to make
+ * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return
+ * immediately without processing next frames, return
+ * :enum:`NGHTTP2_ERR_PAUSE`.  If application decided to reset this
+ * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then
+ * the library will send RST_STREAM with INTERNAL_ERROR as error code.
+ * The application can also return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in
+ * connection closure.  Returning any other value is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ */
+typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
+                                          nghttp2_frame *frame,
+                                          const uint8_t *framehd, size_t length,
+                                          nghttp2_data_source *source,
+                                          void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when |session| wants to receive data from
+ * the remote peer.  The implementation of this function must read at
+ * most |length| bytes of data and store it in |buf|.  The |flags| is
+ * currently not used and always 0.  It must return the number of
+ * bytes written in |buf| if it succeeds.  If it cannot read any
+ * single byte without blocking, it must return
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`.  If it gets EOF before it reads any
+ * single byte, it must return :enum:`NGHTTP2_ERR_EOF`.  For other
+ * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * This callback is required if the application uses
+ * `nghttp2_session_recv()` to receive data from the remote endpoint.
+ * If the application uses solely `nghttp2_session_mem_recv()`
+ * instead, this callback function is unnecessary.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_recv_callback()`.
+ */
+typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
+                                         size_t length, int flags,
+                                         void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when a frame is received.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
+ * member of their data structure are always ``NULL`` and 0
+ * respectively.  The header name/value pairs are emitted via
+ * :type:`nghttp2_on_header_callback`.
+ *
+ * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be
+ * called after stream is closed (see
+ * :type:`nghttp2_on_stream_close_callback`).  The application should
+ * check that stream is still alive using its own stream management or
+ * :func:`nghttp2_session_get_stream_user_data()`.
+ *
+ * Only HEADERS and DATA frame can signal the end of incoming data.
+ * If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
+ * |frame| is the last frame from the remote peer in this stream.
+ *
+ * This callback won't be called for CONTINUATION frames.
+ * HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero value is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_frame_recv_callback()`.
+ */
+typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
+                                              const nghttp2_frame *frame,
+                                              void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
+ * received.  The error is indicated by the |lib_error_code|, which is
+ * one of the values defined in :type:`nghttp2_error`.  When this
+ * callback function is invoked, the library automatically submits
+ * either RST_STREAM or GOAWAY frame.  The |user_data| pointer is the
+ * third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
+ * member of their data structure are always ``NULL`` and 0
+ * respectively.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
+ */
+typedef int (*nghttp2_on_invalid_frame_recv_callback)(
+    nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
+    void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a chunk of data in DATA frame is
+ * received.  The |stream_id| is the stream ID this DATA frame belongs
+ * to.  The |flags| is the flags of DATA frame which this data chunk
+ * is contained.  ``(flags & NGHTTP2_FLAG_END_STREAM) != 0`` does not
+ * necessarily mean this chunk of data is the last one in the stream.
+ * You should use :type:`nghttp2_on_frame_recv_callback` to know all
+ * data frames are received.  The |user_data| pointer is the third
+ * argument passed in to the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * If the application uses `nghttp2_session_mem_recv()`, it can return
+ * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
+ * return without processing further input bytes.  The memory by
+ * pointed by the |data| is retained until
+ * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
+ * The application must retain the input bytes which was used to
+ * produce the |data| parameter, because it may refer to the memory
+ * region included in the input bytes.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error, and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`.
+ */
+typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session,
+                                                   uint8_t flags,
+                                                   int32_t stream_id,
+                                                   const uint8_t *data,
+                                                   size_t len, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked just before the non-DATA frame |frame| is
+ * sent.  The |user_data| pointer is the third argument passed in to
+ * the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the
+ * transmission of the given frame.
+ *
+ * If there is a fatal error while executing this callback, the
+ * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`,
+ * which makes `nghttp2_session_send()` and
+ * `nghttp2_session_mem_send()` functions immediately return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * If the other value is returned, it is treated as if
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.  But the
+ * implementation should not rely on this since the library may define
+ * new return value to extend its capability.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_before_frame_send_callback()`.
+ */
+typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session,
+                                                  const nghttp2_frame *frame,
+                                                  void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked after the frame |frame| is sent.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_frame_send_callback()`.
+ */
+typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session,
+                                              const nghttp2_frame *frame,
+                                              void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked after the non-DATA frame |frame| is not
+ * sent because of the error.  The error is indicated by the
+ * |lib_error_code|, which is one of the values defined in
+ * :type:`nghttp2_error`.  The |user_data| pointer is the third
+ * argument passed in to the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * `nghttp2_session_get_stream_user_data()` can be used to get
+ * associated data.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_frame_not_send_callback()`.
+ */
+typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session,
+                                                  const nghttp2_frame *frame,
+                                                  int lib_error_code,
+                                                  void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the stream |stream_id| is closed.
+ * The reason of closure is indicated by the |error_code|.  The
+ * |error_code| is usually one of :enum:`nghttp2_error_code`, but that
+ * is not guaranteed.  The stream_user_data, which was specified in
+ * `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still
+ * available in this function.  The |user_data| pointer is the third
+ * argument passed in to the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * This function is also called for a stream in reserved state.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`,
+ * `nghttp2_session_send()`, and `nghttp2_session_mem_send()`
+ * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_stream_close_callback()`.
+ */
+typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
+                                                int32_t stream_id,
+                                                uint32_t error_code,
+                                                void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the reception of header block in
+ * HEADERS or PUSH_PROMISE is started.  Each header name/value pair
+ * will be emitted by :type:`nghttp2_on_header_callback`.
+ *
+ * The ``frame->hd.flags`` may not have
+ * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one
+ * or more CONTINUATION frames are involved.  But the application does
+ * not need to care about that because the header name/value pairs are
+ * emitted transparently regardless of CONTINUATION frames.
+ *
+ * The server applications probably create an object to store
+ * information about new stream if ``frame->hd.type ==
+ * NGHTTP2_HEADERS`` and ``frame->headers.cat ==
+ * NGHTTP2_HCAT_REQUEST``.  If |session| is configured as server side,
+ * ``frame->headers.cat`` is either ``NGHTTP2_HCAT_REQUEST``
+ * containing request headers or ``NGHTTP2_HCAT_HEADERS`` containing
+ * trailer fields and never get PUSH_PROMISE in this callback.
+ *
+ * For the client applications, ``frame->hd.type`` is either
+ * ``NGHTTP2_HEADERS`` or ``NGHTTP2_PUSH_PROMISE``.  In case of
+ * ``NGHTTP2_HEADERS``, ``frame->headers.cat ==
+ * NGHTTP2_HCAT_RESPONSE`` means that it is the first response
+ * headers, but it may be non-final response which is indicated by 1xx
+ * status code.  In this case, there may be zero or more HEADERS frame
+ * with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` which has
+ * non-final response code and finally client gets exactly one HEADERS
+ * frame with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS``
+ * containing final response headers (non-1xx status code).  The
+ * trailer fields also has ``frame->headers.cat ==
+ * NGHTTP2_HCAT_HEADERS`` which does not contain any status code.
+ *
+ * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
+ * the stream (promised stream if frame is PUSH_PROMISE) by issuing
+ * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  In this case,
+ * :type:`nghttp2_on_header_callback` and
+ * :type:`nghttp2_on_frame_recv_callback` will not be invoked.  If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Again, use
+ * ``frame->push_promise.promised_stream_id`` as stream_id parameter
+ * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
+ * reset the stream (promised stream if frame is PUSH_PROMISE).  For
+ * critical errors, it must return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other value is
+ * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * is returned.  If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * `nghttp2_session_mem_recv()` function will immediately return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_begin_headers_callback()`.
+ */
+typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
+                                                 const nghttp2_frame *frame,
+                                                 void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a header name/value pair is received
+ * for the |frame|.  The |name| of length |namelen| is header name.
+ * The |value| of length |valuelen| is header value.  The |flags| is
+ * bitwise OR of one or more of :type:`nghttp2_nv_flag`.
+ *
+ * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver
+ * must not index this name/value pair when forwarding it to the next
+ * hop.  More specifically, "Literal Header Field never Indexed"
+ * representation must be used in HPACK encoding.
+ *
+ * When this callback is invoked, ``frame->hd.type`` is either
+ * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`.  After all
+ * header name/value pairs are processed with this callback, and no
+ * error has been detected, :type:`nghttp2_on_frame_recv_callback`
+ * will be invoked.  If there is an error in decompression,
+ * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be
+ * invoked.
+ *
+ * Both |name| and |value| are guaranteed to be NULL-terminated.  The
+ * |namelen| and |valuelen| do not include terminal NULL.  If
+ * `nghttp2_option_set_no_http_messaging()` is used with nonzero
+ * value, NULL character may be included in |name| or |value| before
+ * terminating NULL.
+ *
+ * Please note that unless `nghttp2_option_set_no_http_messaging()` is
+ * used, nghttp2 library does perform validation against the |name|
+ * and the |value| using `nghttp2_check_header_name()` and
+ * `nghttp2_check_header_value()`.  In addition to this, nghttp2
+ * performs validation based on HTTP Messaging rule, which is briefly
+ * explained in :ref:`http-messaging` section.
+ *
+ * If the application uses `nghttp2_session_mem_recv()`, it can return
+ * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
+ * return without processing further input bytes.  The memory pointed
+ * by |frame|, |name| and |value| parameters are retained until
+ * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
+ * The application must retain the input bytes which was used to
+ * produce these parameters, because it may refer to the memory region
+ * included in the input bytes.
+ *
+ * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
+ * the stream (promised stream if frame is PUSH_PROMISE) by issuing
+ * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  In this case,
+ * :type:`nghttp2_on_header_callback` and
+ * :type:`nghttp2_on_frame_recv_callback` will not be invoked.  If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Again, use
+ * ``frame->push_promise.promised_stream_id`` as stream_id parameter
+ * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It may return :enum:`NGHTTP2_ERR_PAUSE` or
+ * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  For other critical
+ * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If
+ * the other nonzero value is returned, it is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_header_callback()`.
+ *
+ * .. warning::
+ *
+ *   Application should properly limit the total buffer size to store
+ *   incoming header fields.  Without it, peer may send large number
+ *   of header fields or large header fields to cause out of memory in
+ *   local endpoint.  Due to how HPACK works, peer can do this
+ *   effectively without using much memory on their own.
+ */
+typedef int (*nghttp2_on_header_callback)(nghttp2_session *session,
+                                          const nghttp2_frame *frame,
+                                          const uint8_t *name, size_t namelen,
+                                          const uint8_t *value, size_t valuelen,
+                                          uint8_t flags, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a header name/value pair is received
+ * for the |frame|.  The |name| is header name.  The |value| is header
+ * value.  The |flags| is bitwise OR of one or more of
+ * :type:`nghttp2_nv_flag`.
+ *
+ * This callback behaves like :type:`nghttp2_on_header_callback`,
+ * except that |name| and |value| are stored in reference counted
+ * buffer.  If application wishes to keep these references without
+ * copying them, use `nghttp2_rcbuf_incref()` to increment their
+ * reference count.  It is the application's responsibility to call
+ * `nghttp2_rcbuf_decref()` if they called `nghttp2_rcbuf_incref()` so
+ * as not to leak memory.  If the |session| is created by
+ * `nghttp2_session_server_new3()` or `nghttp2_session_client_new3()`,
+ * the function to free memory is the one belongs to the mem
+ * parameter.  As long as this free function alives, |name| and
+ * |value| can live after |session| was destroyed.
+ */
+typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session,
+                                           const nghttp2_frame *frame,
+                                           nghttp2_rcbuf *name,
+                                           nghttp2_rcbuf *value, uint8_t flags,
+                                           void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the library asks application how
+ * many padding bytes are required for the transmission of the
+ * |frame|.  The application must choose the total length of payload
+ * including padded bytes in range [frame->hd.length, max_payloadlen],
+ * inclusive.  Choosing number not in this range will be treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Returning
+ * ``frame->hd.length`` means no padding is added.  Returning
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_select_padding_callback()`.
+ */
+typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session,
+                                                   const nghttp2_frame *frame,
+                                                   size_t max_payloadlen,
+                                                   void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library wants to get max length of
+ * data to send data to the remote peer.  The implementation of this
+ * function should return a value in the following range.  [1,
+ * min(|session_remote_window_size|, |stream_remote_window_size|,
+ * |remote_max_frame_size|)].  If a value greater than this range is
+ * returned than the max allow value will be used.  Returning a value
+ * smaller than this range is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  The |frame_type| is provided
+ * for future extensibility and identifies the type of frame (see
+ * :type:`nghttp2_frame_type`) for which to get the length for.
+ * Currently supported frame types are: :enum:`NGHTTP2_DATA`.
+ *
+ * This callback can be used to control the length in bytes for which
+ * :type:`nghttp2_data_source_read_callback` is allowed to send to the
+ * remote endpoint.  This callback is optional.  Returning
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
+ * failure.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_data_source_read_length_callback()`.
+ */
+typedef ssize_t (*nghttp2_data_source_read_length_callback)(
+    nghttp2_session *session, uint8_t frame_type, int32_t stream_id,
+    int32_t session_remote_window_size, int32_t stream_remote_window_size,
+    uint32_t remote_max_frame_size, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a frame header is received.  The
+ * |hd| points to received frame header.
+ *
+ * Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will
+ * also be called when frame header of CONTINUATION frame is received.
+ *
+ * If both :type:`nghttp2_on_begin_frame_callback` and
+ * :type:`nghttp2_on_begin_headers_callback` are set and HEADERS or
+ * PUSH_PROMISE is received, :type:`nghttp2_on_begin_frame_callback`
+ * will be called first.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero value is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
+ */
+typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
+                                               const nghttp2_frame_hd *hd,
+                                               void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when chunk of extension frame payload is
+ * received.  The |hd| points to frame header.  The received
+ * chunk is |data| of length |len|.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ *
+ * To abort processing this extension frame, return
+ * :enum:`NGHTTP2_ERR_CANCEL`.
+ *
+ * If fatal error occurred, application should return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
+ * other values are returned, currently they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ */
+typedef int (*nghttp2_on_extension_chunk_recv_callback)(
+    nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
+    size_t len, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library asks the application to
+ * unpack extension payload from its wire format.  The extension
+ * payload has been passed to the application using
+ * :type:`nghttp2_on_extension_chunk_recv_callback`.  The frame header
+ * is already unpacked by the library and provided as |hd|.
+ *
+ * To receive extension frames, the application must tell desired
+ * extension frame type to the library using
+ * `nghttp2_option_set_user_recv_extension_type()`.
+ *
+ * The implementation of this function may store the pointer to the
+ * created object as a result of unpacking in |*payload|, and returns
+ * 0.  The pointer stored in |*payload| is opaque to the library, and
+ * the library does not own its pointer.  |*payload| is initialized as
+ * ``NULL``.  The |*payload| is available as ``frame->ext.payload`` in
+ * :type:`nghttp2_on_frame_recv_callback`.  Therefore if application
+ * can free that memory inside :type:`nghttp2_on_frame_recv_callback`
+ * callback.  Of course, application has a liberty not ot use
+ * |*payload|, and do its own mechanism to process extension frames.
+ *
+ * To abort processing this extension frame, return
+ * :enum:`NGHTTP2_ERR_CANCEL`.
+ *
+ * If fatal error occurred, application should return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
+ * other values are returned, currently they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ */
+typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
+                                                 void **payload,
+                                                 const nghttp2_frame_hd *hd,
+                                                 void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library asks the application to pack
+ * extension payload in its wire format.  The frame header will be
+ * packed by library.  Application must pack payload only.
+ * ``frame->ext.payload`` is the object passed to
+ * `nghttp2_submit_extension()` as payload parameter.  Application
+ * must pack extension payload to the |buf| of its capacity |len|
+ * bytes.  The |len| is at least 16KiB.
+ *
+ * The implementation of this function should return the number of
+ * bytes written into |buf| when it succeeds.
+ *
+ * To abort processing this extension frame, return
+ * :enum:`NGHTTP2_ERR_CANCEL`, and
+ * :type:`nghttp2_on_frame_not_send_callback` will be invoked.
+ *
+ * If fatal error occurred, application should return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
+ * other values are returned, currently they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the return value is
+ * strictly larger than |len|, it is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ */
+typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
+                                                   uint8_t *buf, size_t len,
+                                                   const nghttp2_frame *frame,
+                                                   void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library provides the error message
+ * intended for human consumption.  This callback is solely for
+ * debugging purpose.  The |msg| is typically NULL-terminated string
+ * of length |len|.  |len| does not include the sentinel NULL
+ * character.
+ *
+ * The format of error message may change between nghttp2 library
+ * versions.  The application should not depend on the particular
+ * format.
+ *
+ * Normally, application should return 0 from this callback.  If fatal
+ * error occurred while doing something in this callback, application
+ * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * library will return immediately with return value
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Currently, if nonzero value
+ * is returned from this callback, they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
+ * rely on this details.
+ */
+typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
+                                      size_t len, void *user_data);
+
+struct nghttp2_session_callbacks;
+
+/**
+ * @struct
+ *
+ * Callback functions for :type:`nghttp2_session`.  The details of
+ * this structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_session_callbacks nghttp2_session_callbacks;
+
+/**
+ * @function
+ *
+ * Initializes |*callbacks_ptr| with NULL values.
+ *
+ * The initialized object can be used when initializing multiple
+ * :type:`nghttp2_session` objects.
+ *
+ * When the application finished using this object, it can use
+ * `nghttp2_session_callbacks_del()` to free its memory.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr);
+
+/**
+ * @function
+ *
+ * Frees any resources allocated for |callbacks|.  If |callbacks| is
+ * ``NULL``, this function does nothing.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a session wants to send data to
+ * the remote peer.  This callback is not necessary if the application
+ * uses solely `nghttp2_session_mem_send()` to serialize data to
+ * transmit.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the a session wants to receive
+ * data from the remote peer.  This callback is not necessary if the
+ * application uses solely `nghttp2_session_mem_recv()` to process
+ * received data.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_recv_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when a frame is received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_recv_callback on_frame_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
+ * received.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a chunk of data in DATA frame
+ * is received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked before a non-DATA frame is sent.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_before_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_before_frame_send_callback before_frame_send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked after a frame is sent.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_send_callback on_frame_send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a non-DATA frame is not sent
+ * because of an error.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_not_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_not_send_callback on_frame_not_send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the stream is closed.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_stream_close_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_stream_close_callback on_stream_close_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the reception of header block
+ * in HEADERS or PUSH_PROMISE is started.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_headers_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_headers_callback on_begin_headers_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a header name/value pair is
+ * received.  If both
+ * `nghttp2_session_callbacks_set_on_header_callback()` and
+ * `nghttp2_session_callbacks_set_on_header_callback2()` are used to
+ * set callbacks, the latter has the precedence.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback on_header_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a header name/value pair is
+ * received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback2(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback2 on_header_callback2);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the library asks application
+ * how many padding bytes are required for the transmission of the
+ * given frame.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_select_padding_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_select_padding_callback select_padding_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function determine the length allowed in
+ * :type:`nghttp2_data_source_read_callback`.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_data_source_read_length_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_data_source_read_length_callback data_source_read_length_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a frame header is received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_frame_callback on_begin_frame_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :type:`nghttp2_data_source_read_callback` to avoid data copy.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_send_data_callback send_data_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the library asks the
+ * application to pack extension frame payload in wire format.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_pack_extension_callback pack_extension_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the library asks the
+ * application to unpack extension frame payload from wire format.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_unpack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_unpack_extension_callback unpack_extension_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when chunk of extension frame
+ * payload is received.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when library tells error message to
+ * the application.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace malloc().  The |mem_user_data|
+ * is the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void *(*nghttp2_malloc)(size_t size, void *mem_user_data);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace free().  The |mem_user_data| is
+ * the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void (*nghttp2_free)(void *ptr, void *mem_user_data);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace calloc().  The |mem_user_data|
+ * is the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void *(*nghttp2_calloc)(size_t nmemb, size_t size, void *mem_user_data);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace realloc().  The |mem_user_data|
+ * is the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void *(*nghttp2_realloc)(void *ptr, size_t size, void *mem_user_data);
+
+/**
+ * @struct
+ *
+ * Custom memory allocator functions and user defined pointer.  The
+ * |mem_user_data| member is passed to each allocator function.  This
+ * can be used, for example, to achieve per-session memory pool.
+ *
+ * In the following example code, ``my_malloc``, ``my_free``,
+ * ``my_calloc`` and ``my_realloc`` are the replacement of the
+ * standard allocators ``malloc``, ``free``, ``calloc`` and
+ * ``realloc`` respectively::
+ *
+ *     void *my_malloc_cb(size_t size, void *mem_user_data) {
+ *       return my_malloc(size);
+ *     }
+ *
+ *     void my_free_cb(void *ptr, void *mem_user_data) { my_free(ptr); }
+ *
+ *     void *my_calloc_cb(size_t nmemb, size_t size, void *mem_user_data) {
+ *       return my_calloc(nmemb, size);
+ *     }
+ *
+ *     void *my_realloc_cb(void *ptr, size_t size, void *mem_user_data) {
+ *       return my_realloc(ptr, size);
+ *     }
+ *
+ *     void session_new() {
+ *       nghttp2_session *session;
+ *       nghttp2_session_callbacks *callbacks;
+ *       nghttp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb,
+ *                          my_realloc_cb};
+ *
+ *       ...
+ *
+ *       nghttp2_session_client_new3(&session, callbacks, NULL, NULL, &mem);
+ *
+ *       ...
+ *     }
+ */
+typedef struct {
+  /**
+   * An arbitrary user supplied data.  This is passed to each
+   * allocator function.
+   */
+  void *mem_user_data;
+  /**
+   * Custom allocator function to replace malloc().
+   */
+  nghttp2_malloc malloc;
+  /**
+   * Custom allocator function to replace free().
+   */
+  nghttp2_free free;
+  /**
+   * Custom allocator function to replace calloc().
+   */
+  nghttp2_calloc calloc;
+  /**
+   * Custom allocator function to replace realloc().
+   */
+  nghttp2_realloc realloc;
+} nghttp2_mem;
+
+struct nghttp2_option;
+
+/**
+ * @struct
+ *
+ * Configuration options for :type:`nghttp2_session`.  The details of
+ * this structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_option nghttp2_option;
+
+/**
+ * @function
+ *
+ * Initializes |*option_ptr| with default values.
+ *
+ * When the application finished using this object, it can use
+ * `nghttp2_option_del()` to free its memory.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr);
+
+/**
+ * @function
+ *
+ * Frees any resources allocated for |option|.  If |option| is
+ * ``NULL``, this function does nothing.
+ */
+NGHTTP2_EXTERN void nghttp2_option_del(nghttp2_option *option);
+
+/**
+ * @function
+ *
+ * This option prevents the library from sending WINDOW_UPDATE for a
+ * connection automatically.  If this option is set to nonzero, the
+ * library won't send WINDOW_UPDATE for DATA until application calls
+ * `nghttp2_session_consume()` to indicate the consumed amount of
+ * data.  Don't use `nghttp2_submit_window_update()` for this purpose.
+ * By default, this option is set to zero.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
+ * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
+ * remote endpoint as if it is received in SETTINGS frame.  Without
+ * specifying this option, before the local endpoint receives
+ * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
+ * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited.  This may
+ * cause problem if local endpoint submits lots of requests initially
+ * and sending them at once to the remote peer may lead to the
+ * rejection of some requests.  Specifying this option to the sensible
+ * value, say 100, may avoid this kind of issue. This value will be
+ * overwritten if the local endpoint receives
+ * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
+                                               uint32_t val);
+
+/**
+ * @function
+ *
+ * By default, nghttp2 library, if configured as server, requires
+ * first 24 bytes of client magic byte string (MAGIC).  In most cases,
+ * this will simplify the implementation of server.  But sometimes
+ * server may want to detect the application protocol based on first
+ * few bytes on clear text communication.
+ *
+ * If this option is used with nonzero |val|, nghttp2 library does not
+ * handle MAGIC.  It still checks following SETTINGS frame.  This
+ * means that applications should deal with MAGIC by themselves.
+ *
+ * If this option is not used or used with zero value, if MAGIC does
+ * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
+ * and `nghttp2_session_mem_recv()` will return error
+ * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
+ * By default, nghttp2 library enforces subset of HTTP Messaging rules
+ * described in `HTTP/2 specification, section 8
+ * <https://tools.ietf.org/html/rfc7540#section-8>`_.  See
+ * :ref:`http-messaging` section for details.  For those applications
+ * who use nghttp2 library as non-HTTP use, give nonzero to |val| to
+ * disable this enforcement.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
+                                                         int val);
+
+/**
+ * @function
+ *
+ * RFC 7540 does not enforce any limit on the number of incoming
+ * reserved streams (in RFC 7540 terms, streams in reserved (remote)
+ * state).  This only affects client side, since only server can push
+ * streams.  Malicious server can push arbitrary number of streams,
+ * and make client's memory exhausted.  This option can set the
+ * maximum number of such incoming streams to avoid possible memory
+ * exhaustion.  If this option is set, and pushed streams are
+ * automatically closed on reception, without calling user provided
+ * callback, if they exceed the given limit.  The default value is
+ * 200.  If session is configured as server side, this option has no
+ * effect.  Server can control the number of streams to push.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
+                                               uint32_t val);
+
+/**
+ * @function
+ *
+ * Sets extension frame type the application is willing to handle with
+ * user defined callbacks (see
+ * :type:`nghttp2_on_extension_chunk_recv_callback` and
+ * :type:`nghttp2_unpack_extension_callback`).  The |type| is
+ * extension frame type, and must be strictly greater than 0x9.
+ * Otherwise, this function does nothing.  The application can call
+ * this function multiple times to set more than one frame type to
+ * receive.  The application does not have to call this function if it
+ * just sends extension frames.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
+                                            uint8_t type);
+
+/**
+ * @function
+ *
+ * Sets extension frame type the application is willing to receive
+ * using builtin handler.  The |type| is the extension frame type to
+ * receive, and must be strictly greater than 0x9.  Otherwise, this
+ * function does nothing.  The application can call this function
+ * multiple times to set more than one frame type to receive.  The
+ * application does not have to call this function if it just sends
+ * extension frames.
+ *
+ * If same frame type is passed to both
+ * `nghttp2_option_set_builtin_recv_extension_type()` and
+ * `nghttp2_option_set_user_recv_extension_type()`, the latter takes
+ * precedence.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
+                                               uint8_t type);
+
+/**
+ * @function
+ *
+ * This option prevents the library from sending PING frame with ACK
+ * flag set automatically when PING frame without ACK flag set is
+ * received.  If this option is set to nonzero, the library won't send
+ * PING frame with ACK flag set in the response for incoming PING
+ * frame.  The application can send PING frame with ACK flag set using
+ * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags
+ * parameter.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
+                                                        int val);
+
+/**
+ * @function
+ *
+ * This option sets the maximum length of header block (a set of
+ * header fields per one HEADERS frame) to send.  The length of a
+ * given set of header fields is calculated using
+ * `nghttp2_hd_deflate_bound()`.  The default value is 64KiB.  If
+ * application attempts to send header fields larger than this limit,
+ * the transmission of the frame fails with error code
+ * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
+                                                size_t val);
+
+/**
+ * @function
+ *
+ * Initializes |*session_ptr| for client use.  The all members of
+ * |callbacks| are copied to |*session_ptr|.  Therefore |*session_ptr|
+ * does not store |callbacks|.  The |user_data| is an arbitrary user
+ * supplied data, which will be passed to the callback functions.
+ *
+ * The :type:`nghttp2_send_callback` must be specified.  If the
+ * application code uses `nghttp2_session_recv()`, the
+ * :type:`nghttp2_recv_callback` must be specified.  The other members
+ * of |callbacks| can be ``NULL``.
+ *
+ * If this function fails, |*session_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_client_new(nghttp2_session **session_ptr,
+                           const nghttp2_session_callbacks *callbacks,
+                           void *user_data);
+
+/**
+ * @function
+ *
+ * Initializes |*session_ptr| for server use.  The all members of
+ * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr|
+ * does not store |callbacks|.  The |user_data| is an arbitrary user
+ * supplied data, which will be passed to the callback functions.
+ *
+ * The :type:`nghttp2_send_callback` must be specified.  If the
+ * application code uses `nghttp2_session_recv()`, the
+ * :type:`nghttp2_recv_callback` must be specified.  The other members
+ * of |callbacks| can be ``NULL``.
+ *
+ * If this function fails, |*session_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_server_new(nghttp2_session **session_ptr,
+                           const nghttp2_session_callbacks *callbacks,
+                           void *user_data);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_client_new()`, but with additional options
+ * specified in the |option|.
+ *
+ * The |option| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_client_new()`.
+ *
+ * This function does not take ownership |option|.  The application is
+ * responsible for freeing |option| if it finishes using the object.
+ *
+ * The library code does not refer to |option| after this function
+ * returns.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_client_new2(nghttp2_session **session_ptr,
+                            const nghttp2_session_callbacks *callbacks,
+                            void *user_data, const nghttp2_option *option);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_server_new()`, but with additional options
+ * specified in the |option|.
+ *
+ * The |option| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_server_new()`.
+ *
+ * This function does not take ownership |option|.  The application is
+ * responsible for freeing |option| if it finishes using the object.
+ *
+ * The library code does not refer to |option| after this function
+ * returns.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_server_new2(nghttp2_session **session_ptr,
+                            const nghttp2_session_callbacks *callbacks,
+                            void *user_data, const nghttp2_option *option);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_client_new2()`, but with additional custom
+ * memory allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_client_new2()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_client_new3(
+    nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks,
+    void *user_data, const nghttp2_option *option, nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_server_new2()`, but with additional custom
+ * memory allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_server_new2()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_server_new3(
+    nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks,
+    void *user_data, const nghttp2_option *option, nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Frees any resources allocated for |session|.  If |session| is
+ * ``NULL``, this function does nothing.
+ */
+NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Sends pending frames to the remote peer.
+ *
+ * This function retrieves the highest prioritized frame from the
+ * outbound queue and sends it to the remote peer.  It does this as
+ * many as possible until the user callback
+ * :type:`nghttp2_send_callback` returns
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty.
+ * This function calls several callback functions which are passed
+ * when initializing the |session|.  Here is the simple time chart
+ * which tells when each callback is invoked:
+ *
+ * 1. Get the next frame to send from outbound queue.
+ *
+ * 2. Prepare transmission of the frame.
+ *
+ * 3. If the control frame cannot be sent because some preconditions
+ *    are not met (e.g., request HEADERS cannot be sent after GOAWAY),
+ *    :type:`nghttp2_on_frame_not_send_callback` is invoked.  Abort
+ *    the following steps.
+ *
+ * 4. If the frame is HEADERS, PUSH_PROMISE or DATA,
+ *    :type:`nghttp2_select_padding_callback` is invoked.
+ *
+ * 5. If the frame is request HEADERS, the stream is opened here.
+ *
+ * 6. :type:`nghttp2_before_frame_send_callback` is invoked.
+ *
+ * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from
+ *    :type:`nghttp2_before_frame_send_callback`, the current frame
+ *    transmission is canceled, and
+ *    :type:`nghttp2_on_frame_not_send_callback` is invoked.  Abort
+ *    the following steps.
+ *
+ * 8. :type:`nghttp2_send_callback` is invoked one or more times to
+ *    send the frame.
+ *
+ * 9. :type:`nghttp2_on_frame_send_callback` is invoked.
+ *
+ * 10. If the transmission of the frame triggers closure of the
+ *     stream, the stream is closed and
+ *     :type:`nghttp2_on_stream_close_callback` is invoked.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ *     The callback function failed.
+ */
+NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the serialized data to send.
+ *
+ * This function behaves like `nghttp2_session_send()` except that it
+ * does not use :type:`nghttp2_send_callback` to transmit data.
+ * Instead, it assigns the pointer to the serialized data to the
+ * |*data_ptr| and returns its length.  The other callbacks are called
+ * in the same way as they are in `nghttp2_session_send()`.
+ *
+ * If no data is available to send, this function returns 0.
+ *
+ * This function may not return all serialized data in one invocation.
+ * To get all data, call this function repeatedly until it returns 0
+ * or one of negative error codes.
+ *
+ * The assigned |*data_ptr| is valid until the next call of
+ * `nghttp2_session_mem_send()` or `nghttp2_session_send()`.
+ *
+ * The caller must send all data before sending the next chunk of
+ * data.
+ *
+ * This function returns the length of the data pointed by the
+ * |*data_ptr| if it succeeds, or one of the following negative error
+ * codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ *
+ * .. note::
+ *
+ *   This function may produce very small byte string.  If that is the
+ *   case, and application disables Nagle algorithm (``TCP_NODELAY``),
+ *   then writing this small chunk leads to very small packet, and it
+ *   is very inefficient.  An application should be responsible to
+ *   buffer up small chunks of data as necessary to avoid this
+ *   situation.
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_session_mem_send(nghttp2_session *session, const uint8_t **data_ptr);
+
+/**
+ * @function
+ *
+ * Receives frames from the remote peer.
+ *
+ * This function receives as many frames as possible until the user
+ * callback :type:`nghttp2_recv_callback` returns
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`.  This function calls several
+ * callback functions which are passed when initializing the
+ * |session|.  Here is the simple time chart which tells when each
+ * callback is invoked:
+ *
+ * 1. :type:`nghttp2_recv_callback` is invoked one or more times to
+ *    receive frame header.
+ *
+ * 2. When frame header is received,
+ *    :type:`nghttp2_on_begin_frame_callback` is invoked.
+ *
+ * 3. If the frame is DATA frame:
+ *
+ *    1. :type:`nghttp2_recv_callback` is invoked to receive DATA
+ *       payload. For each chunk of data,
+ *       :type:`nghttp2_on_data_chunk_recv_callback` is invoked.
+ *
+ *    2. If one DATA frame is completely received,
+ *       :type:`nghttp2_on_frame_recv_callback` is invoked.  If the
+ *       reception of the frame triggers the closure of the stream,
+ *       :type:`nghttp2_on_stream_close_callback` is invoked.
+ *
+ * 4. If the frame is the control frame:
+ *
+ *    1. :type:`nghttp2_recv_callback` is invoked one or more times to
+ *       receive whole frame.
+ *
+ *    2. If the received frame is valid, then following actions are
+ *       taken.  If the frame is either HEADERS or PUSH_PROMISE,
+ *       :type:`nghttp2_on_begin_headers_callback` is invoked.  Then
+ *       :type:`nghttp2_on_header_callback` is invoked for each header
+ *       name/value pair.  After all name/value pairs are emitted
+ *       successfully, :type:`nghttp2_on_frame_recv_callback` is
+ *       invoked.  For other frames,
+ *       :type:`nghttp2_on_frame_recv_callback` is invoked.  If the
+ *       reception of the frame triggers the closure of the stream,
+ *       :type:`nghttp2_on_stream_close_callback` is invoked.
+ *
+ *    3. If the received frame is unpacked but is interpreted as
+ *       invalid, :type:`nghttp2_on_invalid_frame_recv_callback` is
+ *       invoked.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_EOF`
+ *     The remote peer did shutdown on the connection.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ *     The callback function failed.
+ * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ *     Invalid client magic was detected.  This error only returns
+ *     when |session| was configured as server and
+ *     `nghttp2_option_set_no_recv_client_magic()` is not used with
+ *     nonzero value.
+ * :enum:`NGHTTP2_ERR_FLOODED`
+ *     Flooding was detected in this HTTP/2 session, and it must be
+ *     closed.  This is most likely caused by misbehaviour of peer.
+ */
+NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Processes data |in| as an input from the remote endpoint.  The
+ * |inlen| indicates the number of bytes in the |in|.
+ *
+ * This function behaves like `nghttp2_session_recv()` except that it
+ * does not use :type:`nghttp2_recv_callback` to receive data; the
+ * |in| is the only data for the invocation of this function.  If all
+ * bytes are processed, this function returns.  The other callbacks
+ * are called in the same way as they are in `nghttp2_session_recv()`.
+ *
+ * In the current implementation, this function always tries to
+ * processes all input data unless either an error occurs or
+ * :enum:`NGHTTP2_ERR_PAUSE` is returned from
+ * :type:`nghttp2_on_header_callback` or
+ * :type:`nghttp2_on_data_chunk_recv_callback`.  If
+ * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the
+ * number of bytes which was used to produce the data or frame for the
+ * callback.
+ *
+ * This function returns the number of processed bytes, or one of the
+ * following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ *     The callback function failed.
+ * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ *     Invalid client magic was detected.  This error only returns
+ *     when |session| was configured as server and
+ *     `nghttp2_option_set_no_recv_client_magic()` is not used with
+ *     nonzero value.
+ * :enum:`NGHTTP2_ERR_FLOODED`
+ *     Flooding was detected in this HTTP/2 session, and it must be
+ *     closed.  This is most likely caused by misbehaviour of peer.
+ */
+NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
+                                                const uint8_t *in,
+                                                size_t inlen);
+
+/**
+ * @function
+ *
+ * Puts back previously deferred DATA frame in the stream |stream_id|
+ * to the outbound queue.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The stream does not exist; or no deferred data exist.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session,
+                                               int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns nonzero value if |session| wants to receive data from the
+ * remote peer.
+ *
+ * If both `nghttp2_session_want_read()` and
+ * `nghttp2_session_want_write()` return 0, the application should
+ * drop the connection.
+ */
+NGHTTP2_EXTERN int nghttp2_session_want_read(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns nonzero value if |session| wants to send data to the remote
+ * peer.
+ *
+ * If both `nghttp2_session_want_read()` and
+ * `nghttp2_session_want_write()` return 0, the application should
+ * drop the connection.
+ */
+NGHTTP2_EXTERN int nghttp2_session_want_write(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns stream_user_data for the stream |stream_id|.  The
+ * stream_user_data is provided by `nghttp2_submit_request()`,
+ * `nghttp2_submit_headers()` or
+ * `nghttp2_session_set_stream_user_data()`.  Unless it is set using
+ * `nghttp2_session_set_stream_user_data()`, if the stream is
+ * initiated by the remote endpoint, stream_user_data is always
+ * ``NULL``.  If the stream does not exist, this function returns
+ * ``NULL``.
+ */
+NGHTTP2_EXTERN void *
+nghttp2_session_get_stream_user_data(nghttp2_session *session,
+                                     int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Sets the |stream_user_data| to the stream denoted by the
+ * |stream_id|.  If a stream user data is already set to the stream,
+ * it is replaced with the |stream_user_data|.  It is valid to specify
+ * ``NULL`` in the |stream_user_data|, which nullifies the associated
+ * data pointer.
+ *
+ * It is valid to set the |stream_user_data| to the stream reserved by
+ * PUSH_PROMISE frame.
+ *
+ * This function returns 0 if it succeeds, or one of following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The stream does not exist
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_set_stream_user_data(nghttp2_session *session,
+                                     int32_t stream_id, void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Returns the number of frames in the outbound queue.  This does not
+ * include the deferred DATA frames.
+ */
+NGHTTP2_EXTERN size_t
+nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the number of DATA payload in bytes received without
+ * WINDOW_UPDATE transmission for the stream |stream_id|.  The local
+ * (receive) window size can be adjusted by
+ * `nghttp2_submit_window_update()`.  This function takes into account
+ * that and returns effective data length.  In particular, if the
+ * local window size is reduced by submitting negative
+ * window_size_increment with `nghttp2_submit_window_update()`, this
+ * function returns the number of bytes less than actually received.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session,
+                                                      int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns the local (receive) window size for the stream |stream_id|.
+ * The local window size can be adjusted by
+ * `nghttp2_submit_window_update()`.  This function takes into account
+ * that and returns effective window size.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
+                                                       int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns the number of DATA payload in bytes received without
+ * WINDOW_UPDATE transmission for a connection.  The local (receive)
+ * window size can be adjusted by `nghttp2_submit_window_update()`.
+ * This function takes into account that and returns effective data
+ * length.  In particular, if the local window size is reduced by
+ * submitting negative window_size_increment with
+ * `nghttp2_submit_window_update()`, this function returns the number
+ * of bytes less than actually received.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_effective_recv_data_length(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the local (receive) window size for a connection.  The
+ * local window size can be adjusted by
+ * `nghttp2_submit_window_update()`.  This function takes into account
+ * that and returns effective window size.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_effective_local_window_size(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the remote window size for a given stream |stream_id|.
+ *
+ * This is the amount of flow-controlled payload (e.g., DATA) that the
+ * local endpoint can send without stream level WINDOW_UPDATE.  There
+ * is also connection level flow control, so the effective size of
+ * payload that the local endpoint can actually send is
+ * min(`nghttp2_session_get_stream_remote_window_size()`,
+ * `nghttp2_session_get_remote_window_size()`).
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_stream_remote_window_size(nghttp2_session *session,
+                                              int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns the remote window size for a connection.
+ *
+ * This function always succeeds.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_remote_window_size(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns 1 if local peer half closed the given stream |stream_id|.
+ * Returns 0 if it did not.  Returns -1 if no such stream exists.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_get_stream_local_close(nghttp2_session *session,
+                                       int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns 1 if remote peer half closed the given stream |stream_id|.
+ * Returns 0 if it did not.  Returns -1 if no such stream exists.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_get_stream_remote_close(nghttp2_session *session,
+                                        int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Signals the session so that the connection should be terminated.
+ *
+ * The last stream ID is the minimum value between the stream ID of a
+ * stream for which :type:`nghttp2_on_frame_recv_callback` was called
+ * most recently and the last stream ID we have sent to the peer
+ * previously.
+ *
+ * The |error_code| is the error code of this GOAWAY frame.  The
+ * pre-defined error code is one of :enum:`nghttp2_error_code`.
+ *
+ * After the transmission, both `nghttp2_session_want_read()` and
+ * `nghttp2_session_want_write()` return 0.
+ *
+ * This function should be called when the connection should be
+ * terminated after sending GOAWAY.  If the remaining streams should
+ * be processed after GOAWAY, use `nghttp2_submit_goaway()` instead.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
+                                                     uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Signals the session so that the connection should be terminated.
+ *
+ * This function behaves like `nghttp2_session_terminate_session()`,
+ * but the last stream ID can be specified by the application for fine
+ * grained control of stream.  The HTTP/2 specification does not allow
+ * last_stream_id to be increased.  So the actual value sent as
+ * last_stream_id is the minimum value between the given
+ * |last_stream_id| and the last_stream_id we have previously sent to
+ * the peer.
+ *
+ * The |last_stream_id| is peer's stream ID or 0.  So if |session| is
+ * initialized as client, |last_stream_id| must be even or 0.  If
+ * |session| is initialized as server, |last_stream_id| must be odd or
+ * 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |last_stream_id| is invalid.
+ */
+NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
+                                                      int32_t last_stream_id,
+                                                      uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Signals to the client that the server started graceful shutdown
+ * procedure.
+ *
+ * This function is only usable for server.  If this function is
+ * called with client side session, this function returns
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ *
+ * To gracefully shutdown HTTP/2 session, server should call this
+ * function to send GOAWAY with last_stream_id (1u << 31) - 1.  And
+ * after some delay (e.g., 1 RTT), send another GOAWAY with the stream
+ * ID that the server has some processing using
+ * `nghttp2_submit_goaway()`.  See also
+ * `nghttp2_session_get_last_proc_stream_id()`.
+ *
+ * Unlike `nghttp2_submit_goaway()`, this function just sends GOAWAY
+ * and does nothing more.  This is a mere indication to the client
+ * that session shutdown is imminent.  The application should call
+ * `nghttp2_submit_goaway()` with appropriate last_stream_id after
+ * this call.
+ *
+ * If one or more GOAWAY frame have been already sent by either
+ * `nghttp2_submit_goaway()` or `nghttp2_session_terminate_session()`,
+ * this function has no effect.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     The |session| is initialized as client.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the value of SETTINGS |id| notified by a remote endpoint.
+ * The |id| must be one of values defined in
+ * :enum:`nghttp2_settings_id`.
+ */
+NGHTTP2_EXTERN uint32_t
+nghttp2_session_get_remote_settings(nghttp2_session *session,
+                                    nghttp2_settings_id id);
+
+/**
+ * @function
+ *
+ * Tells the |session| that next stream ID is |next_stream_id|.  The
+ * |next_stream_id| must be equal or greater than the value returned
+ * by `nghttp2_session_get_next_stream_id()`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |next_stream_id| is strictly less than the value
+ *     `nghttp2_session_get_next_stream_id()` returns; or
+ *     |next_stream_id| is invalid (e.g., even integer for client, or
+ *     odd integer for server).
+ */
+NGHTTP2_EXTERN int nghttp2_session_set_next_stream_id(nghttp2_session *session,
+                                                      int32_t next_stream_id);
+
+/**
+ * @function
+ *
+ * Returns the next outgoing stream ID.  Notice that return type is
+ * uint32_t.  If we run out of stream ID for this session, this
+ * function returns 1 << 31.
+ */
+NGHTTP2_EXTERN uint32_t
+nghttp2_session_get_next_stream_id(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Tells the |session| that |size| bytes for a stream denoted by
+ * |stream_id| were consumed by application and are ready to
+ * WINDOW_UPDATE.  The consumed bytes are counted towards both
+ * connection and stream level WINDOW_UPDATE (see
+ * `nghttp2_session_consume_connection()` and
+ * `nghttp2_session_consume_stream()` to update consumption
+ * independently).  This function is intended to be used without
+ * automatic window update (see
+ * `nghttp2_option_set_no_auto_window_update()`).
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
+                                           int32_t stream_id, size_t size);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_consume()`, but this only tells library that
+ * |size| bytes were consumed only for connection level.  Note that
+ * HTTP/2 maintains connection and stream level flow control windows
+ * independently.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
+                                                      size_t size);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_consume()`, but this only tells library that
+ * |size| bytes were consumed only for stream denoted by |stream_id|.
+ * Note that HTTP/2 maintains connection and stream level flow control
+ * windows independently.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
+                                                  int32_t stream_id,
+                                                  size_t size);
+
+/**
+ * @function
+ *
+ * Changes priority of existing stream denoted by |stream_id|.  The
+ * new priority specification is |pri_spec|.
+ *
+ * The priority is changed silently and instantly, and no PRIORITY
+ * frame will be sent to notify the peer of this change.  This
+ * function may be useful for server to change the priority of pushed
+ * stream.
+ *
+ * If |session| is initialized as server, and ``pri_spec->stream_id``
+ * points to the idle stream, the idle stream is created if it does
+ * not exist.  The created idle stream will depend on root stream
+ * (stream 0) with weight 16.
+ *
+ * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not
+ * found, we use default priority instead of given |pri_spec|.  That
+ * is make stream depend on root stream with weight 16.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     Attempted to depend on itself; or no stream exist for the given
+ *     |stream_id|; or |stream_id| is 0
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_change_stream_priority(nghttp2_session *session,
+                                       int32_t stream_id,
+                                       const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Creates idle stream with the given |stream_id|, and priority
+ * |pri_spec|.
+ *
+ * The stream creation is done without sending PRIORITY frame, which
+ * means that peer does not know about the existence of this idle
+ * stream in the local endpoint.
+ *
+ * RFC 7540 does not disallow the use of creation of idle stream with
+ * odd or even stream ID regardless of client or server.  So this
+ * function can create odd or even stream ID regardless of client or
+ * server.  But probably it is a bit safer to use the stream ID the
+ * local endpoint can initiate (in other words, use odd stream ID for
+ * client, and even stream ID for server), to avoid potential
+ * collision from peer's instruction.  Also we can use
+ * `nghttp2_session_set_next_stream_id()` to avoid to open created
+ * idle streams accidentally if we follow this recommendation.
+ *
+ * If |session| is initialized as server, and ``pri_spec->stream_id``
+ * points to the idle stream, the idle stream is created if it does
+ * not exist.  The created idle stream will depend on root stream
+ * (stream 0) with weight 16.
+ *
+ * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not
+ * found, we use default priority instead of given |pri_spec|.  That
+ * is make stream depend on root stream with weight 16.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     Attempted to depend on itself; or stream denoted by |stream_id|
+ *     already exists; or |stream_id| cannot be used to create idle
+ *     stream (in other words, local endpoint has already opened
+ *     stream ID greater than or equal to the given stream ID; or
+ *     |stream_id| is 0
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id,
+                                   const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Performs post-process of HTTP Upgrade request.  This function can
+ * be called from both client and server, but the behavior is very
+ * different in each other.
+ *
+ * .. warning::
+ *
+ *   This function is deprecated in favor of
+ *   `nghttp2_session_upgrade2()`, because this function lacks the
+ *   parameter to tell the library the request method used in the
+ *   original HTTP request.  This information is required for client
+ *   to validate actual response body length against content-length
+ *   header field (see `nghttp2_option_set_no_http_messaging()`).  If
+ *   HEAD is used in request, the length of response body must be 0
+ *   regardless of value included in content-length header field.
+ *
+ * If called from client side, the |settings_payload| must be the
+ * value sent in ``HTTP2-Settings`` header field and must be decoded
+ * by base64url decoder.  The |settings_payloadlen| is the length of
+ * |settings_payload|.  The |settings_payload| is unpacked and its
+ * setting values will be submitted using `nghttp2_submit_settings()`.
+ * This means that the client application code does not need to submit
+ * SETTINGS by itself.  The stream with stream ID=1 is opened and the
+ * |stream_user_data| is used for its stream_user_data.  The opened
+ * stream becomes half-closed (local) state.
+ *
+ * If called from server side, the |settings_payload| must be the
+ * value received in ``HTTP2-Settings`` header field and must be
+ * decoded by base64url decoder.  The |settings_payloadlen| is the
+ * length of |settings_payload|.  It is treated as if the SETTINGS
+ * frame with that payload is received.  Thus, callback functions for
+ * the reception of SETTINGS frame will be invoked.  The stream with
+ * stream ID=1 is opened.  The |stream_user_data| is ignored.  The
+ * opened stream becomes half-closed (remote).
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |settings_payload| is badly formed.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The stream ID 1 is already used or closed; or is not available.
+ */
+NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
+                                           const uint8_t *settings_payload,
+                                           size_t settings_payloadlen,
+                                           void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Performs post-process of HTTP Upgrade request.  This function can
+ * be called from both client and server, but the behavior is very
+ * different in each other.
+ *
+ * If called from client side, the |settings_payload| must be the
+ * value sent in ``HTTP2-Settings`` header field and must be decoded
+ * by base64url decoder.  The |settings_payloadlen| is the length of
+ * |settings_payload|.  The |settings_payload| is unpacked and its
+ * setting values will be submitted using `nghttp2_submit_settings()`.
+ * This means that the client application code does not need to submit
+ * SETTINGS by itself.  The stream with stream ID=1 is opened and the
+ * |stream_user_data| is used for its stream_user_data.  The opened
+ * stream becomes half-closed (local) state.
+ *
+ * If called from server side, the |settings_payload| must be the
+ * value received in ``HTTP2-Settings`` header field and must be
+ * decoded by base64url decoder.  The |settings_payloadlen| is the
+ * length of |settings_payload|.  It is treated as if the SETTINGS
+ * frame with that payload is received.  Thus, callback functions for
+ * the reception of SETTINGS frame will be invoked.  The stream with
+ * stream ID=1 is opened.  The |stream_user_data| is ignored.  The
+ * opened stream becomes half-closed (remote).
+ *
+ * If the request method is HEAD, pass nonzero value to
+ * |head_request|.  Otherwise, pass 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |settings_payload| is badly formed.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The stream ID 1 is already used or closed; or is not available.
+ */
+NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session,
+                                            const uint8_t *settings_payload,
+                                            size_t settings_payloadlen,
+                                            int head_request,
+                                            void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Serializes the SETTINGS values |iv| in the |buf|.  The size of the
+ * |buf| is specified by |buflen|.  The number of entries in the |iv|
+ * array is given by |niv|.  The required space in |buf| for the |niv|
+ * entries is ``8*niv`` bytes and if the given buffer is too small, an
+ * error is returned.  This function is used mainly for creating a
+ * SETTINGS payload to be sent with the ``HTTP2-Settings`` header
+ * field in an HTTP Upgrade request.  The data written in |buf| is NOT
+ * base64url encoded and the application is responsible for encoding.
+ *
+ * This function returns the number of bytes written in |buf|, or one
+ * of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |iv| contains duplicate settings ID or invalid value.
+ *
+ * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ *     The provided |buflen| size is too small to hold the output.
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
+                              const nghttp2_settings_entry *iv, size_t niv);
+
+/**
+ * @function
+ *
+ * Returns string describing the |lib_error_code|.  The
+ * |lib_error_code| must be one of the :enum:`nghttp2_error`.
+ */
+NGHTTP2_EXTERN const char *nghttp2_strerror(int lib_error_code);
+
+/**
+ * @function
+ *
+ * Returns string representation of HTTP/2 error code |error_code|
+ * (e.g., ``PROTOCOL_ERROR`` is returned if ``error_code ==
+ * NGHTTP2_PROTOCOL_ERROR``).  If string representation is unknown for
+ * given |error_code|, this function returns string ``unknown``.
+ */
+NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Initializes |pri_spec| with the |stream_id| of the stream to depend
+ * on with |weight| and its exclusive flag.  If |exclusive| is
+ * nonzero, exclusive flag is set.
+ *
+ * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
+ */
+NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
+                                               int32_t stream_id,
+                                               int32_t weight, int exclusive);
+
+/**
+ * @function
+ *
+ * Initializes |pri_spec| with the default values.  The default values
+ * are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and
+ * exclusive = 0.
+ */
+NGHTTP2_EXTERN void
+nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |pri_spec| is filled with default values.
+ */
+NGHTTP2_EXTERN int
+nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Submits HEADERS frame and optionally one or more DATA frames.
+ *
+ * The |pri_spec| is priority specification of this request.  ``NULL``
+ * means the default priority (see
+ * `nghttp2_priority_spec_default_init()`).  To specify the priority,
+ * use `nghttp2_priority_spec_init()`.  If |pri_spec| is not ``NULL``,
+ * this function will copy its data members.
+ *
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
+ * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * HTTP/2 specification has requirement about header fields in the
+ * request HEADERS.  See the specification for more details.
+ *
+ * If |data_prd| is not ``NULL``, it provides data which will be sent
+ * in subsequent DATA frames.  In this case, a method that allows
+ * request message bodies
+ * (https://tools.ietf.org/html/rfc7231#section-4) must be specified
+ * with ``:method`` key in |nva| (e.g. ``POST``).  This function does
+ * not take ownership of the |data_prd|.  The function copies the
+ * members of the |data_prd|.  If |data_prd| is ``NULL``, HEADERS have
+ * END_STREAM set.  The |stream_user_data| is data associated to the
+ * stream opened by this request and can be an arbitrary pointer,
+ * which can be retrieved later by
+ * `nghttp2_session_get_stream_user_data()`.
+ *
+ * This function returns assigned stream ID if it succeeds, or one of
+ * the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ *     No stream ID is available because maximum stream ID was
+ *     reached.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     Trying to depend on itself (new stream ID equals
+ *     ``pri_spec->stream_id``).
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The |session| is server session.
+ *
+ * .. warning::
+ *
+ *   This function returns assigned stream ID if it succeeds.  But
+ *   that stream is not opened yet.  The application must not submit
+ *   frame to that stream ID before
+ *   :type:`nghttp2_before_frame_send_callback` is called for this
+ *   frame.
+ *
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_submit_request(nghttp2_session *session,
+                       const nghttp2_priority_spec *pri_spec,
+                       const nghttp2_nv *nva, size_t nvlen,
+                       const nghttp2_data_provider *data_prd,
+                       void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Submits response HEADERS frame and optionally one or more DATA
+ * frames against the stream |stream_id|.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * HTTP/2 specification has requirement about header fields in the
+ * response HEADERS.  See the specification for more details.
+ *
+ * If |data_prd| is not ``NULL``, it provides data which will be sent
+ * in subsequent DATA frames.  This function does not take ownership
+ * of the |data_prd|.  The function copies the members of the
+ * |data_prd|.  If |data_prd| is ``NULL``, HEADERS will have
+ * END_STREAM flag set.
+ *
+ * This method can be used as normal HTTP response and push response.
+ * When pushing a resource using this function, the |session| must be
+ * configured using `nghttp2_session_server_new()` or its variants and
+ * the target stream denoted by the |stream_id| must be reserved using
+ * `nghttp2_submit_push_promise()`.
+ *
+ * To send non-final response headers (e.g., HTTP status 101), don't
+ * use this function because this function half-closes the outbound
+ * stream.  Instead, use `nghttp2_submit_headers()` for this purpose.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *     DATA or HEADERS has been already submitted and not fully
+ *     processed yet.  Normally, this does not happen, but when
+ *     application wrongly calls `nghttp2_submit_response()` twice,
+ *     this may happen.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The |session| is client session.
+ *
+ * .. warning::
+ *
+ *   Calling this function twice for the same stream ID may lead to
+ *   program crash.  It is generally considered to a programming error
+ *   to commit response twice.
+ */
+NGHTTP2_EXTERN int
+nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
+                        const nghttp2_nv *nva, size_t nvlen,
+                        const nghttp2_data_provider *data_prd);
+
+/**
+ * @function
+ *
+ * Submits trailer fields HEADERS against the stream |stream_id|.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible not to include
+ * pseudo-header fields (header field whose name starts with ":") in
+ * |nva|.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * For server, trailer fields must follow response HEADERS or response
+ * DATA without END_STREAM flat set.  The library does not enforce
+ * this requirement, and applications should do this for themselves.
+ * If `nghttp2_submit_trailer()` is called before any response HEADERS
+ * submission (usually by `nghttp2_submit_response()`), the content of
+ * |nva| will be sent as response headers, which will result in error.
+ *
+ * This function has the same effect with `nghttp2_submit_headers()`,
+ * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and
+ * stream_user_data to NULL.
+ *
+ * To submit trailer fields after `nghttp2_submit_response()` is
+ * called, the application has to specify
+ * :type:`nghttp2_data_provider` to `nghttp2_submit_response()`.
+ * Inside of :type:`nghttp2_data_source_read_callback`, when setting
+ * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`.  After that, the
+ * application can send trailer fields using
+ * `nghttp2_submit_trailer()`.  `nghttp2_submit_trailer()` can be used
+ * inside :type:`nghttp2_data_source_read_callback`.
+ *
+ * This function returns 0 if it succeeds and |stream_id| is -1.
+ * Otherwise, this function returns 0 if it succeeds, or one of the
+ * following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
+                                          int32_t stream_id,
+                                          const nghttp2_nv *nva, size_t nvlen);
+
+/**
+ * @function
+ *
+ * Submits HEADERS frame. The |flags| is bitwise OR of the
+ * following values:
+ *
+ * * :enum:`NGHTTP2_FLAG_END_STREAM`
+ *
+ * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has
+ * END_STREAM flag set.
+ *
+ * The library handles the CONTINUATION frame internally and it
+ * correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE
+ * or CONTINUATION frame.
+ *
+ * If the |stream_id| is -1, this frame is assumed as request (i.e.,
+ * request HEADERS frame which opens new stream).  In this case, the
+ * assigned stream ID will be returned.  Otherwise, specify stream ID
+ * in |stream_id|.
+ *
+ * The |pri_spec| is priority specification of this request.  ``NULL``
+ * means the default priority (see
+ * `nghttp2_priority_spec_default_init()`).  To specify the priority,
+ * use `nghttp2_priority_spec_init()`.  If |pri_spec| is not ``NULL``,
+ * this function will copy its data members.
+ *
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
+ * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * The |stream_user_data| is a pointer to an arbitrary data which is
+ * associated to the stream this frame will open.  Therefore it is
+ * only used if this frame opens streams, in other words, it changes
+ * stream state from idle or reserved to open.
+ *
+ * This function is low-level in a sense that the application code can
+ * specify flags directly.  For usual HTTP request,
+ * `nghttp2_submit_request()` is useful.  Likewise, for HTTP response,
+ * prefer `nghttp2_submit_response()`.
+ *
+ * This function returns newly assigned stream ID if it succeeds and
+ * |stream_id| is -1.  Otherwise, this function returns 0 if it
+ * succeeds, or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ *     No stream ID is available because maximum stream ID was
+ *     reached.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0; or trying to depend on itself (stream ID
+ *     equals ``pri_spec->stream_id``).
+ * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *     DATA or HEADERS has been already submitted and not fully
+ *     processed yet.  This happens if stream denoted by |stream_id|
+ *     is in reserved state.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The |stream_id| is -1, and |session| is server session.
+ *
+ * .. warning::
+ *
+ *   This function returns assigned stream ID if it succeeds and
+ *   |stream_id| is -1.  But that stream is not opened yet.  The
+ *   application must not submit frame to that stream ID before
+ *   :type:`nghttp2_before_frame_send_callback` is called for this
+ *   frame.
+ *
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
+                       int32_t stream_id, const nghttp2_priority_spec *pri_spec,
+                       const nghttp2_nv *nva, size_t nvlen,
+                       void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Submits one or more DATA frames to the stream |stream_id|.  The
+ * data to be sent are provided by |data_prd|.  If |flags| contains
+ * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM
+ * flag set.
+ *
+ * This function does not take ownership of the |data_prd|.  The
+ * function copies the members of the |data_prd|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *     DATA or HEADERS has been already submitted and not fully
+ *     processed yet.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ *     The stream was already closed; or the |stream_id| is invalid.
+ *
+ * .. note::
+ *
+ *   Currently, only one DATA or HEADERS is allowed for a stream at a
+ *   time.  Submitting these frames more than once before first DATA
+ *   or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *   error code.  The earliest callback which tells that previous
+ *   frame is done is :type:`nghttp2_on_frame_send_callback`.  In side
+ *   that callback, new data can be submitted using
+ *   `nghttp2_submit_data()`.  Of course, all data except for last one
+ *   must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in
+ *   |flags|.  This sounds a bit complicated, and we recommend to use
+ *   `nghttp2_submit_request()` and `nghttp2_submit_response()` to
+ *   avoid this cascading issue.  The experience shows that for HTTP
+ *   use, these two functions are enough to implement both client and
+ *   server.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
+                                       int32_t stream_id,
+                                       const nghttp2_data_provider *data_prd);
+
+/**
+ * @function
+ *
+ * Submits PRIORITY frame to change the priority of stream |stream_id|
+ * to the priority specification |pri_spec|.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |pri_spec| is priority specification of this request.  ``NULL``
+ * is not allowed for this function. To specify the priority, use
+ * `nghttp2_priority_spec_init()`.  This function will copy its data
+ * members.
+ *
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
+ * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0; or the |pri_spec| is NULL; or trying to
+ *     depend on itself.
+ */
+NGHTTP2_EXTERN int
+nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
+                        int32_t stream_id,
+                        const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Submits RST_STREAM frame to cancel/reject the stream |stream_id|
+ * with the error code |error_code|.
+ *
+ * The pre-defined error code is one of :enum:`nghttp2_error_code`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
+                                             uint8_t flags, int32_t stream_id,
+                                             uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Stores local settings and submits SETTINGS frame.  The |iv| is the
+ * pointer to the array of :type:`nghttp2_settings_entry`.  The |niv|
+ * indicates the number of :type:`nghttp2_settings_entry`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * This function does not take ownership of the |iv|.  This function
+ * copies all the elements in the |iv|.
+ *
+ * While updating individual stream's local window size, if the window
+ * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
+ * RST_STREAM is issued against such a stream.
+ *
+ * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted
+ * by the library and application could not send it at its will.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |iv| contains invalid value (e.g., initial window size
+ *     strictly greater than (1 << 31) - 1.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
+                                           uint8_t flags,
+                                           const nghttp2_settings_entry *iv,
+                                           size_t niv);
+
+/**
+ * @function
+ *
+ * Submits PUSH_PROMISE frame.
+ *
+ * The |flags| is currently ignored.  The library handles the
+ * CONTINUATION frame internally and it correctly sets END_HEADERS to
+ * the last sequence of the PUSH_PROMISE or CONTINUATION frame.
+ *
+ * The |stream_id| must be client initiated stream ID.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * The |promised_stream_user_data| is a pointer to an arbitrary data
+ * which is associated to the promised stream this frame will open and
+ * make it in reserved state.  It is available using
+ * `nghttp2_session_get_stream_user_data()`.  The application can
+ * access it in :type:`nghttp2_before_frame_send_callback` and
+ * :type:`nghttp2_on_frame_send_callback` of this frame.
+ *
+ * The client side is not allowed to use this function.
+ *
+ * To submit response headers and data, use
+ * `nghttp2_submit_response()`.
+ *
+ * This function returns assigned promised stream ID if it succeeds,
+ * or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     This function was invoked when |session| is initialized as
+ *     client.
+ * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ *     No stream ID is available because maximum stream ID was
+ *     reached.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0; The |stream_id| does not designate stream
+ *     that peer initiated.
+ * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ *     The stream was already closed; or the |stream_id| is invalid.
+ *
+ * .. warning::
+ *
+ *   This function returns assigned promised stream ID if it succeeds.
+ *   As of 1.16.0, stream object for pushed resource is created when
+ *   this function succeeds.  In that case, the application can submit
+ *   push response for the promised frame.
+ *
+ *   In 1.15.0 or prior versions, pushed stream is not opened yet when
+ *   this function succeeds.  The application must not submit frame to
+ *   that stream ID before :type:`nghttp2_before_frame_send_callback`
+ *   is called for this frame.
+ *
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
+                            int32_t stream_id, const nghttp2_nv *nva,
+                            size_t nvlen, void *promised_stream_user_data);
+
+/**
+ * @function
+ *
+ * Submits PING frame.  You don't have to send PING back when you
+ * received PING frame.  The library automatically submits PING frame
+ * in this case.
+ *
+ * The |flags| is bitwise OR of 0 or more of the following value.
+ *
+ * * :enum:`NGHTTP2_FLAG_ACK`
+ *
+ * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags|
+ * should be :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * If the |opaque_data| is non ``NULL``, then it should point to the 8
+ * bytes array of memory to specify opaque data to send with PING
+ * frame.  If the |opaque_data| is ``NULL``, zero-cleared 8 bytes will
+ * be sent as opaque data.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
+                                       const uint8_t *opaque_data);
+
+/**
+ * @function
+ *
+ * Submits GOAWAY frame with the last stream ID |last_stream_id| and
+ * the error code |error_code|.
+ *
+ * The pre-defined error code is one of :enum:`nghttp2_error_code`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |last_stream_id| is peer's stream ID or 0.  So if |session| is
+ * initialized as client, |last_stream_id| must be even or 0.  If
+ * |session| is initialized as server, |last_stream_id| must be odd or
+ * 0.
+ *
+ * The HTTP/2 specification says last_stream_id must not be increased
+ * from the value previously sent.  So the actual value sent as
+ * last_stream_id is the minimum value between the given
+ * |last_stream_id| and the last_stream_id previously sent to the
+ * peer.
+ *
+ * If the |opaque_data| is not ``NULL`` and |opaque_data_len| is not
+ * zero, those data will be sent as additional debug data.  The
+ * library makes a copy of the memory region pointed by |opaque_data|
+ * with the length |opaque_data_len|, so the caller does not need to
+ * keep this memory after the return of this function.  If the
+ * |opaque_data_len| is 0, the |opaque_data| could be ``NULL``.
+ *
+ * After successful transmission of GOAWAY, following things happen.
+ * All incoming streams having strictly more than |last_stream_id| are
+ * closed.  All incoming HEADERS which starts new stream are simply
+ * ignored.  After all active streams are handled, both
+ * `nghttp2_session_want_read()` and `nghttp2_session_want_write()`
+ * return 0 and the application can close session.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |opaque_data_len| is too large; the |last_stream_id| is
+ *     invalid.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_goaway(nghttp2_session *session,
+                                         uint8_t flags, int32_t last_stream_id,
+                                         uint32_t error_code,
+                                         const uint8_t *opaque_data,
+                                         size_t opaque_data_len);
+
+/**
+ * @function
+ *
+ * Returns the last stream ID of a stream for which
+ * :type:`nghttp2_on_frame_recv_callback` was invoked most recently.
+ * The returned value can be used as last_stream_id parameter for
+ * `nghttp2_submit_goaway()` and
+ * `nghttp2_session_terminate_session2()`.
+ *
+ * This function always succeeds.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_last_proc_stream_id(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns nonzero if new request can be sent from local endpoint.
+ *
+ * This function return 0 if request is not allowed for this session.
+ * There are several reasons why request is not allowed.  Some of the
+ * reasons are: session is server; stream ID has been spent; GOAWAY
+ * has been sent or received.
+ *
+ * The application can call `nghttp2_submit_request()` without
+ * consulting this function.  In that case, `nghttp2_submit_request()`
+ * may return error.  Or, request is failed to sent, and
+ * :type:`nghttp2_on_stream_close_callback` is called.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_check_request_allowed(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns nonzero if |session| is initialized as server side session.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_check_server_session(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Submits WINDOW_UPDATE frame.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |stream_id| is the stream ID to send this WINDOW_UPDATE.  To
+ * send connection level WINDOW_UPDATE, specify 0 to |stream_id|.
+ *
+ * If the |window_size_increment| is positive, the WINDOW_UPDATE with
+ * that value as window_size_increment is queued.  If the
+ * |window_size_increment| is larger than the received bytes from the
+ * remote endpoint, the local window size is increased by that
+ * difference.  If the sole purpose is to increase the local window
+ * size, consider to use `nghttp2_session_set_local_window_size()`.
+ *
+ * If the |window_size_increment| is negative, the local window size
+ * is decreased by -|window_size_increment|.  If automatic
+ * WINDOW_UPDATE is enabled
+ * (`nghttp2_option_set_no_auto_window_update()`), and the library
+ * decided that the WINDOW_UPDATE should be submitted, then
+ * WINDOW_UPDATE is queued with the current received bytes count.  If
+ * the sole purpose is to decrease the local window size, consider to
+ * use `nghttp2_session_set_local_window_size()`.
+ *
+ * If the |window_size_increment| is 0, the function does nothing and
+ * returns 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_FLOW_CONTROL`
+ *     The local window size overflow or gets negative.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
+                                                uint8_t flags,
+                                                int32_t stream_id,
+                                                int32_t window_size_increment);
+
+/**
+ * @function
+ *
+ * Set local window size (local endpoints's window size) to the given
+ * |window_size| for the given stream denoted by |stream_id|.  To
+ * change connection level window size, specify 0 to |stream_id|.  To
+ * increase window size, this function may submit WINDOW_UPDATE frame
+ * to transmission queue.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * This sounds similar to `nghttp2_submit_window_update()`, but there
+ * are 2 differences.  The first difference is that this function
+ * takes the absolute value of window size to set, rather than the
+ * delta.  To change the window size, this may be easier to use since
+ * the application just declares the intended window size, rather than
+ * calculating delta.  The second difference is that
+ * `nghttp2_submit_window_update()` affects the received bytes count
+ * which has not acked yet.  By the specification of
+ * `nghttp2_submit_window_update()`, to strictly increase the local
+ * window size, we have to submit delta including all received bytes
+ * count, which might not be desirable in some cases.  On the other
+ * hand, this function does not affect the received bytes count.  It
+ * just sets the local window size to the given value.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is negative.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags,
+                                      int32_t stream_id, int32_t window_size);
+
+/**
+ * @function
+ *
+ * Submits extension frame.
+ *
+ * Application can pass arbitrary frame flags and stream ID in |flags|
+ * and |stream_id| respectively.  The |payload| is opaque pointer, and
+ * it can be accessible though ``frame->ext.payload`` in
+ * :type:`nghttp2_pack_extension_callback`.  The library will not own
+ * passed |payload| pointer.
+ *
+ * The application must set :type:`nghttp2_pack_extension_callback`
+ * using `nghttp2_session_callbacks_set_pack_extension_callback()`.
+ *
+ * The application should retain the memory pointed by |payload| until
+ * the transmission of extension frame is done (which is indicated by
+ * :type:`nghttp2_on_frame_send_callback`), or transmission fails
+ * (which is indicated by :type:`nghttp2_on_frame_not_send_callback`).
+ * If application does not touch this memory region after packing it
+ * into a wire format, application can free it inside
+ * :type:`nghttp2_pack_extension_callback`.
+ *
+ * The standard HTTP/2 frame cannot be sent with this function, so
+ * |type| must be strictly grater than 0x9.  Otherwise, this function
+ * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     If :type:`nghttp2_pack_extension_callback` is not set.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     If  |type| specifies  standard  HTTP/2 frame  type.  The  frame
+ *     types  in the  rage [0x0,  0x9], both  inclusive, are  standard
+ *     HTTP/2 frame type, and cannot be sent using this function.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory
+ */
+NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
+                                            uint8_t type, uint8_t flags,
+                                            int32_t stream_id, void *payload);
+
+/**
+ * @struct
+ *
+ * The payload of ALTSVC frame.  ALTSVC frame is a non-critical
+ * extension to HTTP/2.  If this frame is received, and
+ * `nghttp2_option_set_user_recv_extension_type()` is not set, and
+ * `nghttp2_option_set_builtin_recv_extension_type()` is set for
+ * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to
+ * this struct.
+ *
+ * It has the following members:
+ */
+typedef struct {
+  /**
+   * The pointer to origin which this alternative service is
+   * associated with.  This is not necessarily NULL-terminated.
+   */
+  uint8_t *origin;
+  /**
+   * The length of the |origin|.
+   */
+  size_t origin_len;
+  /**
+   * The pointer to Alt-Svc field value contained in ALTSVC frame.
+   * This is not necessarily NULL-terminated.
+   */
+  uint8_t *field_value;
+  /**
+   * The length of the |field_value|.
+   */
+  size_t field_value_len;
+} nghttp2_ext_altsvc;
+
+/**
+ * @function
+ *
+ * Submits ALTSVC frame.
+ *
+ * ALTSVC frame is a non-critical extension to HTTP/2, and defined in
+ * is defined in `RFC 7383
+ * <https://tools.ietf.org/html/rfc7838#section-4>`_.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |origin| points to the origin this alternative service is
+ * associated with.  The |origin_len| is the length of the origin.  If
+ * |stream_id| is 0, the origin must be specified.  If |stream_id| is
+ * not zero, the origin must be empty (in other words, |origin_len|
+ * must be 0).
+ *
+ * The ALTSVC frame is only usable from server side.  If this function
+ * is invoked with client side session, this function returns
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     The function is called from client side session
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The sum of |origin_len| and |field_value_len| is larger than
+ *     16382; or |origin_len| is 0 while |stream_id| is 0; or
+ *     |origin_len| is not 0 while |stream_id| is not 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session,
+                                         uint8_t flags, int32_t stream_id,
+                                         const uint8_t *origin,
+                                         size_t origin_len,
+                                         const uint8_t *field_value,
+                                         size_t field_value_len);
+
+/**
+ * @function
+ *
+ * Compares ``lhs->name`` of length ``lhs->namelen`` bytes and
+ * ``rhs->name`` of length ``rhs->namelen`` bytes.  Returns negative
+ * integer if ``lhs->name`` is found to be less than ``rhs->name``; or
+ * returns positive integer if ``lhs->name`` is found to be greater
+ * than ``rhs->name``; or returns 0 otherwise.
+ */
+NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
+                                           const nghttp2_nv *rhs);
+
+/**
+ * @function
+ *
+ * A helper function for dealing with NPN in client side or ALPN in
+ * server side.  The |in| contains peer's protocol list in preferable
+ * order.  The format of |in| is length-prefixed and not
+ * null-terminated.  For example, ``h2`` and
+ * ``http/1.1`` stored in |in| like this::
+ *
+ *     in[0] = 2
+ *     in[1..2] = "h2"
+ *     in[3] = 8
+ *     in[4..11] = "http/1.1"
+ *     inlen = 12
+ *
+ * The selection algorithm is as follows:
+ *
+ * 1. If peer's list contains HTTP/2 protocol the library supports,
+ *    it is selected and returns 1. The following step is not taken.
+ *
+ * 2. If peer's list contains ``http/1.1``, this function selects
+ *    ``http/1.1`` and returns 0.  The following step is not taken.
+ *
+ * 3. This function selects nothing and returns -1 (So called
+ *    non-overlap case).  In this case, |out| and |outlen| are left
+ *    untouched.
+ *
+ * Selecting ``h2`` means that ``h2`` is written into |*out| and its
+ * length (which is 2) is assigned to |*outlen|.
+ *
+ * For ALPN, refer to https://tools.ietf.org/html/rfc7301
+ *
+ * See http://technotes.googlecode.com/git/nextprotoneg.html for more
+ * details about NPN.
+ *
+ * For NPN, to use this method you should do something like::
+ *
+ *     static int select_next_proto_cb(SSL* ssl,
+ *                                     unsigned char **out,
+ *                                     unsigned char *outlen,
+ *                                     const unsigned char *in,
+ *                                     unsigned int inlen,
+ *                                     void *arg)
+ *     {
+ *         int rv;
+ *         rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
+ *         if (rv == -1) {
+ *             return SSL_TLSEXT_ERR_NOACK;
+ *         }
+ *         if (rv == 1) {
+ *             ((MyType*)arg)->http2_selected = 1;
+ *         }
+ *         return SSL_TLSEXT_ERR_OK;
+ *     }
+ *     ...
+ *     SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj);
+ *
+ */
+NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
+                                                unsigned char *outlen,
+                                                const unsigned char *in,
+                                                unsigned int inlen);
+
+/**
+ * @function
+ *
+ * Returns a pointer to a nghttp2_info struct with version information
+ * about the run-time library in use.  The |least_version| argument
+ * can be set to a 24 bit numerical value for the least accepted
+ * version number and if the condition is not met, this function will
+ * return a ``NULL``.  Pass in 0 to skip the version checking.
+ */
+NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the :type:`nghttp2_error` library error code
+ * |lib_error| is fatal.
+ */
+NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error_code);
+
+/**
+ * @function
+ *
+ * Returns nonzero if HTTP header field name |name| of length |len| is
+ * valid according to http://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * Because this is a header field name in HTTP2, the upper cased alphabet
+ * is treated as error.
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if HTTP header field value |value| of length |len|
+ * is valid according to
+ * http://tools.ietf.org/html/rfc7230#section-3.2
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
+
+/* HPACK API */
+
+struct nghttp2_hd_deflater;
+
+/**
+ * @struct
+ *
+ * HPACK deflater object.
+ */
+typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
+
+/**
+ * @function
+ *
+ * Initializes |*deflater_ptr| for deflating name/values pairs.
+ *
+ * The |deflate_hd_table_bufsize_max| is the upper bound of header
+ * table size the deflater will use.
+ *
+ * If this function fails, |*deflater_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
+                                          size_t deflate_hd_table_bufsize_max);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_hd_deflate_new()`, but with additional custom memory
+ * allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_hd_deflate_new()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
+                                           size_t deflate_hd_table_bufsize_max,
+                                           nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Deallocates any resources allocated for |deflater|.
+ */
+NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
+
+/**
+ * @function
+ *
+ * Changes header table size of the |deflater| to
+ * |settings_hd_table_bufsize_max| bytes.  This may trigger eviction
+ * in the dynamic table.
+ *
+ * The |settings_hd_table_bufsize_max| should be the value received in
+ * SETTINGS_HEADER_TABLE_SIZE.
+ *
+ * The deflater never uses more memory than
+ * ``deflate_hd_table_bufsize_max`` bytes specified in
+ * `nghttp2_hd_deflate_new()`.  Therefore, if
+ * |settings_hd_table_bufsize_max| > ``deflate_hd_table_bufsize_max``,
+ * resulting maximum table size becomes
+ * ``deflate_hd_table_bufsize_max``.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
+                                     size_t settings_hd_table_bufsize_max);
+
+/**
+ * @function
+ *
+ * Deflates the |nva|, which has the |nvlen| name/value pairs, into
+ * the |buf| of length |buflen|.
+ *
+ * If |buf| is not large enough to store the deflated header block,
+ * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`.  The
+ * caller should use `nghttp2_hd_deflate_bound()` to know the upper
+ * bound of buffer size required to deflate given header name/value
+ * pairs.
+ *
+ * Once this function fails, subsequent call of this function always
+ * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ *
+ * After this function returns, it is safe to delete the |nva|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ *     Deflation process has failed.
+ * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ *     The provided |buflen| size is too small to hold the output.
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
+                      size_t buflen, const nghttp2_nv *nva, size_t nvlen);
+
+/**
+ * @function
+ *
+ * Returns an upper bound on the compressed size after deflation of
+ * |nva| of length |nvlen|.
+ */
+NGHTTP2_EXTERN size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
+                                               const nghttp2_nv *nva,
+                                               size_t nvlen);
+
+/**
+ * @function
+ *
+ * Returns the number of entries that header table of |deflater|
+ * contains.  This is the sum of the number of static table and
+ * dynamic table, so the return value is at least 61.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater);
+
+/**
+ * @function
+ *
+ * Returns the table entry denoted by |idx| from header table of
+ * |deflater|.  The |idx| is 1-based, and idx=1 returns first entry of
+ * static table.  idx=62 returns first entry of dynamic table if it
+ * exists.  Specifying idx=0 is error, and this function returns NULL.
+ * If |idx| is strictly greater than the number of entries the tables
+ * contain, this function returns NULL.
+ */
+NGHTTP2_EXTERN
+const nghttp2_nv *
+nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx);
+
+/**
+ * @function
+ *
+ * Returns the used dynamic table size, including the overhead 32
+ * bytes per entry described in RFC 7541.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater);
+
+/**
+ * @function
+ *
+ * Returns the maximum dynamic table size.
+ */
+NGHTTP2_EXTERN
+size_t
+nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater);
+
+struct nghttp2_hd_inflater;
+
+/**
+ * @struct
+ *
+ * HPACK inflater object.
+ */
+typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
+
+/**
+ * @function
+ *
+ * Initializes |*inflater_ptr| for inflating name/values pairs.
+ *
+ * If this function fails, |*inflater_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_hd_inflate_new()`, but with additional custom memory
+ * allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_hd_inflate_new()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
+                                           nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Deallocates any resources allocated for |inflater|.
+ */
+NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Changes header table size in the |inflater|.  This may trigger
+ * eviction in the dynamic table.
+ *
+ * The |settings_hd_table_bufsize_max| should be the value transmitted
+ * in SETTINGS_HEADER_TABLE_SIZE.
+ *
+ * This function must not be called while header block is being
+ * inflated.  In other words, this function must be called after
+ * initialization of |inflater|, but before calling
+ * `nghttp2_hd_inflate_hd2()`, or after
+ * `nghttp2_hd_inflate_end_headers()`.  Otherwise,
+ * `NGHTTP2_ERR_INVALID_STATE` was returned.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     The function is called while header block is being inflated.
+ *     Probably, application missed to call
+ *     `nghttp2_hd_inflate_end_headers()`.
+ */
+NGHTTP2_EXTERN int
+nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
+                                     size_t settings_hd_table_bufsize_max);
+
+/**
+ * @enum
+ *
+ * The flags for header inflation.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_HD_INFLATE_NONE = 0,
+  /**
+   * Indicates all headers were inflated.
+   */
+  NGHTTP2_HD_INFLATE_FINAL = 0x01,
+  /**
+   * Indicates a header was emitted.
+   */
+  NGHTTP2_HD_INFLATE_EMIT = 0x02
+} nghttp2_hd_inflate_flag;
+
+/**
+ * @function
+ *
+ * .. warning::
+ *
+ *   Deprecated.  Use `nghttp2_hd_inflate_hd2()` instead.
+ *
+ * Inflates name/value block stored in |in| with length |inlen|.  This
+ * function performs decompression.  For each successful emission of
+ * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * |*inflate_flags| and name/value pair is assigned to the |nv_out|
+ * and the function returns.  The caller must not free the members of
+ * |nv_out|.
+ *
+ * The |nv_out| may include pointers to the memory region in the |in|.
+ * The caller must retain the |in| while the |nv_out| is used.
+ *
+ * The application should call this function repeatedly until the
+ * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and
+ * return value is non-negative.  This means the all input values are
+ * processed successfully.  Then the application must call
+ * `nghttp2_hd_inflate_end_headers()` to prepare for the next header
+ * block input.
+ *
+ * The caller can feed complete compressed header block.  It also can
+ * feed it in several chunks.  The caller must set |in_final| to
+ * nonzero if the given input is the last block of the compressed
+ * header.
+ *
+ * This function returns the number of bytes processed if it succeeds,
+ * or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ *     Inflation process has failed.
+ * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ *     The header field name or value is too large.
+ *
+ * Example follows::
+ *
+ *     int inflate_header_block(nghttp2_hd_inflater *hd_inflater,
+ *                              uint8_t *in, size_t inlen, int final)
+ *     {
+ *         ssize_t rv;
+ *
+ *         for(;;) {
+ *             nghttp2_nv nv;
+ *             int inflate_flags = 0;
+ *
+ *             rv = nghttp2_hd_inflate_hd(hd_inflater, &nv, &inflate_flags,
+ *                                        in, inlen, final);
+ *
+ *             if(rv < 0) {
+ *                 fprintf(stderr, "inflate failed with error code %zd", rv);
+ *                 return -1;
+ *             }
+ *
+ *             in += rv;
+ *             inlen -= rv;
+ *
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
+ *                 fwrite(nv.name, nv.namelen, 1, stderr);
+ *                 fprintf(stderr, ": ");
+ *                 fwrite(nv.value, nv.valuelen, 1, stderr);
+ *                 fprintf(stderr, "\n");
+ *             }
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
+ *                 nghttp2_hd_inflate_end_headers(hd_inflater);
+ *                 break;
+ *             }
+ *             if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
+ *                inlen == 0) {
+ *                break;
+ *             }
+ *         }
+ *
+ *         return 0;
+ *     }
+ *
+ */
+NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
+                                             nghttp2_nv *nv_out,
+                                             int *inflate_flags, uint8_t *in,
+                                             size_t inlen, int in_final);
+
+/**
+ * @function
+ *
+ * Inflates name/value block stored in |in| with length |inlen|.  This
+ * function performs decompression.  For each successful emission of
+ * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * |*inflate_flags| and name/value pair is assigned to the |nv_out|
+ * and the function returns.  The caller must not free the members of
+ * |nv_out|.
+ *
+ * The |nv_out| may include pointers to the memory region in the |in|.
+ * The caller must retain the |in| while the |nv_out| is used.
+ *
+ * The application should call this function repeatedly until the
+ * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and
+ * return value is non-negative.  This means the all input values are
+ * processed successfully.  Then the application must call
+ * `nghttp2_hd_inflate_end_headers()` to prepare for the next header
+ * block input.
+ *
+ * The caller can feed complete compressed header block.  It also can
+ * feed it in several chunks.  The caller must set |in_final| to
+ * nonzero if the given input is the last block of the compressed
+ * header.
+ *
+ * This function returns the number of bytes processed if it succeeds,
+ * or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ *     Inflation process has failed.
+ * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ *     The header field name or value is too large.
+ *
+ * Example follows::
+ *
+ *     int inflate_header_block(nghttp2_hd_inflater *hd_inflater,
+ *                              uint8_t *in, size_t inlen, int final)
+ *     {
+ *         ssize_t rv;
+ *
+ *         for(;;) {
+ *             nghttp2_nv nv;
+ *             int inflate_flags = 0;
+ *
+ *             rv = nghttp2_hd_inflate_hd2(hd_inflater, &nv, &inflate_flags,
+ *                                         in, inlen, final);
+ *
+ *             if(rv < 0) {
+ *                 fprintf(stderr, "inflate failed with error code %zd", rv);
+ *                 return -1;
+ *             }
+ *
+ *             in += rv;
+ *             inlen -= rv;
+ *
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
+ *                 fwrite(nv.name, nv.namelen, 1, stderr);
+ *                 fprintf(stderr, ": ");
+ *                 fwrite(nv.value, nv.valuelen, 1, stderr);
+ *                 fprintf(stderr, "\n");
+ *             }
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
+ *                 nghttp2_hd_inflate_end_headers(hd_inflater);
+ *                 break;
+ *             }
+ *             if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
+ *                inlen == 0) {
+ *                break;
+ *             }
+ *         }
+ *
+ *         return 0;
+ *     }
+ *
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
+                       int *inflate_flags, const uint8_t *in, size_t inlen,
+                       int in_final);
+
+/**
+ * @function
+ *
+ * Signals the end of decompression for one header block.
+ *
+ * This function returns 0 if it succeeds. Currently this function
+ * always succeeds.
+ */
+NGHTTP2_EXTERN int
+nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Returns the number of entries that header table of |inflater|
+ * contains.  This is the sum of the number of static table and
+ * dynamic table, so the return value is at least 61.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Returns the table entry denoted by |idx| from header table of
+ * |inflater|.  The |idx| is 1-based, and idx=1 returns first entry of
+ * static table.  idx=62 returns first entry of dynamic table if it
+ * exists.  Specifying idx=0 is error, and this function returns NULL.
+ * If |idx| is strictly greater than the number of entries the tables
+ * contain, this function returns NULL.
+ */
+NGHTTP2_EXTERN
+const nghttp2_nv *
+nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx);
+
+/**
+ * @function
+ *
+ * Returns the used dynamic table size, including the overhead 32
+ * bytes per entry described in RFC 7541.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Returns the maximum dynamic table size.
+ */
+NGHTTP2_EXTERN
+size_t
+nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater);
+
+struct nghttp2_stream;
+
+/**
+ * @struct
+ *
+ * The structure to represent HTTP/2 stream.  The details of this
+ * structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_stream nghttp2_stream;
+
+/**
+ * @function
+ *
+ * Returns pointer to :type:`nghttp2_stream` object denoted by
+ * |stream_id|.  If stream was not found, returns NULL.
+ *
+ * Returns imaginary root stream (see
+ * `nghttp2_session_get_root_stream()`) if 0 is given in |stream_id|.
+ *
+ * Unless |stream_id| == 0, the returned pointer is valid until next
+ * call of `nghttp2_session_send()`, `nghttp2_session_mem_send()`,
+ * `nghttp2_session_recv()`, and `nghttp2_session_mem_recv()`.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_session_find_stream(nghttp2_session *session, int32_t stream_id);
+
+/**
+ * @enum
+ *
+ * State of stream as described in RFC 7540.
+ */
+typedef enum {
+  /**
+   * idle state.
+   */
+  NGHTTP2_STREAM_STATE_IDLE = 1,
+  /**
+   * open state.
+   */
+  NGHTTP2_STREAM_STATE_OPEN,
+  /**
+   * reserved (local) state.
+   */
+  NGHTTP2_STREAM_STATE_RESERVED_LOCAL,
+  /**
+   * reserved (remote) state.
+   */
+  NGHTTP2_STREAM_STATE_RESERVED_REMOTE,
+  /**
+   * half closed (local) state.
+   */
+  NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,
+  /**
+   * half closed (remote) state.
+   */
+  NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE,
+  /**
+   * closed state.
+   */
+  NGHTTP2_STREAM_STATE_CLOSED
+} nghttp2_stream_proto_state;
+
+/**
+ * @function
+ *
+ * Returns state of |stream|.  The root stream retrieved by
+ * `nghttp2_session_get_root_stream()` will have stream state
+ * :enum:`NGHTTP2_STREAM_STATE_IDLE`.
+ */
+NGHTTP2_EXTERN nghttp2_stream_proto_state
+nghttp2_stream_get_state(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns root of dependency tree, which is imaginary stream with
+ * stream ID 0.  The returned pointer is valid until |session| is
+ * freed by `nghttp2_session_del()`.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_session_get_root_stream(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the parent stream of |stream| in dependency tree.  Returns
+ * NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_parent(nghttp2_stream *stream);
+
+NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the next sibling stream of |stream| in dependency tree.
+ * Returns NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_next_sibling(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the previous sibling stream of |stream| in dependency tree.
+ * Returns NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_previous_sibling(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the first child stream of |stream| in dependency tree.
+ * Returns NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_first_child(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns dependency weight to the parent stream of |stream|.
+ */
+NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the sum of the weight for |stream|'s children.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NGHTTP2_H */

+ 42 - 0
components/nghttp/include/nghttp2/nghttp2ver.h

@@ -0,0 +1,42 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012, 2013 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.
+ */
+#ifndef NGHTTP2VER_H
+#define NGHTTP2VER_H
+
+/**
+ * @macro
+ * Version number of the nghttp2 library release
+ */
+#define NGHTTP2_VERSION "@PACKAGE_VERSION@"
+
+/**
+ * @macro
+ * Numerical representation of the version number of the nghttp2 library
+ * release. This is a 24 bit number with 8 bits for major number, 8 bits
+ * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
+ */
+#define NGHTTP2_VERSION_NUM 0x010203
+
+#endif /* NGHTTP2VER_H */

+ 388 - 0
components/nghttp/include/nghttp2_buf.h

@@ -0,0 +1,388 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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.
+ */
+#ifndef NGHTTP2_BUF_H
+#define NGHTTP2_BUF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#include "nghttp2_int.h"
+#include "nghttp2_mem.h"
+
+typedef struct {
+  /* This points to the beginning of the buffer. The effective range
+     of buffer is [begin, end). */
+  uint8_t *begin;
+  /* This points to the memory one byte beyond the end of the
+     buffer. */
+  uint8_t *end;
+  /* The position indicator for effective start of the buffer. pos <=
+     last must be hold. */
+  uint8_t *pos;
+  /* The position indicator for effective one beyond of the end of the
+     buffer. last <= end must be hold. */
+  uint8_t *last;
+  /* Mark arbitrary position in buffer [begin, end) */
+  uint8_t *mark;
+} nghttp2_buf;
+
+#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos))
+#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last))
+#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last))
+#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin))
+
+#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin))
+#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin))
+
+#define nghttp2_buf_shift_right(BUF, AMT)                                      \
+  do {                                                                         \
+    (BUF)->pos += AMT;                                                         \
+    (BUF)->last += AMT;                                                        \
+  } while (0)
+
+#define nghttp2_buf_shift_left(BUF, AMT)                                       \
+  do {                                                                         \
+    (BUF)->pos -= AMT;                                                         \
+    (BUF)->last -= AMT;                                                        \
+  } while (0)
+
+/*
+ * Initializes the |buf|. No memory is allocated in this function. Use
+ * nghttp2_buf_reserve() to allocate memory.
+ */
+void nghttp2_buf_init(nghttp2_buf *buf);
+
+/*
+ * Initializes the |buf| and allocates at least |initial| bytes of
+ * memory.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem);
+
+/*
+ * Frees buffer in |buf|.
+ */
+void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
+
+/*
+ * Extends buffer so that nghttp2_buf_cap() returns at least
+ * |new_cap|. If extensions took place, buffer pointers in |buf| will
+ * change.
+ *
+ * This function returns 0 if it succeeds, or one of the followings
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem);
+
+/*
+ * Resets pos, last, mark member of |buf| to buf->begin.
+ */
+void nghttp2_buf_reset(nghttp2_buf *buf);
+
+/*
+ * Initializes |buf| using supplied buffer |begin| of length
+ * |len|. Semantically, the application should not call *_reserve() or
+ * nghttp2_free() functions for |buf|.
+ */
+void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
+
+struct nghttp2_buf_chain;
+
+typedef struct nghttp2_buf_chain nghttp2_buf_chain;
+
+/* Chains 2 buffers */
+struct nghttp2_buf_chain {
+  /* Points to the subsequent buffer. NULL if there is no such
+     buffer. */
+  nghttp2_buf_chain *next;
+  nghttp2_buf buf;
+};
+
+typedef struct {
+  /* Points to the first buffer */
+  nghttp2_buf_chain *head;
+  /* Buffer pointer where write occurs. */
+  nghttp2_buf_chain *cur;
+  /* Memory allocator */
+  nghttp2_mem *mem;
+  /* The buffer capacity of each buf */
+  size_t chunk_length;
+  /* The maximum number of nghttp2_buf_chain */
+  size_t max_chunk;
+  /* The number of nghttp2_buf_chain allocated */
+  size_t chunk_used;
+  /* The number of nghttp2_buf_chain to keep on reset */
+  size_t chunk_keep;
+  /* pos offset from begin in each buffers. On initialization and
+     reset, buf->pos and buf->last are positioned at buf->begin +
+     offset. */
+  size_t offset;
+} nghttp2_bufs;
+
+/*
+ * This is the same as calling nghttp2_bufs_init2 with the given
+ * arguments and offset = 0.
+ */
+int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
+                      nghttp2_mem *mem);
+
+/*
+ * This is the same as calling nghttp2_bufs_init3 with the given
+ * arguments and chunk_keep = max_chunk.
+ */
+int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t offset, nghttp2_mem *mem);
+
+/*
+ * Initializes |bufs|. Each buffer size is given in the
+ * |chunk_length|.  The maximum number of buffers is given in the
+ * |max_chunk|.  On reset, first |chunk_keep| buffers are kept and
+ * remaining buffers are deleted.  Each buffer will have bufs->pos and
+ * bufs->last shifted to left by |offset| bytes on creation and reset.
+ *
+ * This function allocates first buffer.  bufs->head and bufs->cur
+ * will point to the first buffer after this call.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     chunk_keep is 0; or max_chunk < chunk_keep; or offset is too
+ *     long.
+ */
+int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t chunk_keep, size_t offset,
+                       nghttp2_mem *mem);
+
+/*
+ * Frees any related resources to the |bufs|.
+ */
+void nghttp2_bufs_free(nghttp2_bufs *bufs);
+
+/*
+ * Initializes |bufs| using supplied buffer |begin| of length |len|.
+ * The first buffer bufs->head uses buffer |begin|.  The buffer size
+ * is fixed and no allocate extra chunk buffer is allocated.  In other
+ * words, max_chunk = chunk_keep = 1.  To free the resource allocated
+ * for |bufs|, use nghttp2_bufs_wrap_free().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
+                           nghttp2_mem *mem);
+
+/*
+ * Frees any related resource to the |bufs|.  This function does not
+ * free supplied buffer provided in nghttp2_bufs_wrap_init().
+ */
+void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);
+
+/*
+ * Reallocates internal buffer using |chunk_length|.  The max_chunk,
+ * chunk_keep and offset do not change.  After successful allocation
+ * of new buffer, previous buffers are deallocated without copying
+ * anything into new buffers.  chunk_used is reset to 1.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     chunk_length < offset
+ */
+int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);
+
+/*
+ * Appends the |data| of length |len| to the |bufs|. The write starts
+ * at bufs->cur->buf.last. A new buffers will be allocated to store
+ * all data.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len);
+
+/*
+ * Appends a single byte |b| to the |bufs|. The write starts at
+ * bufs->cur->buf.last. A new buffers will be allocated to store all
+ * data.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);
+
+/*
+ * Behaves like nghttp2_bufs_addb(), but this does not update
+ * buf->last pointer.
+ */
+int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
+
+#define nghttp2_bufs_fast_addb(BUFS, B)                                        \
+  do {                                                                         \
+    *(BUFS)->cur->buf.last++ = B;                                              \
+  } while (0)
+
+#define nghttp2_bufs_fast_addb_hold(BUFS, B)                                   \
+  do {                                                                         \
+    *(BUFS)->cur->buf.last = B;                                                \
+  } while (0)
+
+/*
+ * Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
+ * will be allocated if necessary.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);
+
+/*
+ * Behaves like nghttp2_bufs_orb(), but does not update buf->last
+ * pointer.
+ */
+int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
+
+#define nghttp2_bufs_fast_orb(BUFS, B)                                         \
+  do {                                                                         \
+    uint8_t **p = &(BUFS)->cur->buf.last;                                      \
+    **p = (uint8_t)(**p | (B));                                                \
+    ++(*p);                                                                    \
+  } while (0)
+
+#define nghttp2_bufs_fast_orb_hold(BUFS, B)                                    \
+  do {                                                                         \
+    uint8_t *p = (BUFS)->cur->buf.last;                                        \
+    *p = (uint8_t)(*p | (B));                                                  \
+  } while (0)
+
+/*
+ * Copies all data stored in |bufs| to the contiguous buffer.  This
+ * function allocates the contiguous memory to store all data in
+ * |bufs| and assigns it to |*out|.
+ *
+ * The contents of |bufs| is left unchanged.
+ *
+ * This function returns the length of copied data and assigns the
+ * pointer to copied data to |*out| if it succeeds, or one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
+
+/*
+ * Copies all data stored in |bufs| to |out|.  This function assumes
+ * that the buffer space pointed by |out| has at least
+ * nghttp2_bufs(bufs) bytes.
+ *
+ * The contents of |bufs| is left unchanged.
+ *
+ * This function returns the length of copied data.
+ */
+size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
+
+/*
+ * Resets |bufs| and makes the buffers empty.
+ */
+void nghttp2_bufs_reset(nghttp2_bufs *bufs);
+
+/*
+ * Moves bufs->cur to bufs->cur->next.  If resulting bufs->cur is
+ * NULL, this function allocates new buffers and bufs->cur points to
+ * it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_advance(nghttp2_bufs *bufs);
+
+/* Sets bufs->cur to bufs->head */
+#define nghttp2_bufs_rewind(BUFS)                                              \
+  do {                                                                         \
+    (BUFS)->cur = (BUFS)->head;                                                \
+  } while (0)
+
+/*
+ * Move bufs->cur, from the current position, using next member, to
+ * the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf
+ * which satisfies nghttp2_buf_len(buf) == 0.  If
+ * nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL,
+ * bufs->cur is unchanged.
+ */
+void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
+
+/*
+ * Returns nonzero if bufs->cur->next is not emtpy.
+ */
+int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
+
+#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)
+
+/*
+ * Returns the buffer length of |bufs|.
+ */
+size_t nghttp2_bufs_len(nghttp2_bufs *bufs);
+
+#endif /* NGHTTP2_BUF_H */

+ 117 - 0
components/nghttp/include/nghttp2_callbacks.h

@@ -0,0 +1,117 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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.
+ */
+#ifndef NGHTTP2_CALLBACKS_H
+#define NGHTTP2_CALLBACKS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * Callback functions.
+ */
+struct nghttp2_session_callbacks {
+  /**
+   * Callback function invoked when the session wants to send data to
+   * the remote peer.  This callback is not necessary if the
+   * application uses solely `nghttp2_session_mem_send()` to serialize
+   * data to transmit.
+   */
+  nghttp2_send_callback send_callback;
+  /**
+   * Callback function invoked when the session wants to receive data
+   * from the remote peer.  This callback is not necessary if the
+   * application uses solely `nghttp2_session_mem_recv()` to process
+   * received data.
+   */
+  nghttp2_recv_callback recv_callback;
+  /**
+   * Callback function invoked by `nghttp2_session_recv()` when a
+   * frame is received.
+   */
+  nghttp2_on_frame_recv_callback on_frame_recv_callback;
+  /**
+   * Callback function invoked by `nghttp2_session_recv()` when an
+   * invalid non-DATA frame is received.
+   */
+  nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
+  /**
+   * Callback function invoked when a chunk of data in DATA frame is
+   * received.
+   */
+  nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
+  /**
+   * Callback function invoked before a non-DATA frame is sent.
+   */
+  nghttp2_before_frame_send_callback before_frame_send_callback;
+  /**
+   * Callback function invoked after a frame is sent.
+   */
+  nghttp2_on_frame_send_callback on_frame_send_callback;
+  /**
+   * The callback function invoked when a non-DATA frame is not sent
+   * because of an error.
+   */
+  nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
+  /**
+   * Callback function invoked when the stream is closed.
+   */
+  nghttp2_on_stream_close_callback on_stream_close_callback;
+  /**
+   * Callback function invoked when the reception of header block in
+   * HEADERS or PUSH_PROMISE is started.
+   */
+  nghttp2_on_begin_headers_callback on_begin_headers_callback;
+  /**
+   * Callback function invoked when a header name/value pair is
+   * received.
+   */
+  nghttp2_on_header_callback on_header_callback;
+  nghttp2_on_header_callback2 on_header_callback2;
+  /**
+   * Callback function invoked when the library asks application how
+   * many padding bytes are required for the transmission of the given
+   * frame.
+   */
+  nghttp2_select_padding_callback select_padding_callback;
+  /**
+   * The callback function used to determine the length allowed in
+   * `nghttp2_data_source_read_callback()`
+   */
+  nghttp2_data_source_read_length_callback read_length_callback;
+  /**
+   * Sets callback function invoked when a frame header is received.
+   */
+  nghttp2_on_begin_frame_callback on_begin_frame_callback;
+  nghttp2_send_data_callback send_data_callback;
+  nghttp2_pack_extension_callback pack_extension_callback;
+  nghttp2_unpack_extension_callback unpack_extension_callback;
+  nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
+  nghttp2_error_callback error_callback;
+};
+
+#endif /* NGHTTP2_CALLBACKS_H */

+ 581 - 0
components/nghttp/include/nghttp2_frame.h

@@ -0,0 +1,581 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_FRAME_H
+#define NGHTTP2_FRAME_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_hd.h"
+#include "nghttp2_buf.h"
+
+#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
+#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
+#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
+#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
+#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
+
+/* The number of bytes of frame header. */
+#define NGHTTP2_FRAME_HDLEN 9
+
+#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
+#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
+
+#define NGHTTP2_MAX_PAYLOADLEN 8192//16384--LiuHan/0812
+/* The one frame buffer length for tranmission.  We may use several of
+   them to support CONTINUATION.  To account for Pad Length field, we
+   allocate extra 1 byte, which saves extra large memcopying. */
+#define NGHTTP2_FRAMEBUF_CHUNKLEN                                              \
+  (NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
+
+/* The default length of DATA frame payload. */
+#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN
+
+/* Maximum headers block size to send, calculated using
+   nghttp2_hd_deflate_bound().  This is the default value, and can be
+   overridden by nghttp2_option_set_max_send_header_block_size(). */
+#define NGHTTP2_MAX_HEADERSLEN 65536
+
+/* The number of bytes for each SETTINGS entry */
+#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6
+
+/* Length of priority related fields in HEADERS/PRIORITY frames */
+#define NGHTTP2_PRIORITY_SPECLEN 5
+
+/* Maximum length of padding in bytes. */
+#define NGHTTP2_MAX_PADLEN 256
+
+/* Union of extension frame payload */
+typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
+
+void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
+
+void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
+
+/**
+ * Initializes frame header |hd| with given parameters.  Reserved bit
+ * is set to 0.
+ */
+void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
+                           uint8_t flags, int32_t stream_id);
+
+/**
+ * Returns the number of priority field depending on the |flags|.  If
+ * |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
+ * NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0.
+ */
+size_t nghttp2_frame_priority_len(uint8_t flags);
+
+/**
+ * Packs the |pri_spec| in |buf|.  This function assumes |buf| has
+ * enough space for serialization.
+ */
+void nghttp2_frame_pack_priority_spec(uint8_t *buf,
+                                      const nghttp2_priority_spec *pri_spec);
+
+/**
+ * Unpacks the priority specification from payload |payload| of length
+ * |payloadlen| to |pri_spec|.  The |flags| is used to determine what
+ * kind of priority specification is in |payload|.  This function
+ * assumes the |payload| contains whole priority specification.
+ */
+void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
+                                        uint8_t flags, const uint8_t *payload,
+                                        size_t payloadlen);
+
+/*
+ * Returns the offset from the HEADERS frame payload where the
+ * compressed header block starts. The frame payload does not include
+ * frame header.
+ */
+size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
+
+/*
+ * Packs HEADERS frame |frame| in wire format and store it in |bufs|.
+ * This function expands |bufs| as necessary to store frame.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * frame->hd.length is assigned after length is determined during
+ * packing process.  CONTINUATION frames are also serialized in this
+ * function. This function does not handle padding.
+ *
+ * This function returns 0 if it succeeds, or returns one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_HEADER_COMP
+ *     The deflate operation failed.
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
+                               nghttp2_hd_deflater *deflater);
+
+/*
+ * Unpacks HEADERS frame byte sequence into |frame|.  This function
+ * only unapcks bytes that come before name/value header block and
+ * after possible Pad Length field.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen);
+
+/*
+ * Packs PRIORITY frame |frame| in wire format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
+
+/*
+ * Unpacks PRIORITY wire format into |frame|.
+ */
+void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
+                                           const uint8_t *payload,
+                                           size_t payloadlen);
+
+/*
+ * Packs RST_STREAM frame |frame| in wire frame format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
+                                  nghttp2_rst_stream *frame);
+
+/*
+ * Unpacks RST_STREAM frame byte sequence into |frame|.
+ */
+void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
+                                             const uint8_t *payload,
+                                             size_t payloadlen);
+
+/*
+ * Packs SETTINGS frame |frame| in wire format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function returns 0 if it succeeds, or returns one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The length of the frame is too large.
+ */
+int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame);
+
+/*
+ * Packs the |iv|, which includes |niv| entries, in the |buf|,
+ * assuming the |buf| has at least 8 * |niv| bytes.
+ *
+ * Returns the number of bytes written into the |buf|.
+ */
+size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
+                                           const nghttp2_settings_entry *iv,
+                                           size_t niv);
+
+void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
+                                         const uint8_t *payload);
+
+/*
+ * Initializes payload of frame->settings.  The |frame| takes
+ * ownership of |iv|.
+ */
+void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
+                                           nghttp2_settings_entry *iv,
+                                           size_t niv);
+
+/*
+ * Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
+ * assigned to the |*niv_ptr|. This function allocates enough memory
+ * to store the result in |*iv_ptr|. The caller is responsible to free
+ * |*iv_ptr| after its use.
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
+                                           size_t *niv_ptr,
+                                           const uint8_t *payload,
+                                           size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs PUSH_PROMISE frame |frame| in wire format and store it in
+ * |bufs|.  This function expands |bufs| as necessary to store
+ * frame.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * frame->hd.length is assigned after length is determined during
+ * packing process.  CONTINUATION frames are also serialized in this
+ * function. This function does not handle padding.
+ *
+ * This function returns 0 if it succeeds, or returns one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_HEADER_COMP
+ *     The deflate operation failed.
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
+                                    nghttp2_push_promise *frame,
+                                    nghttp2_hd_deflater *deflater);
+
+/*
+ * Unpacks PUSH_PROMISE frame byte sequence into |frame|.  This
+ * function only unapcks bytes that come before name/value header
+ * block and after possible Pad Length field.
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_PROTO
+ *     TODO END_HEADERS flag is not set
+ */
+int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
+                                              const uint8_t *payload,
+                                              size_t payloadlen);
+
+/*
+ * Packs PING frame |frame| in wire format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
+
+/*
+ * Unpacks PING wire format into |frame|.
+ */
+void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
+                                       const uint8_t *payload,
+                                       size_t payloadlen);
+
+/*
+ * Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
+ * This function expands |bufs| as necessary to store frame.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The length of the frame is too large.
+ */
+int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
+
+/*
+ * Unpacks GOAWAY wire format into |frame|.  The |payload| of length
+ * |payloadlen| contains first 8 bytes of payload.  The
+ * |var_gift_payload| of length |var_gift_payloadlen| contains
+ * remaining payload and its buffer is gifted to the function and then
+ * |frame|.  The |var_gift_payloadlen| must be freed by
+ * nghttp2_frame_goaway_free().
+ */
+void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen,
+                                         uint8_t *var_gift_payload,
+                                         size_t var_gift_payloadlen);
+
+/*
+ * Unpacks GOAWAY wire format into |frame|.  This function only exists
+ * for unit test.  After allocating buffer for debug data, this
+ * function internally calls nghttp2_frame_unpack_goaway_payload().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
+ * in |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
+                                     nghttp2_window_update *frame);
+
+/*
+ * Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
+ */
+void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
+                                                const uint8_t *payload,
+                                                size_t payloadlen);
+
+/*
+ * Packs ALTSVC frame |frame| in wire frame format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
+
+/*
+ * Unpacks ALTSVC wire format into |frame|.  The |payload| of
+ * |payloadlen| bytes contains frame payload.  This function assumes
+ * that frame->payload points to the nghttp2_ext_altsvc object.
+ *
+ * This function always succeeds and returns 0.
+ */
+void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
+                                         size_t origin_len, uint8_t *payload,
+                                         size_t payloadlen);
+
+/*
+ * Unpacks ALTSVC wire format into |frame|.  This function only exists
+ * for unit test.  After allocating buffer for fields, this function
+ * internally calls nghttp2_frame_unpack_altsvc_payload().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The payload is too small.
+ */
+int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Initializes HEADERS frame |frame| with given values.  |frame| takes
+ * ownership of |nva|, so caller must not free it. If |stream_id| is
+ * not assigned yet, it must be -1.
+ */
+void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
+                                int32_t stream_id, nghttp2_headers_category cat,
+                                const nghttp2_priority_spec *pri_spec,
+                                nghttp2_nv *nva, size_t nvlen);
+
+void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem);
+
+void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
+                                 const nghttp2_priority_spec *pri_spec);
+
+void nghttp2_frame_priority_free(nghttp2_priority *frame);
+
+void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
+                                   uint32_t error_code);
+
+void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
+
+/*
+ * Initializes PUSH_PROMISE frame |frame| with given values.  |frame|
+ * takes ownership of |nva|, so caller must not free it.
+ */
+void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
+                                     int32_t stream_id,
+                                     int32_t promised_stream_id,
+                                     nghttp2_nv *nva, size_t nvlen);
+
+void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
+                                     nghttp2_mem *mem);
+
+/*
+ * Initializes SETTINGS frame |frame| with given values. |frame| takes
+ * ownership of |iv|, so caller must not free it. The |flags| are
+ * bitwise-OR of one or more of nghttp2_settings_flag.
+ */
+void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
+                                 nghttp2_settings_entry *iv, size_t niv);
+
+void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem);
+
+/*
+ * Initializes PING frame |frame| with given values. If the
+ * |opqeue_data| is not NULL, it must point to 8 bytes memory region
+ * of data. The data pointed by |opaque_data| is copied. It can be
+ * NULL. In this case, 8 bytes NULL is used.
+ */
+void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
+                             const uint8_t *opque_data);
+
+void nghttp2_frame_ping_free(nghttp2_ping *frame);
+
+/*
+ * Initializes GOAWAY frame |frame| with given values. On success,
+ * this function takes ownership of |opaque_data|, so caller must not
+ * free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
+ */
+void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
+                               uint32_t error_code, uint8_t *opaque_data,
+                               size_t opaque_data_len);
+
+void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem);
+
+void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
+                                      uint8_t flags, int32_t stream_id,
+                                      int32_t window_size_increment);
+
+void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
+
+void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
+                                  uint8_t flags, int32_t stream_id,
+                                  void *payload);
+
+void nghttp2_frame_extension_free(nghttp2_extension *frame);
+
+/*
+ * Initializes ALTSVC frame |frame| with given values.  This function
+ * assumes that frame->payload points to nghttp2_ext_altsvc object.
+ * Also |origin| and |field_value| are allocated in single buffer,
+ * starting |origin|.  On success, this function takes ownership of
+ * |origin|, so caller must not free it.
+ */
+void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
+                               uint8_t *origin, size_t origin_len,
+                               uint8_t *field_value, size_t field_value_len);
+
+/*
+ * Frees up resources under |frame|.  This function does not free
+ * nghttp2_ext_altsvc object pointed by frame->payload.  This function
+ * only frees origin pointed by nghttp2_ext_altsvc.origin.  Therefore,
+ * other fields must be allocated in the same buffer with origin.
+ */
+void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
+
+/*
+ * Returns the number of padding bytes after payload.  The total
+ * padding length is given in the |padlen|.  The returned value does
+ * not include the Pad Length field.  If |padlen| is 0, this function
+ * returns 0, regardless of frame->hd.flags.
+ */
+size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
+
+void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
+                             int32_t stream_id);
+
+void nghttp2_frame_data_free(nghttp2_data *frame);
+
+/*
+ * Makes copy of |iv| and return the copy. The |niv| is the number of
+ * entries in |iv|. This function returns the pointer to the copy if
+ * it succeeds, or NULL.
+ */
+nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
+                                              size_t niv, nghttp2_mem *mem);
+
+/*
+ * Sorts the |nva| in ascending order of name and value. If names are
+ * equivalent, sort them by value.
+ */
+void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
+
+/*
+ * Copies name/value pairs from |nva|, which contains |nvlen| pairs,
+ * to |*nva_ptr|, which is dynamically allocated so that all items can
+ * be stored.  The resultant name and value in nghttp2_nv are
+ * guaranteed to be NULL-terminated even if the input is not
+ * null-terminated.
+ *
+ * The |*nva_ptr| must be freed using nghttp2_nv_array_del().
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
+                          size_t nvlen, nghttp2_mem *mem);
+
+/*
+ * Returns nonzero if the name/value pair |a| equals to |b|. The name
+ * is compared in case-sensitive, because we ensure that this function
+ * is called after the name is lower-cased.
+ */
+int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
+
+/*
+ * Frees |nva|.
+ */
+void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem);
+
+/*
+ * Checks that the |iv|, which includes |niv| entries, does not have
+ * invalid values.
+ *
+ * This function returns nonzero if it succeeds, or 0.
+ */
+int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
+
+/*
+ * Sets Pad Length field and flags and adjusts frame header position
+ * of each buffers in |bufs|.  The number of padding is given in the
+ * |padlen| including Pad Length field.  The |hd| is the frame header
+ * for the serialized data.  This function fills zeros padding region
+ * unless framehd_only is nonzero.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The length of the resulting frame is too large.
+ */
+int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
+                          size_t padlen, int framehd_only);
+
+#endif /* NGHTTP2_FRAME_H */

+ 430 - 0
components/nghttp/include/nghttp2_hd.h

@@ -0,0 +1,430 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013 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.
+ */
+#ifndef NGHTTP2_HD_H
+#define NGHTTP2_HD_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#include "nghttp2_hd_huffman.h"
+#include "nghttp2_buf.h"
+#include "nghttp2_mem.h"
+#include "nghttp2_rcbuf.h"
+
+#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
+#define NGHTTP2_HD_ENTRY_OVERHEAD 32
+
+/* The maximum length of one name/value pair.  This is the sum of the
+   length of name and value.  This is not specified by the spec. We
+   just chose the arbitrary size */
+#define NGHTTP2_HD_MAX_NV 65536
+
+/* Default size of maximum table buffer size for encoder. Even if
+   remote decoder notifies larger buffer size for its decoding,
+   encoder only uses the memory up to this value. */
+#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
+
+/* Exported for unit test */
+#define NGHTTP2_STATIC_TABLE_LENGTH 61
+
+/* Generated by genlibtokenlookup.py */
+typedef enum {
+  NGHTTP2_TOKEN__AUTHORITY = 0,
+  NGHTTP2_TOKEN__METHOD = 1,
+  NGHTTP2_TOKEN__PATH = 3,
+  NGHTTP2_TOKEN__SCHEME = 5,
+  NGHTTP2_TOKEN__STATUS = 7,
+  NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
+  NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
+  NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
+  NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
+  NGHTTP2_TOKEN_ACCEPT = 18,
+  NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
+  NGHTTP2_TOKEN_AGE = 20,
+  NGHTTP2_TOKEN_ALLOW = 21,
+  NGHTTP2_TOKEN_AUTHORIZATION = 22,
+  NGHTTP2_TOKEN_CACHE_CONTROL = 23,
+  NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
+  NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
+  NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
+  NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
+  NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
+  NGHTTP2_TOKEN_CONTENT_RANGE = 29,
+  NGHTTP2_TOKEN_CONTENT_TYPE = 30,
+  NGHTTP2_TOKEN_COOKIE = 31,
+  NGHTTP2_TOKEN_DATE = 32,
+  NGHTTP2_TOKEN_ETAG = 33,
+  NGHTTP2_TOKEN_EXPECT = 34,
+  NGHTTP2_TOKEN_EXPIRES = 35,
+  NGHTTP2_TOKEN_FROM = 36,
+  NGHTTP2_TOKEN_HOST = 37,
+  NGHTTP2_TOKEN_IF_MATCH = 38,
+  NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
+  NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
+  NGHTTP2_TOKEN_IF_RANGE = 41,
+  NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
+  NGHTTP2_TOKEN_LAST_MODIFIED = 43,
+  NGHTTP2_TOKEN_LINK = 44,
+  NGHTTP2_TOKEN_LOCATION = 45,
+  NGHTTP2_TOKEN_MAX_FORWARDS = 46,
+  NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
+  NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
+  NGHTTP2_TOKEN_RANGE = 49,
+  NGHTTP2_TOKEN_REFERER = 50,
+  NGHTTP2_TOKEN_REFRESH = 51,
+  NGHTTP2_TOKEN_RETRY_AFTER = 52,
+  NGHTTP2_TOKEN_SERVER = 53,
+  NGHTTP2_TOKEN_SET_COOKIE = 54,
+  NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
+  NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
+  NGHTTP2_TOKEN_USER_AGENT = 57,
+  NGHTTP2_TOKEN_VARY = 58,
+  NGHTTP2_TOKEN_VIA = 59,
+  NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
+  NGHTTP2_TOKEN_TE,
+  NGHTTP2_TOKEN_CONNECTION,
+  NGHTTP2_TOKEN_KEEP_ALIVE,
+  NGHTTP2_TOKEN_PROXY_CONNECTION,
+  NGHTTP2_TOKEN_UPGRADE,
+} nghttp2_token;
+
+struct nghttp2_hd_entry;
+typedef struct nghttp2_hd_entry nghttp2_hd_entry;
+
+typedef struct {
+  /* The buffer containing header field name.  NULL-termination is
+     guaranteed. */
+  nghttp2_rcbuf *name;
+  /* The buffer containing header field value.  NULL-termination is
+     guaranteed. */
+  nghttp2_rcbuf *value;
+  /* nghttp2_token value for name.  It could be -1 if we have no token
+     for that header field name. */
+  int32_t token;
+  /* Bitwise OR of one or more of nghttp2_nv_flag. */
+  uint8_t flags;
+} nghttp2_hd_nv;
+
+struct nghttp2_hd_entry {
+  /* The header field name/value pair */
+  nghttp2_hd_nv nv;
+  /* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry
+     APIs to keep backward compatibility. */
+  nghttp2_nv cnv;
+  /* The next entry which shares same bucket in hash table. */
+  nghttp2_hd_entry *next;
+  /* The sequence number.  We will increment it by one whenever we
+     store nghttp2_hd_entry to dynamic header table. */
+  uint32_t seq;
+  /* The hash value for header name (nv.name). */
+  uint32_t hash;
+};
+
+/* The entry used for static header table. */
+typedef struct {
+  nghttp2_rcbuf name;
+  nghttp2_rcbuf value;
+  nghttp2_nv cnv;
+  int32_t token;
+  uint32_t hash;
+} nghttp2_hd_static_entry;
+
+typedef struct {
+  nghttp2_hd_entry **buffer;
+  size_t mask;
+  size_t first;
+  size_t len;
+} nghttp2_hd_ringbuf;
+
+typedef enum {
+  NGHTTP2_HD_OPCODE_NONE,
+  NGHTTP2_HD_OPCODE_INDEXED,
+  NGHTTP2_HD_OPCODE_NEWNAME,
+  NGHTTP2_HD_OPCODE_INDNAME
+} nghttp2_hd_opcode;
+
+typedef enum {
+  NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE,
+  NGHTTP2_HD_STATE_INFLATE_START,
+  NGHTTP2_HD_STATE_OPCODE,
+  NGHTTP2_HD_STATE_READ_TABLE_SIZE,
+  NGHTTP2_HD_STATE_READ_INDEX,
+  NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
+  NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
+  NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF,
+  NGHTTP2_HD_STATE_NEWNAME_READ_NAME,
+  NGHTTP2_HD_STATE_CHECK_VALUELEN,
+  NGHTTP2_HD_STATE_READ_VALUELEN,
+  NGHTTP2_HD_STATE_READ_VALUEHUFF,
+  NGHTTP2_HD_STATE_READ_VALUE
+} nghttp2_hd_inflate_state;
+
+typedef enum {
+  NGHTTP2_HD_WITH_INDEXING,
+  NGHTTP2_HD_WITHOUT_INDEXING,
+  NGHTTP2_HD_NEVER_INDEXING
+} nghttp2_hd_indexing_mode;
+
+typedef struct {
+  /* dynamic header table */
+  nghttp2_hd_ringbuf hd_table;
+  /* Memory allocator */
+  nghttp2_mem *mem;
+  /* Abstract buffer size of hd_table as described in the spec. This
+     is the sum of length of name/value in hd_table +
+     NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
+  size_t hd_table_bufsize;
+  /* The effective header table size. */
+  size_t hd_table_bufsize_max;
+  /* Next sequence number for nghttp2_hd_entry */
+  uint32_t next_seq;
+  /* If inflate/deflate error occurred, this value is set to 1 and
+     further invocation of inflate/deflate will fail with
+     NGHTTP2_ERR_HEADER_COMP. */
+  uint8_t bad;
+} nghttp2_hd_context;
+
+#define HD_MAP_SIZE 128
+
+typedef struct { nghttp2_hd_entry *table[HD_MAP_SIZE]; } nghttp2_hd_map;
+
+struct nghttp2_hd_deflater {
+  nghttp2_hd_context ctx;
+  nghttp2_hd_map map;
+  /* The upper limit of the header table size the deflater accepts. */
+  size_t deflate_hd_table_bufsize_max;
+  /* Minimum header table size notified in the next context update */
+  size_t min_hd_table_bufsize_max;
+  /* If nonzero, send header table size using encoding context update
+     in the next deflate process */
+  uint8_t notify_table_size_change;
+};
+
+struct nghttp2_hd_inflater {
+  nghttp2_hd_context ctx;
+  /* Stores current state of huffman decoding */
+  nghttp2_hd_huff_decode_context huff_decode_ctx;
+  /* header buffer */
+  nghttp2_buf namebuf, valuebuf;
+  nghttp2_rcbuf *namercbuf, *valuercbuf;
+  /* Pointer to the name/value pair which are used in the current
+     header emission. */
+  nghttp2_rcbuf *nv_name_keep, *nv_value_keep;
+  /* The number of bytes to read */
+  size_t left;
+  /* The index in indexed repr or indexed name */
+  size_t index;
+  /* The maximum header table size the inflater supports. This is the
+     same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
+  size_t settings_hd_table_bufsize_max;
+  /* Minimum header table size set by nghttp2_hd_inflate_change_table_size */
+  size_t min_hd_table_bufsize_max;
+  /* The number of next shift to decode integer */
+  size_t shift;
+  nghttp2_hd_opcode opcode;
+  nghttp2_hd_inflate_state state;
+  /* nonzero if string is huffman encoded */
+  uint8_t huffman_encoded;
+  /* nonzero if deflater requires that current entry is indexed */
+  uint8_t index_required;
+  /* nonzero if deflater requires that current entry must not be
+     indexed */
+  uint8_t no_index;
+};
+
+/*
+ * Initializes the |ent| members.  The reference counts of nv->name
+ * and nv->value are increased by one for each.
+ */
+void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv);
+
+/*
+ * This function decreases the reference counts of nv->name and
+ * nv->value.
+ */
+void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
+
+/*
+ * Initializes |deflater| for deflating name/values pairs.
+ *
+ * The encoder only uses up to
+ * NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table
+ * even if the larger value is specified later in
+ * nghttp2_hd_change_table_size().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
+
+/*
+ * Initializes |deflater| for deflating name/values pairs.
+ *
+ * The encoder only uses up to |deflate_hd_table_bufsize_max| bytes
+ * for header table even if the larger value is specified later in
+ * nghttp2_hd_change_table_size().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
+                             size_t deflate_hd_table_bufsize_max,
+                             nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |deflater|.
+ */
+void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
+
+/*
+ * Deflates the |nva|, which has the |nvlen| name/value pairs, into
+ * the |bufs|.
+ *
+ * This function expands |bufs| as necessary to store the result. If
+ * buffers is full and the process still requires more space, this
+ * funtion fails and returns NGHTTP2_ERR_HEADER_COMP.
+ *
+ * After this function returns, it is safe to delete the |nva|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_HEADER_COMP
+ *     Deflation process has failed.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
+                               nghttp2_bufs *bufs, const nghttp2_nv *nva,
+                               size_t nvlen);
+
+/*
+ * Initializes |inflater| for inflating name/values pairs.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |inflater|.
+ */
+void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
+
+/*
+ * Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv
+ * instead of nghttp2_nv as output parameter |nv_out|.  Other than
+ * that return values and semantics are the same as
+ * nghttp2_hd_inflate_hd().
+ */
+ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
+                                 nghttp2_hd_nv *nv_out, int *inflate_flags,
+                                 const uint8_t *in, size_t inlen, int in_final);
+
+/* For unittesting purpose */
+int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
+                                  nghttp2_nv *nv, int indexing_mode);
+
+/* For unittesting purpose */
+int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
+                                  int indexing_mode);
+
+/* For unittesting purpose */
+int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
+
+/* For unittesting purpose */
+nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
+
+/* For unittesting purpose */
+ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final,
+                                 uint32_t initial, size_t shift, uint8_t *in,
+                                 uint8_t *last, size_t prefix);
+
+/* Huffman encoding/decoding functions */
+
+/*
+ * Counts the required bytes to encode |src| with length |len|.
+ *
+ * This function returns the number of required bytes to encode given
+ * data, including padding of prefix of terminal symbol code. This
+ * function always succeeds.
+ */
+size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
+
+/*
+ * Encodes the given data |src| with length |srclen| to the |bufs|.
+ * This function expands extra buffers in |bufs| if necessary.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
+                           size_t srclen);
+
+void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
+
+/*
+ * Decodes the given data |src| with length |srclen|.  The |ctx| must
+ * be initialized by nghttp2_hd_huff_decode_context_init(). The result
+ * will be written to |buf|.  This function assumes that |buf| has the
+ * enough room to store the decoded byte string.
+ *
+ * The caller must set the |final| to nonzero if the given input is
+ * the final block.
+ *
+ * This function returns the number of read bytes from the |in|.
+ *
+ * If this function fails, it returns one of the following negative
+ * return codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_HEADER_COMP
+ *     Decoding process has failed.
+ */
+ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
+                               nghttp2_buf *buf, const uint8_t *src,
+                               size_t srclen, int final);
+
+#endif /* NGHTTP2_HD_H */

+ 77 - 0
components/nghttp/include/nghttp2_hd_huffman.h

@@ -0,0 +1,77 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013 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.
+ */
+#ifndef NGHTTP2_HD_HUFFMAN_H
+#define NGHTTP2_HD_HUFFMAN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+typedef enum {
+  /* FSA accepts this state as the end of huffman encoding
+     sequence. */
+  NGHTTP2_HUFF_ACCEPTED = 1,
+  /* This state emits symbol */
+  NGHTTP2_HUFF_SYM = (1 << 1),
+  /* If state machine reaches this state, decoding fails. */
+  NGHTTP2_HUFF_FAIL = (1 << 2)
+} nghttp2_huff_decode_flag;
+
+typedef struct {
+  /* huffman decoding state, which is actually the node ID of internal
+     huffman tree.  We have 257 leaf nodes, but they are identical to
+     root node other than emitting a symbol, so we have 256 internal
+     nodes [1..255], inclusive. */
+  uint8_t state;
+  /* bitwise OR of zero or more of the nghttp2_huff_decode_flag */
+  uint8_t flags;
+  /* symbol if NGHTTP2_HUFF_SYM flag set */
+  uint8_t sym;
+} nghttp2_huff_decode;
+
+typedef nghttp2_huff_decode huff_decode_table_type[16];
+
+typedef struct {
+  /* Current huffman decoding state. We stripped leaf nodes, so the
+     value range is [0..255], inclusive. */
+  uint8_t state;
+  /* nonzero if we can say that the decoding process succeeds at this
+     state */
+  uint8_t accept;
+} nghttp2_hd_huff_decode_context;
+
+typedef struct {
+  /* The number of bits in this code */
+  uint32_t nbits;
+  /* Huffman code aligned to LSB */
+  uint32_t code;
+} nghttp2_huff_sym;
+
+extern const nghttp2_huff_sym huff_sym_table[];
+extern const nghttp2_huff_decode huff_decode_table[][16];
+
+#endif /* NGHTTP2_HD_HUFFMAN_H */

+ 122 - 0
components/nghttp/include/nghttp2_helper.h

@@ -0,0 +1,122 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_HELPER_H
+#define NGHTTP2_HELPER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stddef.h>
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_mem.h"
+
+#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
+#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
+
+#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
+
+#define nghttp2_struct_of(ptr, type, member)                                   \
+  ((type *)(void *)((char *)(ptr)-offsetof(type, member)))
+
+/*
+ * Copies 2 byte unsigned integer |n| in host byte order to |buf| in
+ * network byte order.
+ */
+void nghttp2_put_uint16be(uint8_t *buf, uint16_t n);
+
+/*
+ * Copies 4 byte unsigned integer |n| in host byte order to |buf| in
+ * network byte order.
+ */
+void nghttp2_put_uint32be(uint8_t *buf, uint32_t n);
+
+/*
+ * Retrieves 2 byte unsigned integer stored in |data| in network byte
+ * order and returns it in host byte order.
+ */
+uint16_t nghttp2_get_uint16(const uint8_t *data);
+
+/*
+ * Retrieves 4 byte unsigned integer stored in |data| in network byte
+ * order and returns it in host byte order.
+ */
+uint32_t nghttp2_get_uint32(const uint8_t *data);
+
+void nghttp2_downcase(uint8_t *s, size_t len);
+
+/*
+ * Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|,
+ * |*recv_reduction_ptr| with |*delta_ptr| which is the
+ * WINDOW_UPDATE's window_size_increment sent from local side. If
+ * |delta| is strictly larger than |*recv_window_size_ptr|,
+ * |*local_window_size_ptr| is increased by delta -
+ * *recv_window_size_ptr. If |delta| is negative,
+ * |*local_window_size_ptr| is decreased by delta.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_FLOW_CONTROL
+ *     local_window_size overflow or gets negative.
+ */
+int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
+                                     int32_t *recv_window_size_ptr,
+                                     int32_t *recv_reduction_ptr,
+                                     int32_t *delta_ptr);
+
+/*
+ * This function works like nghttp2_adjust_local_window_size().  The
+ * difference is that this function assumes *delta_ptr >= 0, and
+ * *recv_window_size_ptr is not decreased by *delta_ptr.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_FLOW_CONTROL
+ *     local_window_size overflow or gets negative.
+ */
+int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
+                                       int32_t *recv_window_size_ptr,
+                                       int32_t *recv_reduction_ptr,
+                                       int32_t *delta_ptr);
+
+/*
+ * Returns non-zero if the function decided that WINDOW_UPDATE should
+ * be sent.
+ */
+int nghttp2_should_send_window_update(int32_t local_window_size,
+                                      int32_t recv_window_size);
+
+/*
+ * Copies the buffer |src| of length |len| to the destination pointed
+ * by the |dest|, assuming that the |dest| is at lest |len| bytes long
+ * . Returns dest + len.
+ */
+uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
+
+#endif /* NGHTTP2_HELPER_H */

+ 97 - 0
components/nghttp/include/nghttp2_http.h

@@ -0,0 +1,97 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2015 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.
+ */
+#ifndef NGHTTP2_HTTP_H
+#define NGHTTP2_HTTP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_session.h"
+#include "nghttp2_stream.h"
+
+/*
+ * This function is called when HTTP header field |nv| in |frame| is
+ * received for |stream|.  This function will validate |nv| against
+ * the current state of stream.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_HTTP_HEADER
+ *     Invalid HTTP header field was received.
+ * NGHTTP2_ERR_IGN_HTTP_HEADER
+ *     Invalid HTTP header field was received but it can be treated as
+ *     if it was not received because of compatibility reasons.
+ */
+int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
+                           nghttp2_frame *frame, nghttp2_hd_nv *nv,
+                           int trailer);
+
+/*
+ * This function is called when request header is received.  This
+ * function performs validation and returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_request_headers(nghttp2_stream *stream,
+                                    nghttp2_frame *frame);
+
+/*
+ * This function is called when response header is received.  This
+ * function performs validation and returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_response_headers(nghttp2_stream *stream);
+
+/*
+ * This function is called trailer header (for both request and
+ * response) is received.  This function performs validation and
+ * returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
+                                    nghttp2_frame *frame);
+
+/*
+ * This function is called when END_STREAM flag is seen in incoming
+ * frame.  This function performs validation and returns 0 if it
+ * succeeds, or -1.
+ */
+int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream);
+
+/*
+ * This function is called when chunk of data is received.  This
+ * function performs validation and returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
+
+/*
+ * This function inspects header field in |frame| and records its
+ * method in stream->http_flags.  If frame->hd.type is neither
+ * NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does
+ * nothing.
+ */
+void nghttp2_http_record_request_method(nghttp2_stream *stream,
+                                        nghttp2_frame *frame);
+
+#endif /* NGHTTP2_HTTP_H */

+ 58 - 0
components/nghttp/include/nghttp2_int.h

@@ -0,0 +1,58 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_INT_H
+#define NGHTTP2_INT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+/* Macros, types and constants for internal use */
+
+#ifdef DEBUGBUILD
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x)                                                              \
+  do {                                                                         \
+  } while (0)
+#endif
+
+/* "less" function, return nonzero if |lhs| is less than |rhs|. */
+typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
+
+/* Internal error code. They must be in the range [-499, -100],
+   inclusive. */
+typedef enum {
+  NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
+  NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
+  NGHTTP2_ERR_IGN_PAYLOAD = -104,
+  /*
+   * Invalid HTTP header field was received but it can be treated as
+   * if it was not received because of compatibility reasons.
+   */
+  NGHTTP2_ERR_IGN_HTTP_HEADER = -105
+} nghttp2_internal_error;
+
+#endif /* NGHTTP2_INT_H */

+ 144 - 0
components/nghttp/include/nghttp2_map.h

@@ -0,0 +1,144 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_MAP_H
+#define NGHTTP2_MAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_int.h"
+#include "nghttp2_mem.h"
+
+/* Implementation of unordered map */
+
+typedef int32_t key_type;
+
+typedef struct nghttp2_map_entry {
+  struct nghttp2_map_entry *next;
+  key_type key;
+#if SIZEOF_INT_P == 4
+  /* we requires 8 bytes aligment */
+  int64_t pad;
+#endif
+} nghttp2_map_entry;
+
+typedef struct {
+  nghttp2_map_entry **table;
+  nghttp2_mem *mem;
+  size_t size;
+  uint32_t tablelen;
+} nghttp2_map;
+
+/*
+ * Initializes the map |map|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *   Out of memory
+ */
+int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |map|. The stored entries
+ * are not freed by this function. Use nghttp2_map_each_free() to free
+ * each entries.
+ */
+void nghttp2_map_free(nghttp2_map *map);
+
+/*
+ * Deallocates each entries using |func| function and any resources
+ * allocated for |map|. The |func| function is responsible for freeing
+ * given the |entry| object. The |ptr| will be passed to the |func| as
+ * send argument. The return value of the |func| will be ignored.
+ */
+void nghttp2_map_each_free(nghttp2_map *map,
+                           int (*func)(nghttp2_map_entry *entry, void *ptr),
+                           void *ptr);
+
+/*
+ * Initializes the |entry| with the |key|. All entries to be inserted
+ * to the map must be initialized with this function.
+ */
+void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
+
+/*
+ * Inserts the new |entry| with the key |entry->key| to the map |map|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The item associated by |key| already exists.
+ * NGHTTP2_ERR_NOMEM
+ *   Out of memory
+ */
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
+
+/*
+ * Returns the entry associated by the key |key|.  If there is no such
+ * entry, this function returns NULL.
+ */
+nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
+
+/*
+ * Removes the entry associated by the key |key| from the |map|.  The
+ * removed entry is not freed by this function.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The entry associated by |key| does not exist.
+ */
+int nghttp2_map_remove(nghttp2_map *map, key_type key);
+
+/*
+ * Returns the number of items stored in the map |map|.
+ */
+size_t nghttp2_map_size(nghttp2_map *map);
+
+/*
+ * Applies the function |func| to each entry in the |map| with the
+ * optional user supplied pointer |ptr|.
+ *
+ * If the |func| returns 0, this function calls the |func| with the
+ * next entry. If the |func| returns nonzero, it will not call the
+ * |func| for further entries and return the return value of the
+ * |func| immediately.  Thus, this function returns 0 if all the
+ * invocations of the |func| return 0, or nonzero value which the last
+ * invocation of |func| returns.
+ *
+ * Don't use this function to free each entry. Use
+ * nghttp2_map_each_free() instead.
+ */
+int nghttp2_map_each(nghttp2_map *map,
+                     int (*func)(nghttp2_map_entry *entry, void *ptr),
+                     void *ptr);
+
+#endif /* NGHTTP2_MAP_H */

+ 45 - 0
components/nghttp/include/nghttp2_mem.h

@@ -0,0 +1,45 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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.
+ */
+#ifndef NGHTTP2_MEM_H
+#define NGHTTP2_MEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/* The default, system standard memory allocator */
+nghttp2_mem *nghttp2_mem_default(void);
+
+/* Convenient wrapper functions to call allocator function in
+   |mem|. */
+void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size);
+void nghttp2_mem_free(nghttp2_mem *mem, void *ptr);
+void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data);
+void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size);
+void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size);
+
+#endif /* NGHTTP2_MEM_H */

+ 91 - 0
components/nghttp/include/nghttp2_net.h

@@ -0,0 +1,91 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_NET_H
+#define NGHTTP2_NET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif /* HAVE_ARPA_INET_H */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+
+#include <nghttp2/nghttp2.h>
+
+#if defined(WIN32)
+/* Windows requires ws2_32 library for ntonl family functions.  We
+   define inline functions for those function so that we don't have
+   dependeny on that lib. */
+
+#ifdef _MSC_VER
+#define STIN static __inline
+#else
+#define STIN static inline
+#endif
+
+STIN uint32_t htonl(uint32_t hostlong) {
+  uint32_t res;
+  unsigned char *p = (unsigned char *)&res;
+  *p++ = hostlong >> 24;
+  *p++ = (hostlong >> 16) & 0xffu;
+  *p++ = (hostlong >> 8) & 0xffu;
+  *p = hostlong & 0xffu;
+  return res;
+}
+
+STIN uint16_t htons(uint16_t hostshort) {
+  uint16_t res;
+  unsigned char *p = (unsigned char *)&res;
+  *p++ = hostshort >> 8;
+  *p = hostshort & 0xffu;
+  return res;
+}
+
+STIN uint32_t ntohl(uint32_t netlong) {
+  uint32_t res;
+  unsigned char *p = (unsigned char *)&netlong;
+  res = *p++ << 24;
+  res += *p++ << 16;
+  res += *p++ << 8;
+  res += *p;
+  return res;
+}
+
+STIN uint16_t ntohs(uint16_t netshort) {
+  uint16_t res;
+  unsigned char *p = (unsigned char *)&netshort;
+  res = *p++ << 8;
+  res += *p;
+  return res;
+}
+
+#endif /* WIN32 */
+
+#endif /* NGHTTP2_NET_H */

+ 34 - 0
components/nghttp/include/nghttp2_npn.h

@@ -0,0 +1,34 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_NPN_H
+#define NGHTTP2_NPN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#endif /* NGHTTP2_NPN_H */

+ 116 - 0
components/nghttp/include/nghttp2_option.h

@@ -0,0 +1,116 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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.
+ */
+#ifndef NGHTTP2_OPTION_H
+#define NGHTTP2_OPTION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/**
+ * Configuration options
+ */
+typedef enum {
+  /**
+   * This option prevents the library from sending WINDOW_UPDATE for a
+   * connection automatically.  If this option is set to nonzero, the
+   * library won't send WINDOW_UPDATE for DATA until application calls
+   * nghttp2_session_consume() to indicate the amount of consumed
+   * DATA.  By default, this option is set to zero.
+   */
+  NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
+  /**
+   * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
+   * remote endpoint as if it is received in SETTINGS frame. Without
+   * specifying this option, before the local endpoint receives
+   * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
+   * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
+   * cause problem if local endpoint submits lots of requests
+   * initially and sending them at once to the remote peer may lead to
+   * the rejection of some requests. Specifying this option to the
+   * sensible value, say 100, may avoid this kind of issue. This value
+   * will be overwritten if the local endpoint receives
+   * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
+   */
+  NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
+  NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
+  NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
+  NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
+  NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
+  NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
+  NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
+  NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
+} nghttp2_option_flag;
+
+/**
+ * Struct to store option values for nghttp2_session.
+ */
+struct nghttp2_option {
+  /**
+   * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
+   */
+  size_t max_send_header_block_length;
+  /**
+   * Bitwise OR of nghttp2_option_flag to determine that which fields
+   * are specified.
+   */
+  uint32_t opt_set_mask;
+  /**
+   * NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
+   */
+  uint32_t peer_max_concurrent_streams;
+  /**
+   * NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS
+   */
+  uint32_t max_reserved_remote_streams;
+  /**
+   * NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES
+   */
+  uint32_t builtin_recv_ext_types;
+  /**
+   * NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
+   */
+  int no_auto_window_update;
+  /**
+   * NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC
+   */
+  int no_recv_client_magic;
+  /**
+   * NGHTTP2_OPT_NO_HTTP_MESSAGING
+   */
+  int no_http_messaging;
+  /**
+   * NGHTTP2_OPT_NO_AUTO_PING_ACK
+   */
+  int no_auto_ping_ack;
+  /**
+   * NGHTTP2_OPT_USER_RECV_EXT_TYPES
+   */
+  uint8_t user_recv_ext_types[32];
+};
+
+#endif /* NGHTTP2_OPTION_H */

+ 166 - 0
components/nghttp/include/nghttp2_outbound_item.h

@@ -0,0 +1,166 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_OUTBOUND_ITEM_H
+#define NGHTTP2_OUTBOUND_ITEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_frame.h"
+#include "nghttp2_mem.h"
+
+/* struct used for HEADERS and PUSH_PROMISE frame */
+typedef struct {
+  nghttp2_data_provider data_prd;
+  void *stream_user_data;
+  /* error code when request HEADERS is canceled by RST_STREAM while
+     it is in queue. */
+  uint32_t error_code;
+  /* nonzero if request HEADERS is canceled.  The error code is stored
+     in |error_code|. */
+  uint8_t canceled;
+} nghttp2_headers_aux_data;
+
+/* struct used for DATA frame */
+typedef struct {
+  /**
+   * The data to be sent for this DATA frame.
+   */
+  nghttp2_data_provider data_prd;
+  /**
+   * The flags of DATA frame.  We use separate flags here and
+   * nghttp2_data frame.  The latter contains flags actually sent to
+   * peer.  This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
+   * when |eof| becomes nonzero, flags in nghttp2_data has
+   * NGHTTP2_FLAG_END_STREAM set.
+   */
+  uint8_t flags;
+  /**
+   * The flag to indicate whether EOF was reached or not. Initially
+   * |eof| is 0. It becomes 1 after all data were read.
+   */
+  uint8_t eof;
+  /**
+   * The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
+   */
+  uint8_t no_copy;
+} nghttp2_data_aux_data;
+
+typedef enum {
+  NGHTTP2_GOAWAY_AUX_NONE = 0x0,
+  /* indicates that session should be terminated after the
+     transmission of this frame. */
+  NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1,
+  /* indicates that this GOAWAY is just a notification for graceful
+     shutdown.  No nghttp2_session.goaway_flags should be updated on
+     the reaction to this frame. */
+  NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
+} nghttp2_goaway_aux_flag;
+
+/* struct used for GOAWAY frame */
+typedef struct {
+  /* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */
+  uint8_t flags;
+} nghttp2_goaway_aux_data;
+
+/* struct used for extension frame */
+typedef struct {
+  /* nonzero if this extension frame is serialized by library
+     function, instead of user-defined callbacks. */
+  uint8_t builtin;
+} nghttp2_ext_aux_data;
+
+/* Additional data which cannot be stored in nghttp2_frame struct */
+typedef union {
+  nghttp2_data_aux_data data;
+  nghttp2_headers_aux_data headers;
+  nghttp2_goaway_aux_data goaway;
+  nghttp2_ext_aux_data ext;
+} nghttp2_aux_data;
+
+struct nghttp2_outbound_item;
+typedef struct nghttp2_outbound_item nghttp2_outbound_item;
+
+struct nghttp2_outbound_item {
+  nghttp2_frame frame;
+  /* Storage for extension frame payload.  frame->ext.payload points
+     to this structure to avoid frequent memory allocation. */
+  nghttp2_ext_frame_payload ext_frame_payload;
+  nghttp2_aux_data aux_data;
+  /* The priority used in priority comparion.  Smaller is served
+     ealier.  For PING, SETTINGS and non-DATA frames (excluding
+     response HEADERS frame) have dedicated cycle value defined above.
+     For DATA frame, cycle is computed by taking into account of
+     effective weight and frame payload length previously sent, so
+     that the amount of transmission is distributed across streams
+     proportional to effective weight (inside a tree). */
+  uint64_t cycle;
+  nghttp2_outbound_item *qnext;
+  /* nonzero if this object is queued, except for DATA or HEADERS
+     which are attached to stream as item. */
+  uint8_t queued;
+};
+
+/*
+ * Initializes |item|.  No memory allocation is done in this function.
+ * Don't call nghttp2_outbound_item_free() until frame member is
+ * initialized.
+ */
+void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
+
+/*
+ * Deallocates resource for |item|. If |item| is NULL, this function
+ * does nothing.
+ */
+void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
+
+/*
+ * queue for nghttp2_outbound_item.
+ */
+typedef struct {
+  nghttp2_outbound_item *head, *tail;
+  /* number of items in this queue. */
+  size_t n;
+} nghttp2_outbound_queue;
+
+void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
+
+/* Pushes |item| into |q| */
+void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
+                                 nghttp2_outbound_item *item);
+
+/* Pops |item| at the top from |q|.  If |q| is empty, nothing
+   happens. */
+void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
+
+/* Returns the top item. */
+#define nghttp2_outbound_queue_top(Q) ((Q)->head)
+
+/* Returns the size of the queue */
+#define nghttp2_outbound_queue_size(Q) ((Q)->n)
+
+#endif /* NGHTTP2_OUTBOUND_ITEM_H */

+ 128 - 0
components/nghttp/include/nghttp2_pq.h

@@ -0,0 +1,128 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_PQ_H
+#define NGHTTP2_PQ_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_int.h"
+#include "nghttp2_mem.h"
+
+/* Implementation of priority queue */
+
+typedef struct { size_t index; } nghttp2_pq_entry;
+
+typedef struct {
+  /* The pointer to the pointer to the item stored */
+  nghttp2_pq_entry **q;
+  /* Memory allocator */
+  nghttp2_mem *mem;
+  /* The number of items sotred */
+  size_t length;
+  /* The maximum number of items this pq can store. This is
+     automatically extended when length is reached to this value. */
+  size_t capacity;
+  /* The less function between items */
+  nghttp2_less less;
+} nghttp2_pq;
+
+/*
+ * Initializes priority queue |pq| with compare function |cmp|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |pq|.  The stored items are
+ * not freed by this function.
+ */
+void nghttp2_pq_free(nghttp2_pq *pq);
+
+/*
+ * Adds |item| to the priority queue |pq|.
+ *
+ * This function returns 0 if it succeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item);
+
+/*
+ * Returns item at the top of the queue |pq|. If the queue is empty,
+ * this function returns NULL.
+ */
+nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq);
+
+/*
+ * Pops item at the top of the queue |pq|. The popped item is not
+ * freed by this function.
+ */
+void nghttp2_pq_pop(nghttp2_pq *pq);
+
+/*
+ * Returns nonzero if the queue |pq| is empty.
+ */
+int nghttp2_pq_empty(nghttp2_pq *pq);
+
+/*
+ * Returns the number of items in the queue |pq|.
+ */
+size_t nghttp2_pq_size(nghttp2_pq *pq);
+
+typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
+
+/*
+ * Updates each item in |pq| using function |fun| and re-construct
+ * priority queue. The |fun| must return non-zero if it modifies the
+ * item in a way that it affects ordering in the priority queue. The
+ * |arg| is passed to the 2nd parameter of |fun|.
+ */
+void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
+
+/*
+ * Applys |fun| to each item in |pq|.  The |arg| is passed as arg
+ * parameter to callback function.  This function must not change the
+ * ordering key.  If the return value from callback is nonzero, this
+ * function returns 1 immediately without iterating remaining items.
+ * Otherwise this function returns 0.
+ */
+int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
+
+/*
+ * Removes |item| from priority queue.
+ */
+void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item);
+
+#endif /* NGHTTP2_PQ_H */

+ 42 - 0
components/nghttp/include/nghttp2_priority_spec.h

@@ -0,0 +1,42 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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.
+ */
+#ifndef NGHTTP2_PRIORITY_SPEC_H
+#define NGHTTP2_PRIORITY_SPEC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * This function normalizes pri_spec->weight if it is out of range.
+ * If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to
+ * NGHTTP2_MIN_WEIGHT.  If pri_spec->weight is larger than
+ * NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT.
+ */
+void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec);
+
+#endif /* NGHTTP2_PRIORITY_SPEC_H */

+ 49 - 0
components/nghttp/include/nghttp2_queue.h

@@ -0,0 +1,49 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_QUEUE_H
+#define NGHTTP2_QUEUE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+typedef struct nghttp2_queue_cell {
+  void *data;
+  struct nghttp2_queue_cell *next;
+} nghttp2_queue_cell;
+
+typedef struct { nghttp2_queue_cell *front, *back; } nghttp2_queue;
+
+void nghttp2_queue_init(nghttp2_queue *queue);
+void nghttp2_queue_free(nghttp2_queue *queue);
+int nghttp2_queue_push(nghttp2_queue *queue, void *data);
+void nghttp2_queue_pop(nghttp2_queue *queue);
+void *nghttp2_queue_front(nghttp2_queue *queue);
+void *nghttp2_queue_back(nghttp2_queue *queue);
+int nghttp2_queue_empty(nghttp2_queue *queue);
+
+#endif /* NGHTTP2_QUEUE_H */

+ 80 - 0
components/nghttp/include/nghttp2_rcbuf.h

@@ -0,0 +1,80 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2016 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.
+ */
+#ifndef NGHTTP2_RCBUF_H
+#define NGHTTP2_RCBUF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+struct nghttp2_rcbuf {
+  /* custom memory allocator belongs to the mem parameter when
+     creating this object. */
+  void *mem_user_data;
+  nghttp2_free free;
+  /* The pointer to the underlying buffer */
+  uint8_t *base;
+  /* Size of buffer pointed by |base|. */
+  size_t len;
+  /* Reference count */
+  int32_t ref;
+};
+
+/*
+ * Allocates nghttp2_rcbuf object with |size| as initial buffer size.
+ * When the function succeeds, the reference count becomes 1.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM:
+ *     Out of memory.
+ */
+int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem);
+
+/*
+ * Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of
+ * length |srclen|.  This function allocates additional byte at the
+ * end and puts '\0' into it, so that the resulting buffer could be
+ * used as NULL-terminated string.  Still (*rcbuf_ptr)->len equals to
+ * |srclen|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM:
+ *     Out of memory.
+ */
+int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
+                       size_t srclen, nghttp2_mem *mem);
+
+/*
+ * Frees |rcbuf| itself, regardless of its reference cout.
+ */
+void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf);
+
+#endif /* NGHTTP2_RCBUF_H */

+ 878 - 0
components/nghttp/include/nghttp2_session.h

@@ -0,0 +1,878 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_SESSION_H
+#define NGHTTP2_SESSION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_map.h"
+#include "nghttp2_frame.h"
+#include "nghttp2_hd.h"
+#include "nghttp2_stream.h"
+#include "nghttp2_outbound_item.h"
+#include "nghttp2_int.h"
+#include "nghttp2_buf.h"
+#include "nghttp2_callbacks.h"
+#include "nghttp2_mem.h"
+
+/* The global variable for tests where we want to disable strict
+   preface handling. */
+extern int nghttp2_enable_strict_preface;
+
+/*
+ * Option flags.
+ */
+typedef enum {
+  NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
+  NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
+  NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
+  NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3
+} nghttp2_optmask;
+
+/*
+ * bitmask for built-in type to enable the default handling for that
+ * type of the frame.
+ */
+typedef enum {
+  NGHTTP2_TYPEMASK_NONE = 0,
+  NGHTTP2_TYPEMASK_ALTSVC = 1 << 0
+} nghttp2_typemask;
+
+typedef enum {
+  NGHTTP2_OB_POP_ITEM,
+  NGHTTP2_OB_SEND_DATA,
+  NGHTTP2_OB_SEND_NO_COPY,
+  NGHTTP2_OB_SEND_CLIENT_MAGIC
+} nghttp2_outbound_state;
+
+typedef struct {
+  nghttp2_outbound_item *item;
+  nghttp2_bufs framebufs;
+  nghttp2_outbound_state state;
+} nghttp2_active_outbound_item;
+
+/* Buffer length for inbound raw byte stream used in
+   nghttp2_session_recv(). */
+#define NGHTTP2_INBOUND_BUFFER_LENGTH 3072//16384--LiuHan/08.12
+
+/* The default maximum number of incoming reserved streams */
+#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
+
+/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
+   number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
+#define NGHTTP2_MIN_IDLE_STREAMS 16
+
+/* The maximum number of items in outbound queue, which is considered
+   as flooding caused by peer.  All frames are not considered here.
+   We only consider PING + ACK and SETTINGS + ACK.  This is because
+   they both are response to the frame initiated by peer and peer can
+   send as many of them as they want.  If peer does not read network,
+   response frames are stacked up, which leads to memory exhaustion.
+   The value selected here is arbitrary, but safe value and if we have
+   these frames in this number, it is considered suspicious. */
+#define NGHTTP2_MAX_OBQ_FLOOD_ITEM 10000
+
+/* The default value of maximum number of concurrent streams. */
+#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
+
+/* Internal state when receiving incoming frame */
+typedef enum {
+  /* Receiving frame header */
+  NGHTTP2_IB_READ_CLIENT_MAGIC,
+  NGHTTP2_IB_READ_FIRST_SETTINGS,
+  NGHTTP2_IB_READ_HEAD,
+  NGHTTP2_IB_READ_NBYTE,
+  NGHTTP2_IB_READ_HEADER_BLOCK,
+  NGHTTP2_IB_IGN_HEADER_BLOCK,
+  NGHTTP2_IB_IGN_PAYLOAD,
+  NGHTTP2_IB_FRAME_SIZE_ERROR,
+  NGHTTP2_IB_READ_SETTINGS,
+  NGHTTP2_IB_READ_GOAWAY_DEBUG,
+  NGHTTP2_IB_EXPECT_CONTINUATION,
+  NGHTTP2_IB_IGN_CONTINUATION,
+  NGHTTP2_IB_READ_PAD_DATA,
+  NGHTTP2_IB_READ_DATA,
+  NGHTTP2_IB_IGN_DATA,
+  NGHTTP2_IB_IGN_ALL,
+  NGHTTP2_IB_READ_ALTSVC_PAYLOAD,
+  NGHTTP2_IB_READ_EXTENSION_PAYLOAD
+} nghttp2_inbound_state;
+
+typedef struct {
+  nghttp2_frame frame;
+  /* Storage for extension frame payload.  frame->ext.payload points
+     to this structure to avoid frequent memory allocation. */
+  nghttp2_ext_frame_payload ext_frame_payload;
+  /* The received SETTINGS entry.  For the standard settings entries,
+     we only keep the last seen value.  For
+     SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the
+     last index. */
+  nghttp2_settings_entry *iv;
+  /* buffer pointers to small buffer, raw_sbuf */
+  nghttp2_buf sbuf;
+  /* buffer pointers to large buffer, raw_lbuf */
+  nghttp2_buf lbuf;
+  /* Large buffer, malloced on demand */
+  uint8_t *raw_lbuf;
+  /* The number of entry filled in |iv| */
+  size_t niv;
+  /* The number of entries |iv| can store. */
+  size_t max_niv;
+  /* How many bytes we still need to receive for current frame */
+  size_t payloadleft;
+  /* padding length for the current frame */
+  size_t padlen;
+  nghttp2_inbound_state state;
+  /* Small buffer.  Currently the largest contiguous chunk to buffer
+     is frame header.  We buffer part of payload, but they are smaller
+     than frame header. */
+  uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
+} nghttp2_inbound_frame;
+
+typedef struct {
+  uint32_t header_table_size;
+  uint32_t enable_push;
+  uint32_t max_concurrent_streams;
+  uint32_t initial_window_size;
+  uint32_t max_frame_size;
+  uint32_t max_header_list_size;
+} nghttp2_settings_storage;
+
+typedef enum {
+  NGHTTP2_GOAWAY_NONE = 0,
+  /* Flag means that connection should be terminated after sending GOAWAY. */
+  NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1,
+  /* Flag means GOAWAY to terminate session has been sent */
+  NGHTTP2_GOAWAY_TERM_SENT = 0x2,
+  /* Flag means GOAWAY was sent */
+  NGHTTP2_GOAWAY_SENT = 0x4,
+  /* Flag means GOAWAY was received */
+  NGHTTP2_GOAWAY_RECV = 0x8
+} nghttp2_goaway_flag;
+
+/* nghttp2_inflight_settings stores the SETTINGS entries which local
+   endpoint has sent to the remote endpoint, and has not received ACK
+   yet. */
+struct nghttp2_inflight_settings {
+  struct nghttp2_inflight_settings *next;
+  nghttp2_settings_entry *iv;
+  size_t niv;
+};
+
+typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
+
+struct nghttp2_session {
+  nghttp2_map /* <nghttp2_stream*> */ streams;
+  /* root of dependency tree*/
+  nghttp2_stream root;
+  /* Queue for outbound urgent frames (PING and SETTINGS) */
+  nghttp2_outbound_queue ob_urgent;
+  /* Queue for non-DATA frames */
+  nghttp2_outbound_queue ob_reg;
+  /* Queue for outbound stream-creating HEADERS (request or push
+     response) frame, which are subject to
+     SETTINGS_MAX_CONCURRENT_STREAMS limit. */
+  nghttp2_outbound_queue ob_syn;
+  nghttp2_active_outbound_item aob;
+  nghttp2_inbound_frame iframe;
+  nghttp2_hd_deflater hd_deflater;
+  nghttp2_hd_inflater hd_inflater;
+  nghttp2_session_callbacks callbacks;
+  /* Memory allocator */
+  nghttp2_mem mem;
+  /* Base value when we schedule next DATA frame write.  This is
+     updated when one frame was written. */
+  uint64_t last_cycle;
+  void *user_data;
+  /* Points to the latest incoming closed stream.  NULL if there is no
+     closed stream.  Only used when session is initialized as
+     server. */
+  nghttp2_stream *closed_stream_head;
+  /* Points to the oldest incoming closed stream.  NULL if there is no
+     closed stream.  Only used when session is initialized as
+     server. */
+  nghttp2_stream *closed_stream_tail;
+  /* Points to the latest idle stream.  NULL if there is no idle
+     stream.  Only used when session is initialized as server .*/
+  nghttp2_stream *idle_stream_head;
+  /* Points to the oldest idle stream.  NULL if there is no idle
+     stream.  Only used when session is initialized as erver. */
+  nghttp2_stream *idle_stream_tail;
+  /* Queue of In-flight SETTINGS values.  SETTINGS bearing ACK is not
+     considered as in-flight. */
+  nghttp2_inflight_settings *inflight_settings_head;
+  /* The number of outgoing streams. This will be capped by
+     remote_settings.max_concurrent_streams. */
+  size_t num_outgoing_streams;
+  /* The number of incoming streams. This will be capped by
+     local_settings.max_concurrent_streams. */
+  size_t num_incoming_streams;
+  /* The number of incoming reserved streams.  This is the number of
+     streams in reserved (remote) state.  RFC 7540 does not limit this
+     number.  nghttp2 offers
+     nghttp2_option_set_max_reserved_remote_streams() to achieve this.
+     If it is used, num_incoming_streams is capped by
+     max_incoming_reserved_streams.  Client application should
+     consider to set this because without that server can send
+     arbitrary number of PUSH_PROMISE, and exhaust client's memory. */
+  size_t num_incoming_reserved_streams;
+  /* The maximum number of incoming reserved streams (reserved
+     (remote) state).  RST_STREAM will be sent for the pushed stream
+     which exceeds this limit. */
+  size_t max_incoming_reserved_streams;
+  /* The number of closed streams still kept in |streams| hash.  The
+     closed streams can be accessed through single linked list
+     |closed_stream_head|.  The current implementation only keeps
+     incoming streams and session is initialized as server. */
+  size_t num_closed_streams;
+  /* The number of idle streams kept in |streams| hash.  The idle
+     streams can be accessed through doubly linked list
+     |idle_stream_head|.  The current implementation only keeps idle
+     streams if session is initialized as server. */
+  size_t num_idle_streams;
+  /* The number of bytes allocated for nvbuf */
+  size_t nvbuflen;
+  /* Counter for detecting flooding in outbound queue */
+  size_t obq_flood_counter_;
+  /* The maximum length of header block to send.  Calculated by the
+     same way as nghttp2_hd_deflate_bound() does. */
+  size_t max_send_header_block_length;
+  /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
+  uint32_t next_stream_id;
+  /* The last stream ID this session initiated.  For client session,
+     this is the last stream ID it has sent.  For server session, it
+     is the last promised stream ID sent in PUSH_PROMISE. */
+  int32_t last_sent_stream_id;
+  /* The largest stream ID received so far */
+  int32_t last_recv_stream_id;
+  /* The largest stream ID which has been processed in some way. This
+     value will be used as last-stream-id when sending GOAWAY
+     frame. */
+  int32_t last_proc_stream_id;
+  /* Counter of unique ID of PING. Wraps when it exceeds
+     NGHTTP2_MAX_UNIQUE_ID */
+  uint32_t next_unique_id;
+  /* This is the last-stream-ID we have sent in GOAWAY */
+  int32_t local_last_stream_id;
+  /* This is the value in GOAWAY frame received from remote endpoint. */
+  int32_t remote_last_stream_id;
+  /* Current sender window size. This value is computed against the
+     current initial window size of remote endpoint. */
+  int32_t remote_window_size;
+  /* Keep track of the number of bytes received without
+     WINDOW_UPDATE. This could be negative after submitting negative
+     value to WINDOW_UPDATE. */
+  int32_t recv_window_size;
+  /* The number of bytes consumed by the application and now is
+     subject to WINDOW_UPDATE.  This is only used when auto
+     WINDOW_UPDATE is turned off. */
+  int32_t consumed_size;
+  /* The amount of recv_window_size cut using submitting negative
+     value to WINDOW_UPDATE */
+  int32_t recv_reduction;
+  /* window size for local flow control. It is initially set to
+     NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be
+     increased/decreased by submitting WINDOW_UPDATE. See
+     nghttp2_submit_window_update(). */
+  int32_t local_window_size;
+  /* Settings value received from the remote endpoint. We just use ID
+     as index. The index = 0 is unused. */
+  nghttp2_settings_storage remote_settings;
+  /* Settings value of the local endpoint. */
+  nghttp2_settings_storage local_settings;
+  /* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
+  uint32_t opt_flags;
+  /* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
+     to refuse the incoming stream if it exceeds this value. */
+  uint32_t pending_local_max_concurrent_stream;
+  /* The bitwose OR of zero or more of nghttp2_typemask to indicate
+     that the default handling of extension frame is enabled. */
+  uint32_t builtin_recv_ext_types;
+  /* Unacked local ENABLE_PUSH value.  We use this to refuse
+     PUSH_PROMISE before SETTINGS ACK is received. */
+  uint8_t pending_enable_push;
+  /* Nonzero if the session is server side. */
+  uint8_t server;
+  /* Flags indicating GOAWAY is sent and/or recieved. The flags are
+     composed by bitwise OR-ing nghttp2_goaway_flag. */
+  uint8_t goaway_flags;
+  /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
+     this session.  The nonzero does not necessarily mean
+     WINDOW_UPDATE is not queued. */
+  uint8_t window_update_queued;
+  /* Bitfield of extension frame types that application is willing to
+     receive.  To designate the bit of given frame type i, use
+     user_recv_ext_types[i / 8] & (1 << (i & 0x7)).  First 10 frame
+     types are standard frame types and not used in this bitfield.  If
+     bit is set, it indicates that incoming frame with that type is
+     passed to user defined callbacks, otherwise they are ignored. */
+  uint8_t user_recv_ext_types[32];
+};
+
+/* Struct used when updating initial window size of each active
+   stream. */
+typedef struct {
+  nghttp2_session *session;
+  int32_t new_window_size, old_window_size;
+} nghttp2_update_window_size_arg;
+
+typedef struct {
+  nghttp2_session *session;
+  /* linked list of streams to close */
+  nghttp2_stream *head;
+  int32_t last_stream_id;
+  /* nonzero if GOAWAY is sent to peer, which means we are going to
+     close incoming streams.  zero if GOAWAY is received from peer and
+     we are going to close outgoing streams. */
+  int incoming;
+} nghttp2_close_stream_on_goaway_arg;
+
+/* TODO stream timeout etc */
+
+/*
+ * Returns nonzero value if |stream_id| is initiated by local
+ * endpoint.
+ */
+int nghttp2_session_is_my_stream_id(nghttp2_session *session,
+                                    int32_t stream_id);
+
+/*
+ * Adds |item| to the outbound queue in |session|.  When this function
+ * succeeds, it takes ownership of |item|. So caller must not free it
+ * on success.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_STREAM_CLOSED
+ *     Stream already closed (DATA and PUSH_PROMISE frame only)
+ */
+int nghttp2_session_add_item(nghttp2_session *session,
+                             nghttp2_outbound_item *item);
+
+/*
+ * Adds RST_STREAM frame for the stream |stream_id| with the error
+ * code |error_code|. This is a convenient function built on top of
+ * nghttp2_session_add_frame() to add RST_STREAM easily.
+ *
+ * This function simply returns 0 without adding RST_STREAM frame if
+ * given stream is in NGHTTP2_STREAM_CLOSING state, because multiple
+ * RST_STREAM for a stream is redundant.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
+                                   uint32_t error_code);
+
+/*
+ * Adds PING frame. This is a convenient functin built on top of
+ * nghttp2_session_add_frame() to add PING easily.
+ *
+ * If the |opaque_data| is not NULL, it must point to 8 bytes memory
+ * region of data. The data pointed by |opaque_data| is copied. It can
+ * be NULL. In this case, 8 bytes NULL is used.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue; this only happens
+ *     if NGHTTP2_FLAG_ACK is set in |flags|
+ */
+int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
+                             const uint8_t *opaque_data);
+
+/*
+ * Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the
+ * error code |error_code|. This is a convenient function built on top
+ * of nghttp2_session_add_frame() to add GOAWAY easily.  The
+ * |aux_flags| are bitwise-OR of one or more of
+ * nghttp2_goaway_aux_flag.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The |opaque_data_len| is too large.
+ */
+int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
+                               uint32_t error_code, const uint8_t *opaque_data,
+                               size_t opaque_data_len, uint8_t aux_flags);
+
+/*
+ * Adds WINDOW_UPDATE frame with stream ID |stream_id| and
+ * window-size-increment |window_size_increment|. This is a convenient
+ * function built on top of nghttp2_session_add_frame() to add
+ * WINDOW_UPDATE easily.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
+                                      int32_t stream_id,
+                                      int32_t window_size_increment);
+
+/*
+ * Adds SETTINGS frame.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue; this only happens
+ *     if NGHTTP2_FLAG_ACK is set in |flags|
+ */
+int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
+                                 const nghttp2_settings_entry *iv, size_t niv);
+
+/*
+ * Creates new stream in |session| with stream ID |stream_id|,
+ * priority |pri_spec| and flags |flags|.  The |flags| is bitwise OR
+ * of nghttp2_stream_flag.  Since this function is called when initial
+ * HEADERS is sent or received, these flags are taken from it.  The
+ * state of stream is set to |initial_state|. The |stream_user_data|
+ * is a pointer to the arbitrary user supplied data to be associated
+ * to this stream.
+ *
+ * If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets
+ * NGHTTP2_STREAM_FLAG_PUSH flag set.
+ *
+ * This function returns a pointer to created new stream object, or
+ * NULL.
+ *
+ * This function adjusts neither the number of closed streams or idle
+ * streams.  The caller should manually call
+ * nghttp2_session_adjust_closed_stream() or
+ * nghttp2_session_adjust_idle_stream() respectively.
+ */
+nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
+                                            int32_t stream_id, uint8_t flags,
+                                            nghttp2_priority_spec *pri_spec,
+                                            nghttp2_stream_state initial_state,
+                                            void *stream_user_data);
+
+/*
+ * Closes stream whose stream ID is |stream_id|. The reason of closure
+ * is indicated by the |error_code|. When closing the stream,
+ * on_stream_close_callback will be called.
+ *
+ * If the session is initialized as server and |stream| is incoming
+ * stream, stream is just marked closed and this function calls
+ * nghttp2_session_keep_closed_stream() with |stream|.  Otherwise,
+ * |stream| will be deleted from memory.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The specified stream does not exist.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The callback function failed.
+ */
+int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
+                                 uint32_t error_code);
+
+/*
+ * Deletes |stream| from memory.  After this function returns, stream
+ * cannot be accessed.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_destroy_stream(nghttp2_session *session,
+                                   nghttp2_stream *stream);
+
+/*
+ * Tries to keep incoming closed stream |stream|.  Due to the
+ * limitation of maximum number of streams in memory, |stream| is not
+ * closed and just deleted from memory (see
+ * nghttp2_session_destroy_stream).
+ */
+void nghttp2_session_keep_closed_stream(nghttp2_session *session,
+                                        nghttp2_stream *stream);
+
+/*
+ * Appends |stream| to linked list |session->idle_stream_head|.  We
+ * apply fixed limit for list size.  To fit into that limit, one or
+ * more oldest streams are removed from list as necessary.
+ */
+void nghttp2_session_keep_idle_stream(nghttp2_session *session,
+                                      nghttp2_stream *stream);
+
+/*
+ * Detaches |stream| from idle streams linked list.
+ */
+void nghttp2_session_detach_idle_stream(nghttp2_session *session,
+                                        nghttp2_stream *stream);
+
+/*
+ * Deletes closed stream to ensure that number of incoming streams
+ * including active and closed is in the maximum number of allowed
+ * stream.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
+
+/*
+ * Deletes idle stream to ensure that number of idle streams is in
+ * certain limit.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_adjust_idle_stream(nghttp2_session *session);
+
+/*
+ * If further receptions and transmissions over the stream |stream_id|
+ * are disallowed, close the stream with error code NGHTTP2_NO_ERROR.
+ *
+ * This function returns 0 if it
+ * succeeds, or one of the following negative error codes:
+ *
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The specified stream does not exist.
+ */
+int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
+                                              nghttp2_stream *stream);
+
+int nghttp2_session_on_request_headers_received(nghttp2_session *session,
+                                                nghttp2_frame *frame);
+
+int nghttp2_session_on_response_headers_received(nghttp2_session *session,
+                                                 nghttp2_frame *frame,
+                                                 nghttp2_stream *stream);
+
+int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
+                                                      nghttp2_frame *frame,
+                                                      nghttp2_stream *stream);
+
+/*
+ * Called when HEADERS is received, assuming |frame| is properly
+ * initialized.  This function does first validate received frame and
+ * then open stream and call callback functions.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_IGN_HEADER_BLOCK
+ *     Frame was rejected and header block must be decoded but
+ *     result must be ignored.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_headers_received(nghttp2_session *session,
+                                        nghttp2_frame *frame,
+                                        nghttp2_stream *stream);
+
+/*
+ * Called when PRIORITY is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_priority_received(nghttp2_session *session,
+                                         nghttp2_frame *frame);
+
+/*
+ * Called when RST_STREAM is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
+                                           nghttp2_frame *frame);
+
+/*
+ * Called when SETTINGS is received, assuming |frame| is properly
+ * initialized. If |noack| is non-zero, SETTINGS with ACK will not be
+ * submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS
+ * with ACK will not be submitted regardless of |noack|.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue, and this is most
+ *     likely caused by misbehaviour of peer.
+ */
+int nghttp2_session_on_settings_received(nghttp2_session *session,
+                                         nghttp2_frame *frame, int noack);
+
+/*
+ * Called when PUSH_PROMISE is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_IGN_HEADER_BLOCK
+ *     Frame was rejected and header block must be decoded but
+ *     result must be ignored.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_push_promise_received(nghttp2_session *session,
+                                             nghttp2_frame *frame);
+
+/*
+ * Called when PING is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue, and this is most
+ *     likely caused by misbehaviour of peer.
+ */
+int nghttp2_session_on_ping_received(nghttp2_session *session,
+                                     nghttp2_frame *frame);
+
+/*
+ * Called when GOAWAY is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_goaway_received(nghttp2_session *session,
+                                       nghttp2_frame *frame);
+
+/*
+ * Called when WINDOW_UPDATE is recieved, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_window_update_received(nghttp2_session *session,
+                                              nghttp2_frame *frame);
+
+/*
+ * Called when ALTSVC is recieved, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_altsvc_received(nghttp2_session *session,
+                                       nghttp2_frame *frame);
+
+/*
+ * Called when DATA is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_data_received(nghttp2_session *session,
+                                     nghttp2_frame *frame);
+
+/*
+ * Returns nghttp2_stream* object whose stream ID is |stream_id|.  It
+ * could be NULL if such stream does not exist.  This function returns
+ * NULL if stream is marked as closed.
+ */
+nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
+                                           int32_t stream_id);
+
+/*
+ * This function behaves like nghttp2_session_get_stream(), but it
+ * returns stream object even if it is marked as closed or in
+ * NGHTTP2_STREAM_IDLE state.
+ */
+nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
+                                               int32_t stream_id);
+
+/*
+ * Packs DATA frame |frame| in wire frame format and stores it in
+ * |bufs|.  Payload will be read using |aux_data->data_prd|.  The
+ * length of payload is at most |datamax| bytes.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_DEFERRED
+ *     The DATA frame is postponed.
+ * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
+ *     The read_callback failed (stream error).
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed (session error).
+ */
+int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
+                              size_t datamax, nghttp2_frame *frame,
+                              nghttp2_data_aux_data *aux_data,
+                              nghttp2_stream *stream);
+
+/*
+ * Pops and returns next item to send.  If there is no such item,
+ * returns NULL.  This function takes into account max concurrent
+ * streams.  That means if session->ob_syn has item and max concurrent
+ * streams is reached, the even if other queues contain items, then
+ * this function returns NULL.
+ */
+nghttp2_outbound_item *
+nghttp2_session_pop_next_ob_item(nghttp2_session *session);
+
+/*
+ * Returns next item to send.  If there is no such item, this function
+ * returns NULL.  This function takes into account max concurrent
+ * streams.  That means if session->ob_syn has item and max concurrent
+ * streams is reached, the even if other queues contain items, then
+ * this function returns NULL.
+ */
+nghttp2_outbound_item *
+nghttp2_session_get_next_ob_item(nghttp2_session *session);
+
+/*
+ * Updates local settings with the |iv|. The number of elements in the
+ * array pointed by the |iv| is given by the |niv|.  This function
+ * assumes that the all settings_id member in |iv| are in range 1 to
+ * NGHTTP2_SETTINGS_MAX, inclusive.
+ *
+ * While updating individual stream's local window size, if the window
+ * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
+ * RST_STREAM is issued against such a stream.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_update_local_settings(nghttp2_session *session,
+                                          nghttp2_settings_entry *iv,
+                                          size_t niv);
+
+/*
+ * Re-prioritize |stream|. The new priority specification is
+ * |pri_spec|.  Caller must ensure that stream->hd.stream_id !=
+ * pri_spec->stream_id.
+ *
+ * This function does not adjust the number of idle streams.  The
+ * caller should call nghttp2_session_adjust_idle_stream() later.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_reprioritize_stream(nghttp2_session *session,
+                                        nghttp2_stream *stream,
+                                        const nghttp2_priority_spec *pri_spec);
+
+/*
+ * Terminates current |session| with the |error_code|.  The |reason|
+ * is NULL-terminated debug string.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The |reason| is too long.
+ */
+int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
+                                                  uint32_t error_code,
+                                                  const char *reason);
+
+#endif /* NGHTTP2_SESSION_H */

+ 436 - 0
components/nghttp/include/nghttp2_stream.h

@@ -0,0 +1,436 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_STREAM_H
+#define NGHTTP2_STREAM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_outbound_item.h"
+#include "nghttp2_map.h"
+#include "nghttp2_pq.h"
+#include "nghttp2_int.h"
+
+/*
+ * If local peer is stream initiator:
+ * NGHTTP2_STREAM_OPENING : upon sending request HEADERS
+ * NGHTTP2_STREAM_OPENED : upon receiving response HEADERS
+ * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
+ *
+ * If remote peer is stream initiator:
+ * NGHTTP2_STREAM_OPENING : upon receiving request HEADERS
+ * NGHTTP2_STREAM_OPENED : upon sending response HEADERS
+ * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
+ */
+typedef enum {
+  /* Initial state */
+  NGHTTP2_STREAM_INITIAL,
+  /* For stream initiator: request HEADERS has been sent, but response
+     HEADERS has not been received yet.  For receiver: request HEADERS
+     has been received, but it does not send response HEADERS yet. */
+  NGHTTP2_STREAM_OPENING,
+  /* For stream initiator: response HEADERS is received. For receiver:
+     response HEADERS is sent. */
+  NGHTTP2_STREAM_OPENED,
+  /* RST_STREAM is received, but somehow we need to keep stream in
+     memory. */
+  NGHTTP2_STREAM_CLOSING,
+  /* PUSH_PROMISE is received or sent */
+  NGHTTP2_STREAM_RESERVED,
+  /* Stream is created in this state if it is used as anchor in
+     dependency tree. */
+  NGHTTP2_STREAM_IDLE
+} nghttp2_stream_state;
+
+typedef enum {
+  NGHTTP2_SHUT_NONE = 0,
+  /* Indicates further receptions will be disallowed. */
+  NGHTTP2_SHUT_RD = 0x01,
+  /* Indicates further transmissions will be disallowed. */
+  NGHTTP2_SHUT_WR = 0x02,
+  /* Indicates both further receptions and transmissions will be
+     disallowed. */
+  NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR
+} nghttp2_shut_flag;
+
+typedef enum {
+  NGHTTP2_STREAM_FLAG_NONE = 0,
+  /* Indicates that this stream is pushed stream and not opened
+     yet. */
+  NGHTTP2_STREAM_FLAG_PUSH = 0x01,
+  /* Indicates that this stream was closed */
+  NGHTTP2_STREAM_FLAG_CLOSED = 0x02,
+  /* Indicates the item is deferred due to flow control. */
+  NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04,
+  /* Indicates the item is deferred by user callback */
+  NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
+  /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
+     NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
+  NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
+
+} nghttp2_stream_flag;
+
+/* HTTP related flags to enforce HTTP semantics */
+typedef enum {
+  NGHTTP2_HTTP_FLAG_NONE = 0,
+  /* header field seen so far */
+  NGHTTP2_HTTP_FLAG__AUTHORITY = 1,
+  NGHTTP2_HTTP_FLAG__PATH = 1 << 1,
+  NGHTTP2_HTTP_FLAG__METHOD = 1 << 2,
+  NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3,
+  /* host is not pseudo header, but we require either host or
+     :authority */
+  NGHTTP2_HTTP_FLAG_HOST = 1 << 4,
+  NGHTTP2_HTTP_FLAG__STATUS = 1 << 5,
+  /* required header fields for HTTP request except for CONNECT
+     method. */
+  NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD |
+                                  NGHTTP2_HTTP_FLAG__PATH |
+                                  NGHTTP2_HTTP_FLAG__SCHEME,
+  NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6,
+  /* HTTP method flags */
+  NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
+  NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
+  NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
+  NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
+  NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
+                               NGHTTP2_HTTP_FLAG_METH_HEAD |
+                               NGHTTP2_HTTP_FLAG_METH_OPTIONS |
+                               NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
+  /* :path category */
+  /* path starts with "/" */
+  NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
+  /* path "*" */
+  NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12,
+  /* scheme */
+  /* "http" or "https" scheme */
+  NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
+  /* set if final response is expected */
+  NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14
+} nghttp2_http_flag;
+
+struct nghttp2_stream {
+  /* Intrusive Map */
+  nghttp2_map_entry map_entry;
+  /* Entry for dep_prev->obq */
+  nghttp2_pq_entry pq_entry;
+  /* Priority Queue storing direct descendant (nghttp2_stream).  Only
+     streams which itself has some data to send, or has a descendant
+     which has some data to sent. */
+  nghttp2_pq obq;
+  /* Content-Length of request/response body.  -1 if unknown. */
+  int64_t content_length;
+  /* Received body so far */
+  int64_t recv_content_length;
+  /* Base last_cycle for direct descendent streams. */
+  uint32_t descendant_last_cycle;
+  /* Next scheduled time to sent item */
+  uint32_t cycle;
+  /* Next seq used for direct descendant streams */
+  uint64_t descendant_next_seq;
+  /* Secondary key for prioritization to break a tie for cycle.  This
+     value is monotonically increased for single parent stream. */
+  uint64_t seq;
+  /* pointers to form dependency tree.  If multiple streams depend on
+     a stream, only one stream (left most) has non-NULL dep_prev which
+     points to the stream it depends on. The remaining streams are
+     linked using sib_prev and sib_next.  The stream which has
+     non-NULL dep_prev always NULL sib_prev.  The right most stream
+     has NULL sib_next.  If this stream is a root of dependency tree,
+     dep_prev and sib_prev are NULL. */
+  nghttp2_stream *dep_prev, *dep_next;
+  nghttp2_stream *sib_prev, *sib_next;
+  /* When stream is kept after closure, it may be kept in doubly
+     linked list pointed by nghttp2_session closed_stream_head.
+     closed_next points to the next stream object if it is the element
+     of the list. */
+  nghttp2_stream *closed_prev, *closed_next;
+  /* The arbitrary data provided by user for this stream. */
+  void *stream_user_data;
+  /* Item to send */
+  nghttp2_outbound_item *item;
+  /* Last written length of frame payload */
+  size_t last_writelen;
+  /* stream ID */
+  int32_t stream_id;
+  /* Current remote window size. This value is computed against the
+     current initial window size of remote endpoint. */
+  int32_t remote_window_size;
+  /* Keep track of the number of bytes received without
+     WINDOW_UPDATE. This could be negative after submitting negative
+     value to WINDOW_UPDATE */
+  int32_t recv_window_size;
+  /* The number of bytes consumed by the application and now is
+     subject to WINDOW_UPDATE.  This is only used when auto
+     WINDOW_UPDATE is turned off. */
+  int32_t consumed_size;
+  /* The amount of recv_window_size cut using submitting negative
+     value to WINDOW_UPDATE */
+  int32_t recv_reduction;
+  /* window size for local flow control. It is initially set to
+     NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
+     submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
+  int32_t local_window_size;
+  /* weight of this stream */
+  int32_t weight;
+  /* This is unpaid penalty (offset) when calculating cycle. */
+  uint32_t pending_penalty;
+  /* sum of weight of direct descendants */
+  int32_t sum_dep_weight;
+  nghttp2_stream_state state;
+  /* status code from remote server */
+  int16_t status_code;
+  /* Bitwise OR of zero or more nghttp2_http_flag values */
+  uint16_t http_flags;
+  /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
+  uint8_t flags;
+  /* Bitwise OR of zero or more nghttp2_shut_flag values */
+  uint8_t shut_flags;
+  /* Nonzero if this stream has been queued to stream pointed by
+     dep_prev.  We maintain the invariant that if a stream is queued,
+     then its ancestors, except for root, are also queued.  This
+     invariant may break in fatal error condition. */
+  uint8_t queued;
+  /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
+     this stream.  The nonzero does not necessarily mean WINDOW_UPDATE
+     is not queued. */
+  uint8_t window_update_queued;
+};
+
+void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
+                         uint8_t flags, nghttp2_stream_state initial_state,
+                         int32_t weight, int32_t remote_initial_window_size,
+                         int32_t local_initial_window_size,
+                         void *stream_user_data, nghttp2_mem *mem);
+
+void nghttp2_stream_free(nghttp2_stream *stream);
+
+/*
+ * Disallow either further receptions or transmissions, or both.
+ * |flag| is bitwise OR of one or more of nghttp2_shut_flag.
+ */
+void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
+
+/*
+ * Defer |stream->item|.  We won't call this function in the situation
+ * where |stream->item| == NULL.  The |flags| is bitwise OR of zero or
+ * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
+ * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL.  The |flags| indicates
+ * the reason of this action.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
+
+/*
+ * Put back deferred data in this stream to active state.  The |flags|
+ * are one or more of bitwise OR of the following values:
+ * NGHTTP2_STREAM_FLAG_DEFERRED_USER and
+ * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
+ * cleared if they are set.  So even if this function is called, if
+ * one of flag is still set, data does not become active.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags);
+
+/*
+ * Returns nonzero if item is deferred by whatever reason.
+ */
+int nghttp2_stream_check_deferred_item(nghttp2_stream *stream);
+
+/*
+ * Returns nonzero if item is deferred by flow control.
+ */
+int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
+
+/*
+ * Updates the remote window size with the new value
+ * |new_initial_window_size|. The |old_initial_window_size| is used to
+ * calculate the current window size.
+ *
+ * This function returns 0 if it succeeds or -1. The failure is due to
+ * overflow.
+ */
+int nghttp2_stream_update_remote_initial_window_size(
+    nghttp2_stream *stream, int32_t new_initial_window_size,
+    int32_t old_initial_window_size);
+
+/*
+ * Updates the local window size with the new value
+ * |new_initial_window_size|. The |old_initial_window_size| is used to
+ * calculate the current window size.
+ *
+ * This function returns 0 if it succeeds or -1. The failure is due to
+ * overflow.
+ */
+int nghttp2_stream_update_local_initial_window_size(
+    nghttp2_stream *stream, int32_t new_initial_window_size,
+    int32_t old_initial_window_size);
+
+/*
+ * Call this function if promised stream |stream| is replied with
+ * HEADERS.  This function makes the state of the |stream| to
+ * NGHTTP2_STREAM_OPENED.
+ */
+void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
+
+/*
+ * Returns nonzero if |target| is an ancestor of |stream|.
+ */
+int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
+                                     nghttp2_stream *target);
+
+/*
+ * Computes distributed weight of a stream of the |weight| under the
+ * |stream| if |stream| is removed from a dependency tree.
+ */
+int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
+                                              int32_t weight);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * exclusive.  All existing direct descendants of |dep_stream| become
+ * the descendants of the |stream|.  This function assumes
+ * |stream->item| is NULL.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
+                              nghttp2_stream *stream);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * not exclusive.  This function assumes |stream->item| is NULL.
+ */
+void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
+
+/*
+ * Removes the |stream| from the current dependency tree.  This
+ * function assumes |stream->item| is NULL.
+ */
+int nghttp2_stream_dep_remove(nghttp2_stream *stream);
+
+/*
+ * Attaches |item| to |stream|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_attach_item(nghttp2_stream *stream,
+                               nghttp2_outbound_item *item);
+
+/*
+ * Detaches |stream->item|.  This function does not free
+ * |stream->item|.  The caller must free it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_detach_item(nghttp2_stream *stream);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * exclusive.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
+                                      nghttp2_stream *stream);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * not exclusive.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
+                                   nghttp2_stream *stream);
+
+/*
+ * Removes subtree whose root stream is |stream|.  The
+ * effective_weight of streams in removed subtree is not updated.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
+
+/*
+ * Returns nonzero if |stream| is in any dependency tree.
+ */
+int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
+
+/*
+ * Schedules transmission of |stream|'s item, assuming stream->item is
+ * attached, and stream->last_writelen was updated.
+ */
+void nghttp2_stream_reschedule(nghttp2_stream *stream);
+
+/*
+ * Changes |stream|'s weight to |weight|.  If |stream| is queued, it
+ * will be rescheduled based on new weight.
+ */
+void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight);
+
+/*
+ * Returns a stream which has highest priority, updating
+ * descendant_last_cycle of selected stream's ancestors.
+ */
+nghttp2_outbound_item *
+nghttp2_stream_next_outbound_item(nghttp2_stream *stream);
+
+#endif /* NGHTTP2_STREAM */

+ 34 - 0
components/nghttp/include/nghttp2_submit.h

@@ -0,0 +1,34 @@
+/*
+ * nghttp2 - HTTP/2 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.
+ */
+#ifndef NGHTTP2_SUBMIT_H
+#define NGHTTP2_SUBMIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#endif /* NGHTTP2_SUBMIT_H */

+ 494 - 0
components/nghttp/library/nghttp2_buf.c

@@ -0,0 +1,494 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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 "nghttp2_buf.h"
+
+#include <stdio.h>
+
+#include "nghttp2_helper.h"
+
+void nghttp2_buf_init(nghttp2_buf *buf) {
+  buf->begin = NULL;
+  buf->end = NULL;
+  buf->pos = NULL;
+  buf->last = NULL;
+  buf->mark = NULL;
+}
+
+int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
+  nghttp2_buf_init(buf);
+  return nghttp2_buf_reserve(buf, initial, mem);
+}
+
+void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) {
+  if (buf == NULL) {
+    return;
+  }
+
+  nghttp2_mem_free(mem, buf->begin);
+  buf->begin = NULL;
+}
+
+int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) {
+  uint8_t *ptr;
+  size_t cap;
+
+  cap = nghttp2_buf_cap(buf);
+
+  if (cap >= new_cap) {
+    return 0;
+  }
+
+  new_cap = nghttp2_max(new_cap, cap * 2);
+
+  ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
+  if (ptr == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  buf->pos = ptr + (buf->pos - buf->begin);
+  buf->last = ptr + (buf->last - buf->begin);
+  buf->mark = ptr + (buf->mark - buf->begin);
+  buf->begin = ptr;
+  buf->end = ptr + new_cap;
+
+  return 0;
+}
+
+void nghttp2_buf_reset(nghttp2_buf *buf) {
+  buf->pos = buf->last = buf->mark = buf->begin;
+}
+
+void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
+  buf->begin = buf->pos = buf->last = buf->mark = begin;
+  buf->end = begin + len;
+}
+
+static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
+                         nghttp2_mem *mem) {
+  int rv;
+
+  *chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
+  if (*chain == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  (*chain)->next = NULL;
+
+  rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
+  if (rv != 0) {
+    nghttp2_mem_free(mem, *chain);
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  return 0;
+}
+
+static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) {
+  nghttp2_buf_free(&chain->buf, mem);
+  nghttp2_mem_free(mem, chain);
+}
+
+int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
+                      nghttp2_mem *mem) {
+  return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
+}
+
+int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t offset, nghttp2_mem *mem) {
+  return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
+                            mem);
+}
+
+int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t chunk_keep, size_t offset,
+                       nghttp2_mem *mem) {
+  int rv;
+  nghttp2_buf_chain *chain;
+
+  if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  rv = buf_chain_new(&chain, chunk_length, mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  bufs->mem = mem;
+  bufs->offset = offset;
+
+  bufs->head = chain;
+  bufs->cur = bufs->head;
+
+  nghttp2_buf_shift_right(&bufs->cur->buf, offset);
+
+  bufs->chunk_length = chunk_length;
+  bufs->chunk_used = 1;
+  bufs->max_chunk = max_chunk;
+  bufs->chunk_keep = chunk_keep;
+
+  return 0;
+}
+
+int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
+  int rv;
+  nghttp2_buf_chain *chain;
+
+  if (chunk_length < bufs->offset) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  rv = buf_chain_new(&chain, chunk_length, bufs->mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  nghttp2_bufs_free(bufs);
+
+  bufs->head = chain;
+  bufs->cur = bufs->head;
+
+  nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
+
+  bufs->chunk_length = chunk_length;
+  bufs->chunk_used = 1;
+
+  return 0;
+}
+
+void nghttp2_bufs_free(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *chain, *next_chain;
+
+  if (bufs == NULL) {
+    return;
+  }
+
+  for (chain = bufs->head; chain;) {
+    next_chain = chain->next;
+
+    buf_chain_del(chain, bufs->mem);
+
+    chain = next_chain;
+  }
+
+  bufs->head = NULL;
+}
+
+int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
+                           nghttp2_mem *mem) {
+  nghttp2_buf_chain *chain;
+
+  chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
+  if (chain == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  chain->next = NULL;
+
+  nghttp2_buf_wrap_init(&chain->buf, begin, len);
+
+  bufs->mem = mem;
+  bufs->offset = 0;
+
+  bufs->head = chain;
+  bufs->cur = bufs->head;
+
+  bufs->chunk_length = len;
+  bufs->chunk_used = 1;
+  bufs->max_chunk = 1;
+  bufs->chunk_keep = 1;
+
+  return 0;
+}
+
+void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
+  if (bufs == NULL) {
+    return;
+  }
+
+  nghttp2_mem_free(bufs->mem, bufs->head);
+  bufs->head = NULL;
+}
+
+void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *ci;
+
+  for (ci = bufs->cur; ci; ci = ci->next) {
+    if (nghttp2_buf_len(&ci->buf) == 0) {
+      return;
+    } else {
+      bufs->cur = ci;
+    }
+  }
+}
+
+size_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *ci;
+  size_t len;
+
+  len = 0;
+  for (ci = bufs->head; ci; ci = ci->next) {
+    len += nghttp2_buf_len(&ci->buf);
+  }
+
+  return len;
+}
+
+static size_t bufs_avail(nghttp2_bufs *bufs) {
+  return nghttp2_buf_avail(&bufs->cur->buf) +
+         (bufs->chunk_length - bufs->offset) *
+             (bufs->max_chunk - bufs->chunk_used);
+}
+
+static int bufs_alloc_chain(nghttp2_bufs *bufs) {
+  int rv;
+  nghttp2_buf_chain *chain;
+
+  if (bufs->cur->next) {
+    bufs->cur = bufs->cur->next;
+
+    return 0;
+  }
+
+  if (bufs->max_chunk == bufs->chunk_used) {
+    return NGHTTP2_ERR_BUFFER_ERROR;
+  }
+
+  rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  DEBUGF(fprintf(stderr,
+                 "new buffer %zu bytes allocated for bufs %p, used %zu\n",
+                 bufs->chunk_length, bufs, bufs->chunk_used));
+
+  ++bufs->chunk_used;
+
+  bufs->cur->next = chain;
+  bufs->cur = chain;
+
+  nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
+
+  return 0;
+}
+
+int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
+  int rv;
+  size_t nwrite;
+  nghttp2_buf *buf;
+  const uint8_t *p;
+
+  if (bufs_avail(bufs) < len) {
+    return NGHTTP2_ERR_BUFFER_ERROR;
+  }
+
+  p = data;
+
+  while (len) {
+    buf = &bufs->cur->buf;
+
+    nwrite = nghttp2_min(nghttp2_buf_avail(buf), len);
+    if (nwrite == 0) {
+      rv = bufs_alloc_chain(bufs);
+      if (rv != 0) {
+        return rv;
+      }
+      continue;
+    }
+
+    buf->last = nghttp2_cpymem(buf->last, p, nwrite);
+    p += nwrite;
+    len -= nwrite;
+  }
+
+  return 0;
+}
+
+static int bufs_ensure_addb(nghttp2_bufs *bufs) {
+  int rv;
+  nghttp2_buf *buf;
+
+  buf = &bufs->cur->buf;
+
+  if (nghttp2_buf_avail(buf) > 0) {
+    return 0;
+  }
+
+  rv = bufs_alloc_chain(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return 0;
+}
+
+int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last++ = b;
+
+  return 0;
+}
+
+int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last = b;
+
+  return 0;
+}
+
+int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last++ |= b;
+
+  return 0;
+}
+
+int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last |= b;
+
+  return 0;
+}
+
+ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
+  size_t len;
+  nghttp2_buf_chain *chain;
+  nghttp2_buf *buf;
+  uint8_t *res;
+  nghttp2_buf resbuf;
+
+  len = 0;
+
+  for (chain = bufs->head; chain; chain = chain->next) {
+    len += nghttp2_buf_len(&chain->buf);
+  }
+
+  if (len == 0) {
+    res = NULL;
+    return 0;
+  }
+
+  res = nghttp2_mem_malloc(bufs->mem, len);
+  if (res == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  nghttp2_buf_wrap_init(&resbuf, res, len);
+
+  for (chain = bufs->head; chain; chain = chain->next) {
+    buf = &chain->buf;
+    resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
+  }
+
+  *out = res;
+
+  return (ssize_t)len;
+}
+
+size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
+  size_t len;
+  nghttp2_buf_chain *chain;
+  nghttp2_buf *buf;
+  nghttp2_buf resbuf;
+
+  len = nghttp2_bufs_len(bufs);
+
+  nghttp2_buf_wrap_init(&resbuf, out, len);
+
+  for (chain = bufs->head; chain; chain = chain->next) {
+    buf = &chain->buf;
+    resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
+  }
+
+  return len;
+}
+
+void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *chain, *ci;
+  size_t k;
+
+  k = bufs->chunk_keep;
+
+  for (ci = bufs->head; ci; ci = ci->next) {
+    nghttp2_buf_reset(&ci->buf);
+    nghttp2_buf_shift_right(&ci->buf, bufs->offset);
+
+    if (--k == 0) {
+      break;
+    }
+  }
+
+  if (ci) {
+    chain = ci->next;
+    ci->next = NULL;
+
+    for (ci = chain; ci;) {
+      chain = ci->next;
+
+      buf_chain_del(ci, bufs->mem);
+
+      ci = chain;
+    }
+
+    bufs->chunk_used = bufs->chunk_keep;
+  }
+
+  bufs->cur = bufs->head;
+}
+
+int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); }
+
+int nghttp2_bufs_next_present(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *chain;
+
+  chain = bufs->cur->next;
+
+  return chain && nghttp2_buf_len(&chain->buf);
+}

+ 158 - 0
components/nghttp/library/nghttp2_callbacks.c

@@ -0,0 +1,158 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 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 "nghttp2_callbacks.h"
+
+#include <stdlib.h>
+
+int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) {
+  *callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
+
+  if (*callbacks_ptr == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  return 0;
+}
+
+void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) {
+  free(callbacks);
+}
+
+void nghttp2_session_callbacks_set_send_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) {
+  cbs->send_callback = send_callback;
+}
+
+void nghttp2_session_callbacks_set_recv_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) {
+  cbs->recv_callback = recv_callback;
+}
+
+void nghttp2_session_callbacks_set_on_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_recv_callback on_frame_recv_callback) {
+  cbs->on_frame_recv_callback = on_frame_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) {
+  cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) {
+  cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_before_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_before_frame_send_callback before_frame_send_callback) {
+  cbs->before_frame_send_callback = before_frame_send_callback;
+}
+
+void nghttp2_session_callbacks_set_on_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_send_callback on_frame_send_callback) {
+  cbs->on_frame_send_callback = on_frame_send_callback;
+}
+
+void nghttp2_session_callbacks_set_on_frame_not_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_not_send_callback on_frame_not_send_callback) {
+  cbs->on_frame_not_send_callback = on_frame_not_send_callback;
+}
+
+void nghttp2_session_callbacks_set_on_stream_close_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_stream_close_callback on_stream_close_callback) {
+  cbs->on_stream_close_callback = on_stream_close_callback;
+}
+
+void nghttp2_session_callbacks_set_on_begin_headers_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_headers_callback on_begin_headers_callback) {
+  cbs->on_begin_headers_callback = on_begin_headers_callback;
+}
+
+void nghttp2_session_callbacks_set_on_header_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback on_header_callback) {
+  cbs->on_header_callback = on_header_callback;
+}
+
+void nghttp2_session_callbacks_set_on_header_callback2(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback2 on_header_callback2) {
+  cbs->on_header_callback2 = on_header_callback2;
+}
+
+void nghttp2_session_callbacks_set_select_padding_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_select_padding_callback select_padding_callback) {
+  cbs->select_padding_callback = select_padding_callback;
+}
+
+void nghttp2_session_callbacks_set_data_source_read_length_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_data_source_read_length_callback data_source_read_length_callback) {
+  cbs->read_length_callback = data_source_read_length_callback;
+}
+
+void nghttp2_session_callbacks_set_on_begin_frame_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_frame_callback on_begin_frame_callback) {
+  cbs->on_begin_frame_callback = on_begin_frame_callback;
+}
+
+void nghttp2_session_callbacks_set_send_data_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_send_data_callback send_data_callback) {
+  cbs->send_data_callback = send_data_callback;
+}
+
+void nghttp2_session_callbacks_set_pack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_pack_extension_callback pack_extension_callback) {
+  cbs->pack_extension_callback = pack_extension_callback;
+}
+
+void nghttp2_session_callbacks_set_unpack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_unpack_extension_callback unpack_extension_callback) {
+  cbs->unpack_extension_callback = unpack_extension_callback;
+}
+
+void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
+  cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_error_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) {
+  cbs->error_callback = error_callback;
+}

Some files were not shown because too many files changed in this diff