这个只是个demo程序,仅做参考。功能做到了最简化,只支持get请求,但是是性能还是很不错的,支持大量并发操作,资源使用量低,非常适合在嵌入式平台使用。

    使用当前目录作为根目录并运行:

    ./httpd

    指定根目录并运行:

    ./httpd /home/xxxx/root

    1. /* //////////////////////////////////////////////////////////////////////////////////////
    2. * includes
    3. */
    4. #include "tbox/tbox.h"
    5.  
    6. /* //////////////////////////////////////////////////////////////////////////////////////
    7. * macros
    8. */
    9.  
    10. // the httpd port
    11. #define TB_DEMO_HTTPD_PORT (8080)
    12.  
    13. // the httpd session maximum count
    14. #define TB_DEMO_HTTPD_SESSION_MAXN (100000)
    15.  
    16. // the httpd session timeout: 15s
    17. #define TB_DEMO_HTTPD_SESSION_TIMEOUT (15000)
    18.  
    19. // the httpd session buffer maximum size
    20. #define TB_DEMO_HTTPD_SESSION_BUFF_MAXN (8192)
    21.  
    22. /* //////////////////////////////////////////////////////////////////////////////////////
    23. * types
    24. */
    25.  
    26. // the httpd type
    27. typedef struct __tb_demo_httpd_t
    28. {
    29. // the root directory
    30. tb_char_t root[TB_PATH_MAXN];
    31.  
    32. // the listen port
    33. tb_uint16_t port;
    34.  
    35. // the listen aico
    36. tb_aico_ref_t aico;
    37.  
    38. // the aicp
    39. tb_aicp_ref_t aicp;
    40.  
    41. }tb_demo_httpd_t;
    42.  
    43. // the httpd session type
    44. typedef struct __tb_demo_httpd_session_t
    45. {
    46. // the aico
    47. tb_aico_ref_t aico;
    48.  
    49. // the code
    50. tb_size_t code;
    51.  
    52. // the file
    53. tb_file_ref_t file;
    54.  
    55. // the path
    56. tb_string_t path;
    57.  
    58. // the line
    59. tb_string_t line;
    60.  
    61. // the index
    62. tb_size_t index;
    63.  
    64. // the cache
    65. tb_buffer_t cache;
    66.  
    67. // the httpd
    68. tb_demo_httpd_t* httpd;
    69.  
    70. // the method
    71. tb_size_t method;
    72.  
    73. // the file offset
    74. tb_hize_t file_offset;
    75.  
    76. // the content size
    77. tb_hize_t content_size;
    78.  
    79. // the version
    80. tb_uint32_t version : 1;
    81.  
    82. // keep-alive?
    83. tb_uint32_t balived : 1;
    84.  
    85. // the recv and send buffer
    86. tb_byte_t buffer[TB_DEMO_HTTPD_SESSION_BUFF_MAXN];
    87.  
    88. }tb_demo_httpd_session_t;
    89.  
    90. /* //////////////////////////////////////////////////////////////////////////////////////
    91. * implementation
    92. */
    93. static tb_char_t const* tb_demo_httpd_code_cstr(tb_size_t code)
    94. {
    95. // done
    96. tb_char_t const* cstr = tb_null;
    97. switch (code)
    98. {
    99. case TB_HTTP_CODE_OK: cstr = "OK"; break;
    100. case TB_HTTP_CODE_BAD_REQUEST: cstr = "Bad Request"; break;
    101. case TB_HTTP_CODE_NOT_FOUND: cstr = "Not Found"; break;
    102. case TB_HTTP_CODE_NOT_IMPLEMENTED: cstr = "Not Implemented"; break;
    103. case TB_HTTP_CODE_NOT_MODIFIED: cstr = "Not Modified"; break;
    104. case TB_HTTP_CODE_INTERNAL_SERVER_ERROR: cstr = "Internal Server Error"; break;
    105. default: break;
    106. }
    107.  
    108. // check
    109. tb_assert_abort(cstr);
    110.  
    111. // ok?
    112. return cstr;
    113. }
    114. static tb_bool_t tb_demo_httpd_aico_clos(tb_aice_ref_t aice)
    115. {
    116. // check
    117. tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_CLOS, tb_false);
    118.  
    119. // trace
    120. tb_trace_d("aico[%p]: clos: %s", aice->aico, tb_state_cstr(aice->state));
    121.  
    122. // exit aico
    123. tb_aico_exit(aice->aico);
    124.  
    125. // ok
    126. return tb_true;
    127. }
    128. static tb_void_t tb_demo_httpd_session_exit(tb_demo_httpd_session_t* session)
    129. {
    130. // check
    131. tb_assert_and_check_return(session);
    132.  
    133. // clos aico
    134. if (session->aico) tb_aico_clos(session->aico, tb_demo_httpd_aico_clos, tb_null);
    135. session->aico = tb_null;
    136.  
    137. // exit file
    138. if (session->file) tb_file_exit(session->file);
    139. session->file = tb_null;
    140.  
    141. // exit cache
    142. tb_buffer_exit(&session->cache);
    143.  
    144. // exit line
    145. tb_string_exit(&session->line);
    146.  
    147. // exit path
    148. tb_string_exit(&session->path);
    149.  
    150. // clear status
    151. session->code = TB_HTTP_CODE_OK;
    152. session->index = 0;
    153. session->httpd = tb_null;
    154. session->method = TB_HTTP_METHOD_GET;
    155. session->version = 1;
    156. session->balived = 0;
    157. session->file_offset = 0;
    158. session->content_size = 0;
    159.  
    160. // exit it
    161. tb_free(session);
    162. }
    163. static tb_void_t tb_demo_httpd_session_keep(tb_demo_httpd_session_t* session)
    164. {
    165. // check
    166. tb_assert_and_check_return(session);
    167.  
    168. // exit file
    169. if (session->file) tb_file_exit(session->file);
    170. session->file = tb_null;
    171.  
    172. // clear cache
    173. tb_buffer_clear(&session->cache);
    174.  
    175. // clear line
    176. tb_string_clear(&session->line);
    177.  
    178. // clear path
    179. tb_string_clear(&session->path);
    180.  
    181. // clear some status
    182. session->code = TB_HTTP_CODE_OK;
    183. session->index = 0;
    184. session->method = TB_HTTP_METHOD_GET;
    185. session->file_offset = 0;
    186. session->content_size = 0;
    187. }
    188. static tb_demo_httpd_session_t* tb_demo_httpd_session_init(tb_demo_httpd_t* httpd, tb_aico_ref_t aico)
    189. {
    190. // check
    191. tb_assert_and_check_return_val(httpd && httpd->aicp && aico, tb_null);
    192.  
    193. // done
    194. tb_bool_t ok = tb_false;
    195. tb_demo_httpd_session_t* session = tb_null;
    196. do
    197. {
    198. // make session
    199. session = tb_malloc0_type(tb_demo_httpd_session_t);
    200. tb_assert_and_check_break(session);
    201.  
    202. // init session
    203. session->httpd = httpd;
    204. session->aico = aico;
    205. session->code = TB_HTTP_CODE_OK;
    206. session->version = 1;
    207. session->balived = 0;
    208. session->method = TB_HTTP_METHOD_GET;
    209. session->file_offset = 0;
    210. session->content_size = 0;
    211.  
    212. // init path
    213. if (!tb_string_init(&session->path)) break;
    214.  
    215. // init line
    216. if (!tb_string_init(&session->line)) break;
    217.  
    218. // init cache
    219. if (!tb_buffer_init(&session->cache)) break;
    220.  
    221. // init timeout
    222. tb_aico_timeout_set(session->aico, TB_AICO_TIMEOUT_SEND, TB_DEMO_HTTPD_SESSION_TIMEOUT);
    223. tb_aico_timeout_set(session->aico, TB_AICO_TIMEOUT_RECV, TB_DEMO_HTTPD_SESSION_TIMEOUT);
    224.  
    225. // ok
    226. ok = tb_true;
    227.  
    228. } while (0);
    229.  
    230. // failed?
    231. if (!ok)
    232. {
    233. // exit session
    234. if (session) tb_demo_httpd_session_exit(session);
    235. session = tb_null;
    236. }
    237.  
    238. // ok?
    239. return session;
    240. }
    241. static tb_bool_t tb_demo_httpd_session_head_recv(tb_aice_ref_t aice);
    242. static tb_void_t tb_demo_httpd_session_resp_exit(tb_demo_httpd_session_t* session)
    243. {
    244. // keep-alived?
    245. tb_bool_t ok = tb_false;
    246. if (session->balived && session->aico)
    247. {
    248. // keep session
    249. tb_demo_httpd_session_keep(session);
    250.  
    251. // recv the header
    252. ok = tb_aico_recv(session->aico, session->buffer, sizeof(session->buffer), tb_demo_httpd_session_head_recv, session);
    253. }
    254.  
    255. // exit session
    256. if (!ok) tb_demo_httpd_session_exit(session);
    257. }
    258. static tb_bool_t tb_demo_httpd_session_resp_send_file(tb_aice_ref_t aice)
    259. {
    260. // check
    261. tb_assert_and_check_return_val(aice && aice->code == TB_AICE_CODE_SENDF, tb_false);
    262.  
    263. // the session
    264. tb_demo_httpd_session_t* session = (tb_demo_httpd_session_t*)aice->priv;
    265. tb_assert_and_check_return_val(session, tb_false);
    266.  
    267. // done
    268. tb_bool_t ok = tb_false;
    269. do
    270. {
    271. // ok?
    272. tb_check_break(aice->state == TB_STATE_OK);
    273.  
    274. // trace
    275. tb_trace_d("resp_send_file[%p]: real: %lu, size: %llu", aice->aico, aice->u.sendf.real, aice->u.sendf.size);
    276.  
    277. // save offset
    278. session->file_offset += aice->u.sendf.real;
    279.  
    280. // continue to send it?
    281. if (aice->u.sendf.real < aice->u.sendf.size)
    282. {
    283. // send file
    284. ok = tb_aico_sendf(aice->aico, session->file, session->file_offset, aice->u.sendf.size - aice->u.sendf.real, tb_demo_httpd_session_resp_send_file, session);
    285. }
    286.  
    287. } while (0);
    288.  
    289. // finished or closed or failed?
    290. if (!ok)
    291. {
    292. // trace
    293. tb_trace_d("resp_send_file[%p]: state: %s", aice->aico, tb_state_cstr(aice->state));
    294.  
    295. // exit response
    296. tb_demo_httpd_session_resp_exit(session);
    297. }
    298.  
    299. // ok
    300. return tb_true;
    301. }
    302. static tb_bool_t tb_demo_httpd_session_resp_send_head(tb_aice_ref_t aice)
    303. {
    304. // check
    305. tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_SEND, tb_false);
    306.  
    307. // the session
    308. tb_demo_httpd_session_t* session = (tb_demo_httpd_session_t*)aice->priv;
    309. tb_assert_and_check_return_val(session, tb_false);
    310.  
    311. // done
    312. tb_bool_t ok = tb_false;
    313. do
    314. {
    315. // ok?
    316. tb_check_break(aice->state == TB_STATE_OK);
    317.  
    318. // trace
    319. tb_trace_d("resp_send_head[%p]: real: %lu, size: %lu", aice->aico, aice->u.send.real, aice->u.send.size);
    320.  
    321. // check data
    322. tb_assert_and_check_break(aice->u.send.data && aice->u.send.size);
    323.  
    324. // not finished?
    325. if (aice->u.send.real < aice->u.send.size)
    326. {
    327. // continue to send it
    328. ok = tb_aico_send(aice->aico, aice->u.send.data, aice->u.send.size - aice->u.send.real, tb_demo_httpd_session_resp_send_head, session);
    329. }
    330. // send file if exists
    331. else if (session->file)
    332. {
    333. // send file
    334. ok = tb_aico_sendf(aice->aico, session->file, session->file_offset, tb_file_size(session->file), tb_demo_httpd_session_resp_send_file, session);
    335. }
    336.  
    337. } while (0);
    338.  
    339. // not continue?
    340. if (!ok)
    341. {
    342. // trace
    343. tb_trace_d("resp_send_head[%p]: state: %s", aice->aico, tb_state_cstr(aice->state));
    344.  
    345. // exit response
    346. tb_demo_httpd_session_resp_exit(session);
    347. }
    348.  
    349. // ok
    350. return tb_true;
    351. }
    352. static tb_bool_t tb_demo_httpd_session_resp_send_done(tb_demo_httpd_session_t* session)
    353. {
    354. // check
    355. tb_assert_and_check_return_val(session, tb_false);
    356.  
    357. // format the error info
    358. tb_long_t size = tb_snprintf( (tb_char_t*)session->buffer
    359. , sizeof(session->buffer) - 1
    360. , "HTTP/1.%u %lu %s\r\n"
    361. "Server: %s\r\n"
    362. "Content-Type: text/html\r\n"
    363. "Content-Length: %llu\r\n"
    364. "Connection: %s\r\n"
    365. "\r\n"
    366. , session->version
    367. , session->code
    368. , tb_demo_httpd_code_cstr(session->code)
    369. , TB_VERSION_SHORT_STRING
    370. , session->file? tb_file_size(session->file) : 0
    371. , session->balived? "keep-alive" : "close");
    372.  
    373. tb_assert_and_check_return_val(size > 0, tb_false);
    374.  
    375. // end
    376. session->buffer[size] = '\0';
    377.  
    378. // trace
    379. tb_trace_d("response[%p]: %s", session->aico, session->buffer);
    380.  
    381. // send the error info
    382. return tb_aico_send(session->aico, session->buffer, size, tb_demo_httpd_session_resp_send_head, session);
    383. }
    384. static tb_bool_t tb_demo_httpd_session_reqt_done(tb_demo_httpd_session_t* session)
    385. {
    386. // check
    387. tb_assert_and_check_return_val(session && session->aico, tb_false);
    388.  
    389. // done
    390. tb_bool_t ok = tb_false;
    391. do
    392. {
    393. // check
    394. tb_check_break(session->code == TB_HTTP_CODE_OK);
    395. tb_assert_and_check_break(session->httpd);
    396.  
    397. // get?
    398. if (session->method == TB_HTTP_METHOD_GET)
    399. {
    400. // check path
    401. tb_check_break_state(tb_string_size(&session->path), session->code, TB_HTTP_CODE_BAD_REQUEST);
    402.  
    403. // the path
    404. tb_char_t const* path = tb_string_cstr(&session->path);
    405. tb_check_break_state(!session->file && path, session->code, TB_HTTP_CODE_INTERNAL_SERVER_ERROR);
    406.  
    407. // the full path
    408. tb_char_t full[TB_PATH_MAXN] = {0};
    409. tb_long_t size = tb_snprintf(full, sizeof(full) - 1, "%s%s%s", session->httpd->root, path[0] != '/'? "/" : "", path);
    410. tb_assert_abort(size > 0);
    411.  
    412. // end
    413. full[size] = '\0';
    414.  
    415. // trace
    416. tb_trace_d("reqt_done[%p]: full path: %s", session->aico, full);
    417.  
    418. // init file
    419. session->file = tb_file_init(full, TB_FILE_MODE_RO | TB_FILE_MODE_BINARY | TB_FILE_MODE_ASIO);
    420. tb_check_break_state(session->file, session->code, TB_HTTP_CODE_NOT_FOUND);
    421.  
    422. // send the file
    423. if (!tb_demo_httpd_session_resp_send_done(session)) return tb_false;
    424.  
    425. // ok
    426. ok = tb_true;
    427. }
    428. else
    429. {
    430. // not implemented
    431. session->code = TB_HTTP_CODE_NOT_IMPLEMENTED;
    432. break;
    433. }
    434.  
    435. } while (0);
    436.  
    437. // error?
    438. if (!ok)
    439. {
    440. // save code
    441. if (session->code == TB_HTTP_CODE_OK) session->code = TB_HTTP_CODE_INTERNAL_SERVER_ERROR;
    442.  
    443. // send the error info
    444. if (!tb_demo_httpd_session_resp_send_done(session)) return tb_false;
    445. }
    446.  
    447. // ok
    448. return tb_true;
    449. }
    450. static tb_bool_t tb_demo_httpd_session_head_done(tb_demo_httpd_session_t* session)
    451. {
    452. // check
    453. tb_assert_and_check_return_val(session, tb_false);
    454.  
    455. // the line and size
    456. tb_char_t const* line = tb_string_cstr(&session->line);
    457. tb_size_t size = tb_string_size(&session->line);
    458. tb_assert_and_check_return_val(line && size, tb_false);
    459.  
    460. // the first line?
    461. tb_char_t const* p = line;
    462. if (!session->index)
    463. {
    464. // check protocol
    465. if (tb_stristr(line, "HTTP/1.1")) session->version = 1;
    466. else if (tb_stristr(line, "HTTP/1.0")) session->version = 0;
    467. // bad request?
    468. else
    469. {
    470. // save code
    471. session->code = TB_HTTP_CODE_BAD_REQUEST;
    472. return tb_false;
    473. }
    474.  
    475. // parse get
    476. if (!tb_strnicmp(line, "GET", 3))
    477. {
    478. // save the method
    479. session->method = TB_HTTP_METHOD_GET;
    480.  
    481. // skip the method
    482. p += 3;
    483. }
    484. // parse post
    485. else if (!tb_strnicmp(line, "POST", 4))
    486. {
    487. // save the method
    488. session->method = TB_HTTP_METHOD_POST;
    489.  
    490. // save code
    491. session->code = TB_HTTP_CODE_NOT_IMPLEMENTED;
    492.  
    493. // skip the method
    494. p += 4;
    495. }
    496. else
    497. {
    498. // trace
    499. tb_trace_e("the method: %s is not supported now!", line);
    500.  
    501. // save code
    502. session->code = TB_HTTP_CODE_NOT_IMPLEMENTED;
    503. }
    504.  
    505. // get or post? parse the path
    506. if ( session->method == TB_HTTP_METHOD_GET
    507. || session->method == TB_HTTP_METHOD_POST)
    508. {
    509. // skip space
    510. while (*p && tb_isspace(*p)) p++;
    511.  
    512. // append path
    513. while (*p && !tb_isspace(*p)) tb_string_chrcat(&session->path, *p++);
    514. }
    515. }
    516. // key: value?
    517. else
    518. {
    519. // seek to value
    520. while (*p && *p != ':') p++;
    521. tb_assert_and_check_return_val(*p, tb_false);
    522. p++; while (*p && tb_isspace(*p)) p++;
    523.  
    524. // no value
    525. tb_check_return_val(*p, tb_true);
    526.  
    527. // parse content-length
    528. if (!tb_strnicmp(line, "Content-Length", 14))
    529. {
    530. // the content size
    531. session->content_size = tb_stou64(p);
    532. }
    533. // parse connection
    534. else if (!tb_strnicmp(line, "Connection", 10))
    535. {
    536. // keep-alive?
    537. session->balived = !tb_stricmp(p, "keep-alive")? 1 : 0;
    538. }
    539. // parse accept-encoding
    540. else if (!tb_strnicmp(line, "Accept-Encoding", 15))
    541. {
    542. }
    543. // parse accept
    544. else if (!tb_strnicmp(line, "Accept", 6))
    545. {
    546. }
    547. // parse cookie
    548. else if (!tb_strnicmp(line, "Cookie", 6))
    549. {
    550. }
    551. // parse range
    552. else if (!tb_strnicmp(line, "Range", 5))
    553. {
    554. // save code
    555. session->code = TB_HTTP_CODE_NOT_IMPLEMENTED;
    556. }
    557. // parse host
    558. else if (!tb_strnicmp(line, "Host", 4))
    559. {
    560. }
    561. }
    562.  
    563. // ok
    564. return tb_true;
    565. }
    566. static tb_bool_t tb_demo_httpd_session_head_recv(tb_aice_ref_t aice)
    567. {
    568. // check
    569. tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_RECV, tb_false);
    570.  
    571. // the session
    572. tb_demo_httpd_session_t* session = (tb_demo_httpd_session_t*)aice->priv;
    573. tb_assert_and_check_return_val(session, tb_false);
    574.  
    575. // done
    576. tb_bool_t state = tb_false;
    577. do
    578. {
    579. // ok?
    580. tb_check_break(aice->state == TB_STATE_OK);
    581.  
    582. // trace
    583. tb_trace_d("head_recv[%p]: real: %lu, size: %lu", aice->aico, aice->u.recv.real, aice->u.recv.size);
    584.  
    585. // check
    586. tb_assert_and_check_break(aice->u.recv.data);
    587.  
    588. // done
    589. tb_long_t ok = 0;
    590. tb_char_t ch = '\0';
    591. tb_char_t const* p = (tb_char_t const*)aice->u.recv.data;
    592. tb_char_t const* e = p + aice->u.recv.size;
    593. while (p < e)
    594. {
    595. // the char
    596. ch = *p++;
    597.  
    598. // error end?
    599. if (!ch)
    600. {
    601. ok = -1;
    602. break;
    603. }
    604.  
    605. // append char to line
    606. if (ch != '\n') tb_string_chrcat(&session->line, ch);
    607. // is line end?
    608. else
    609. {
    610. // strip '\r' if exists
    611. tb_char_t const* pb = tb_string_cstr(&session->line);
    612. tb_size_t pn = tb_string_size(&session->line);
    613. if (!pb || !pn)
    614. {
    615. ok = -1;
    616. tb_assert(0);
    617. break;
    618. }
    619.  
    620. // line end? strip '\r\n'
    621. if (pb[pn - 1] == '\r') tb_string_strip(&session->line, pn - 1);
    622.  
    623. // trace
    624. tb_trace_d("head_recv[%p]: %s", aice->aico, pb);
    625.  
    626. // end?
    627. if (!tb_string_size(&session->line))
    628. {
    629. // ok
    630. ok = 1;
    631. break;
    632. }
    633.  
    634. // done the head request
    635. if (!tb_demo_httpd_session_head_done(session))
    636. {
    637. // error
    638. ok = -1;
    639. break;
    640. }
    641.  
    642. // clear line
    643. tb_string_clear(&session->line);
    644.  
    645. // update index
    646. session->index++;
    647. }
    648. }
    649.  
    650. // continue?
    651. if (!ok)
    652. {
    653. // recv the header
    654. if (!tb_aico_recv(aice->aico, session->buffer, sizeof(session->buffer), tb_demo_httpd_session_head_recv, session)) break;
    655. }
    656. // end?
    657. else if (ok > 0)
    658. {
    659. // trace
    660. tb_trace_d("head_recv[%p]: end, left: %lu", aice->aico, e - p);
    661.  
    662. // save the left data to the cache
    663. tb_buffer_memncpy(&session->cache, (tb_byte_t const*)p, e - p);
    664.  
    665. // trace
    666. tb_trace_d("head_recv[%p]: ok", aice->aico);
    667.  
    668. // done request
    669. if (!tb_demo_httpd_session_reqt_done(session)) break;
    670. }
    671. // failed?
    672. else
    673. {
    674. // trace
    675. tb_trace_e("head_recv[%p]: failed", aice->aico);
    676. break;
    677. }
    678.  
    679. // ok
    680. state = tb_true;
    681.  
    682. } while (0);
    683.  
    684. // closed or failed?
    685. if (!state)
    686. {
    687. // trace
    688. tb_trace_d("head_recv[%p]: state: %s", aice->aico, tb_state_cstr(aice->state));
    689.  
    690. // exit session
    691. tb_demo_httpd_session_exit(session);
    692. }
    693.  
    694. // ok
    695. return tb_true;
    696. }
    697. static tb_void_t tb_demo_httpd_exit(tb_demo_httpd_t* httpd)
    698. {
    699. // check
    700. tb_assert_and_check_return(httpd);
    701.  
    702. // trace
    703. tb_trace_d("exit");
    704.  
    705. // clear aico
    706. httpd->aico = tb_null;
    707.  
    708. // exit it
    709. tb_free(httpd);
    710. }
    711. static tb_demo_httpd_t* tb_demo_httpd_init(tb_char_t const* root)
    712. {
    713. // done
    714. tb_bool_t ok = tb_false;
    715. tb_demo_httpd_t* httpd = tb_null;
    716. do
    717. {
    718. // make httpd
    719. httpd = tb_malloc0_type(tb_demo_httpd_t);
    720. tb_assert_and_check_break(httpd);
    721.  
    722. // init root
    723. if (root) tb_strlcpy(httpd->root, root, sizeof(httpd->root));
    724. else tb_directory_curt(httpd->root, sizeof(httpd->root));
    725. httpd->root[sizeof(httpd->root) - 1] = '\0';
    726. tb_assert_and_check_break(tb_file_info(httpd->root, tb_null));
    727.  
    728. // init port
    729. httpd->port = TB_DEMO_HTTPD_PORT;
    730.  
    731. // trace
    732. tb_trace_d("init: %s: %u", httpd->root, httpd->port);
    733.  
    734. // init aicp
    735. httpd->aicp = tb_aicp();
    736. tb_assert_and_check_break(httpd->aicp);
    737.  
    738. // init aico
    739. httpd->aico = tb_aico_init(httpd->aicp);
    740. tb_assert_and_check_break(httpd->aico);
    741.  
    742. // open aico
    743. if (!tb_aico_open_sock_from_type(httpd->aico, TB_SOCKET_TYPE_TCP)) break;
    744.  
    745. // bind port
    746. if (!tb_socket_bind(tb_aico_sock(httpd->aico), tb_null, httpd->port)) break;
    747.  
    748. // listen sock
    749. if (!tb_socket_listen(tb_aico_sock(httpd->aico), TB_DEMO_HTTPD_SESSION_MAXN >> 2)) break;
    750.  
    751. // ok
    752. ok = tb_true;
    753.  
    754. } while (0);
    755.  
    756. // failed?
    757. if (!ok)
    758. {
    759. // exit httpd
    760. if (httpd) tb_demo_httpd_exit(httpd);
    761. httpd = tb_null;
    762. }
    763.  
    764. // ok?
    765. return httpd;
    766. }
    767. static tb_bool_t tb_demo_httpd_acpt(tb_aice_ref_t aice)
    768. {
    769. // check
    770. tb_assert_and_check_return_val(aice && aice->aico && aice->code == TB_AICE_CODE_ACPT, tb_false);
    771.  
    772. // the httpd
    773. tb_demo_httpd_t* httpd = (tb_demo_httpd_t*)aice->priv;
    774. tb_assert_and_check_return_val(httpd && httpd->aicp, tb_false);
    775.  
    776. // done
    777. tb_bool_t ok = tb_false;
    778. tb_demo_httpd_session_t* session = tb_null;
    779. do
    780. {
    781. // ok?
    782. tb_check_break(aice->state == TB_STATE_OK);
    783.  
    784. // check
    785. tb_assert_and_check_break(aice->u.acpt.aico);
    786.  
    787. // trace
    788. tb_trace_d("acpt[%p]: aico: %p, addr: %u.%u.%u.%u, port: %u", aice->aico, aice->u.acpt.aico, tb_ipv4_u8x4(aice->u.acpt.addr), aice->u.acpt.port);
    789.  
    790. // init the session
    791. session = tb_demo_httpd_session_init(httpd, aice->u.acpt.aico);
    792. tb_assert_and_check_break(session && session->aico);
    793.  
    794. // recv the header
    795. if (!tb_aico_recv(session->aico, session->buffer, sizeof(session->buffer), tb_demo_httpd_session_head_recv, session)) break;
    796.  
    797. // ok
    798. ok = tb_true;
    799.  
    800. } while (0);
    801.  
    802. // failed?
    803. if (!ok)
    804. {
    805. // trace
    806. tb_trace_d("acpt[%p]: state: %s", aice->aico, tb_state_cstr(aice->state));
    807.  
    808. // exit session
    809. if (session) tb_demo_httpd_session_exit(session);
    810. session = tb_null;
    811.  
    812. // clos aico
    813. if (aice->aico) tb_aico_clos(aice->aico, tb_demo_httpd_aico_clos, tb_null);
    814. }
    815.  
    816. // ok
    817. return tb_true;
    818. }
    819. static tb_void_t tb_demo_httpd_done(tb_demo_httpd_t* httpd)
    820. {
    821. // check
    822. tb_assert_and_check_return(httpd && httpd->aicp && httpd->aico);
    823.  
    824. // done listen
    825. if (!tb_aico_acpt(httpd->aico, tb_demo_httpd_acpt, httpd)) return ;
    826.  
    827. // wait some time
    828. getchar();
    829. }
    830.  
    831.  
    832. /* //////////////////////////////////////////////////////////////////////////////////////
    833. * main
    834. */
    835. tb_int_t main(tb_int_t argc, tb_char_t** argv)
    836. {
    837. // init tbox
    838. if (!tb_init(tb_null, tb_null, 0)) return 0;
    839.  
    840. // init httpd
    841. tb_demo_httpd_t* httpd = tb_demo_httpd_init(argv[1]);
    842. if (httpd)
    843. {
    844. // done httpd
    845. tb_demo_httpd_done(httpd);
    846.  
    847. // exit httpd
    848. tb_demo_httpd_exit(httpd);
    849. }
    850.  
    851. // exit tbox
    852. tb_exit();
    853. return 0;
    854. }