PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/share/dexatek/Service/HTTPd.c

https://bitbucket.org/DexaSamTsai/dxdoorcam_development
C | 772 lines | 616 code | 131 blank | 25 comment | 181 complexity | c0da8c5175eb4113a0abf0affe954e6f MD5 | raw file
Possible License(s): 0BSD
  1. /*!
  2. * @file HTTPd.c
  3. * @version 0.01
  4. * @author Sam Tsai
  5. */
  6. //==========================================================================
  7. // Include Files
  8. //==========================================================================
  9. #include "HTTPd.h"
  10. #include "Socket.h"
  11. #include "HTTP.h"
  12. //==========================================================================
  13. // Type Definition
  14. //==========================================================================
  15. typedef struct {
  16. Httpd_CGIContext context;
  17. void *next;
  18. } httpd_cgi_t;
  19. typedef struct {
  20. u32 status;
  21. int http_fd;
  22. int https_fd;
  23. int p_id;
  24. struct sockaddr_in client_addr;
  25. http_info_t http;
  26. char username[ 64 ];
  27. u32 last_keep_alive;
  28. struct timeval start_time;
  29. httpd_cgi_t *cgi_handle;
  30. void *next;
  31. } httpd_service_t;
  32. typedef struct httpd_location httpd_location;
  33. struct httpd_location{
  34. char *location;
  35. int len;
  36. httpd_location *next;
  37. };
  38. //==========================================================================
  39. // Public Param
  40. //==========================================================================
  41. //==========================================================================
  42. // Static Param
  43. //==========================================================================
  44. static struct {
  45. int ready;
  46. int p_id;
  47. int http_fd;
  48. int https_fd;
  49. int stream_num;
  50. char root[ 128 ];
  51. char homepage[ 128 ];
  52. char server_name[ 128 ];
  53. u32 auth_type;
  54. u16 http_port;
  55. u16 https_port;
  56. } httpd_server = { 0, };
  57. static httpd_service_t *httpd_services = NULL;
  58. static pthread_mutex_t httpd_server_mutex = PTHREAD_MUTEX_INITIALIZER;
  59. static httpd_cgi_t *httpd_cgis = NULL;
  60. static pthread_mutex_t httpd_cgi_mutex = PTHREAD_MUTEX_INITIALIZER;
  61. static httpd_location *httpd_locations = NULL;
  62. static pthread_mutex_t httpd_location_mutex = PTHREAD_MUTEX_INITIALIZER;
  63. //==========================================================================
  64. // Static Functions
  65. //==========================================================================
  66. static int
  67. montoi( const char *s )
  68. {
  69. static const char *ar[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  70. size_t i;
  71. for ( i = 0; i < 12; i ++ ) {
  72. if ( strcmp( s, ar[ i ] ) == 0 ) {
  73. return i;
  74. }
  75. }
  76. return -1;
  77. }
  78. static time_t
  79. datetosec( const char *s )
  80. {
  81. struct tm stm;
  82. char mon[ 32 ];
  83. int sec, min, hour, mday, month, year;
  84. memset( &stm, 0, sizeof( stm ) );
  85. sec = min = hour = mday = month = year = 0;
  86. if ( ( ( sscanf( s, "%d/%3s/%d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) &&
  87. ( sscanf( s, "%d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) &&
  88. ( sscanf( s, "%*3s, %d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) &&
  89. ( sscanf( s, "%d-%3s-%d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) ) &&
  90. ( month = montoi( mon ) ) != -1 ) {
  91. stm.tm_mday = mday;
  92. stm.tm_mon = month;
  93. stm.tm_year = year;
  94. stm.tm_hour = hour;
  95. stm.tm_min = min;
  96. stm.tm_sec = sec;
  97. }
  98. if ( stm.tm_year > 1900 ) {
  99. stm.tm_year -= 1900;
  100. } else if ( stm.tm_year < 70 ) {
  101. stm.tm_year += 100;
  102. }
  103. return ( mktime( &stm ) );
  104. }
  105. static int
  106. httpd_service_remove( httpd_service_t *service )
  107. {
  108. int res = FAILURE;
  109. pthread_mutex_lock( &httpd_server_mutex );
  110. if ( httpd_services == service ) {
  111. httpd_services = service->next;
  112. res = SUCCESS;
  113. } else if ( httpd_services ) {
  114. httpd_service_t *s = httpd_services;
  115. while ( s->next ) {
  116. if ( s->next == service ) {
  117. s->next = service->next;
  118. res = SUCCESS;
  119. break;
  120. }
  121. s = s->next;
  122. }
  123. }
  124. pthread_mutex_unlock( &httpd_server_mutex );
  125. return res;
  126. }
  127. static int
  128. httpd_service_insert( httpd_service_t *service )
  129. {
  130. int res = FAILURE;
  131. pthread_mutex_lock( &httpd_server_mutex );
  132. if ( httpd_services == NULL ) {
  133. httpd_services = service;
  134. res = SUCCESS;
  135. } else {
  136. httpd_service_t *s = httpd_services;
  137. while ( s->next ) {
  138. s = s->next;
  139. }
  140. s->next = service;
  141. service->next = NULL;
  142. res = SUCCESS;
  143. }
  144. pthread_mutex_unlock( &httpd_server_mutex );
  145. return res;
  146. }
  147. static BOOL
  148. httpd_service_exist( httpd_service_t *service )
  149. {
  150. BOOL res = FALSE;
  151. pthread_mutex_lock( &httpd_server_mutex );
  152. httpd_service_t *s = httpd_services;
  153. while ( s ) {
  154. if ( s == service ) {
  155. res = TRUE;
  156. break;
  157. }
  158. s = s->next;
  159. }
  160. pthread_mutex_unlock( &httpd_server_mutex );
  161. return res;
  162. }
  163. static httpd_cgi_t *
  164. httpd_cgi_find_handle( char *url )
  165. {
  166. httpd_cgi_t *u;
  167. char *pos;
  168. pthread_mutex_lock( &httpd_cgi_mutex );
  169. u = httpd_cgis;
  170. while ( u ) {
  171. pos = strstr( url, u->context.url );
  172. if ( pos && ( pos[ strlen( u->context.url ) ] == 0 ) ) {
  173. pthread_mutex_unlock( &httpd_cgi_mutex );
  174. return u;
  175. }
  176. u = u->next;
  177. }
  178. pthread_mutex_unlock( &httpd_cgi_mutex );
  179. return NULL;
  180. }
  181. static int
  182. httpd_cgi_insert( httpd_cgi_t *cgi )
  183. {
  184. int res = FAILURE;
  185. pthread_mutex_lock( &httpd_cgi_mutex );
  186. if ( httpd_cgis == NULL ) {
  187. httpd_cgis = cgi;
  188. res = SUCCESS;
  189. } else {
  190. httpd_cgi_t *u = httpd_cgis;
  191. while ( u->next ) {
  192. u = u->next;
  193. }
  194. u->next = cgi;
  195. cgi->next = NULL;
  196. res = SUCCESS;
  197. }
  198. pthread_mutex_unlock( &httpd_cgi_mutex );
  199. return res;
  200. }
  201. static void
  202. httpd_send_system_error( int client_fd, int code, char *reason )
  203. {
  204. char dst[ 256 ], size = 0;
  205. size = sprintf( dst, "HTTP/1.0 %d %s\r\n\r\n", code, reason );
  206. Socket_Send( client_fd, dst, size );
  207. }
  208. static int
  209. web_send_result( httpd_service_t *httpd, int code )
  210. {
  211. httpd->http.status = code;
  212. if ( http_build_reply_header( httpd_server.server_name, httpd->http.uri, &httpd->http ) > 0 ) {
  213. int res = Socket_Send( httpd->http_fd, httpd->http.rw.buf, httpd->http.rw.size );
  214. httpd->http.rw.size = 0;
  215. if ( res <= 0 ) {
  216. return FAILURE;
  217. } else {
  218. return SUCCESS;
  219. }
  220. } else {
  221. return FAILURE;
  222. }
  223. }
  224. static int
  225. httpd_do_get( httpd_service_t *httpd )
  226. {
  227. int send_len;
  228. web_send_result( httpd, 200 );
  229. while ( httpd->http.fd > 0 ) {
  230. httpd->http.rw.size = read( httpd->http.fd, httpd->http.rw.buf, IO_MAX );
  231. if ( httpd->http.rw.size <= 0 ) {
  232. return FAILURE;
  233. }
  234. send_len = Socket_Send( httpd->http_fd, httpd->http.rw.buf, httpd->http.rw.size );
  235. if ( send_len < 0 ) {
  236. return FAILURE;
  237. }
  238. }
  239. return FAILURE;
  240. }
  241. static int
  242. httpd_do_post( httpd_service_t *httpd )
  243. {
  244. // Not Support
  245. return FAILURE;
  246. }
  247. static int
  248. httpd_do_request( httpd_service_t *httpd )
  249. {
  250. if ( httpd->cgi_handle ) {
  251. if ( httpd->http.http_method == METHOD_GET ) {
  252. if ( httpd->cgi_handle->context.cgi_get ) {
  253. return httpd->cgi_handle->context.cgi_get( httpd, httpd->http_fd );
  254. }
  255. } else if ( httpd->http.http_method == METHOD_POST ) {
  256. if ( httpd->cgi_handle->context.cgi_post ) {
  257. return httpd->cgi_handle->context.cgi_post( httpd, httpd->http_fd );
  258. }
  259. }
  260. } else {
  261. if ( httpd->http.http_method == METHOD_GET ) {
  262. return httpd_do_get( httpd );
  263. } else if ( httpd->http.http_method == METHOD_POST ) {
  264. return httpd_do_post( httpd );
  265. }
  266. }
  267. return FAILURE;
  268. }
  269. static int
  270. httpd_parse_request( httpd_service_t *httpd )
  271. {
  272. char *temp;
  273. int res = SUCCESS;
  274. if ( httpd->http.uri[ 1 ] == 0 ) {
  275. sprintf( httpd->http.uri, "%s", httpd_server.homepage );
  276. } else {
  277. char *uri = strdup( httpd->http.uri );
  278. if ( httpd->http.uri[ 1 ] == '?' ) {
  279. sprintf( httpd->http.uri, "%s%s", httpd_server.homepage, uri + 1 );
  280. } else {
  281. char *path = httpd_server.root;
  282. httpd_location *loc = httpd_locations;
  283. while ( loc ) {
  284. if ( strncmp( loc->location, uri, loc->len ) == 0 ) {
  285. path = NULL;
  286. break;
  287. }
  288. loc = loc->next;
  289. }
  290. if ( path ) {
  291. sprintf( httpd->http.uri, "%s%s", path, uri );
  292. }
  293. }
  294. if ( ( temp = strchr( httpd->http.uri, '?' ) ) ) {
  295. http_parser_cgi( temp, httpd->http.env, MAX_HTTP_PARAM );
  296. temp[ 0 ] = 0;
  297. }
  298. free( uri );
  299. }
  300. if ( ( temp = http_get_field( httpd->http.http_env, "If-Modified-Since", MAX_HTTP_TAG ) ) ) {
  301. httpd->http.ims = datetosec( temp );
  302. }
  303. httpd->http.keep_alive = 0;
  304. if ( ( temp = http_get_field( httpd->http.http_env, "Connection", MAX_HTTP_TAG ) ) ) {
  305. if ( strstr( temp, "keep-alive" ) ) {
  306. httpd->http.keep_alive = 1;
  307. }
  308. }
  309. if ( ( temp = http_get_field( httpd->http.http_env, "Content-Length", MAX_HTTP_TAG ) ) ) {
  310. httpd->http.cclength = atoi( temp );
  311. } else {
  312. httpd->http.cclength = 0;
  313. }
  314. if ( ( httpd_server.auth_type != WEB_AUTH_TYPE_NONE ) &&
  315. ( http_check_auth( &httpd->http, httpd->http.method, httpd->username ) < 0 ) ) {
  316. web_send_result( httpd, 401 );
  317. return SUCCESS;
  318. } else if ( !strcasecmp( httpd->http.method, "GET" ) ) {
  319. httpd->http.http_method = METHOD_GET;
  320. } else if ( !strcasecmp( httpd->http.method, "POST" ) ) {
  321. httpd->http.http_method = METHOD_POST;
  322. } else if ( !strcasecmp( httpd->http.method, "HEAD" ) ) {
  323. httpd->http.http_method = METHOD_GET;
  324. } else {
  325. dbg_line( "UN-Know Method %s\n", httpd->http.method );
  326. web_send_result( httpd, 501 );
  327. return FAILURE;
  328. }
  329. if ( stat( httpd->http.uri, &httpd->http.st ) == 0 ) {
  330. if ( S_ISREG( httpd->http.st.st_mode ) ) {
  331. httpd->http.cclength = httpd->http.st.st_size;
  332. if ( ( httpd->http.fd = open( httpd->http.uri, O_RDONLY, 0644 ) ) < 0 ) {
  333. web_send_result( httpd, 500 );
  334. return FAILURE;
  335. }
  336. } else {
  337. web_send_result( httpd, 403 );
  338. return FAILURE;
  339. }
  340. } else {
  341. httpd->cgi_handle = httpd_cgi_find_handle( httpd->http.uri );
  342. if ( httpd->cgi_handle == NULL ) {
  343. web_send_result( httpd, 404 );
  344. return FAILURE;
  345. }
  346. }
  347. return res;
  348. }
  349. static int
  350. httpd_read_header( httpd_service_t *httpd )
  351. {
  352. int res;
  353. u32 start_clock = seconds();
  354. u32 curr_clock;
  355. Socket_SetBlockMode( httpd->http_fd, 0 );
  356. while ( TRUE ) {
  357. if ( Socket_isReadable( httpd->http_fd ) ) {
  358. int recv_size = IO_MAX - httpd->http.header.size;
  359. if ( httpd->http.header.size < 32 ) {
  360. if ( recv_size > 64 ) {
  361. recv_size = 64;
  362. }
  363. } else {
  364. if ( recv_size > 12 ) {
  365. recv_size = 12;
  366. }
  367. }
  368. if ( ( res = Socket_Recv( httpd->http_fd, &httpd->http.header.buf[ httpd->http.header.size ], recv_size ) ) < 0 ) {
  369. return NET_ERR_CONNECT_FAIL;
  370. } else if ( res == 0 ) {
  371. return NET_ERR_DISCONNECT;
  372. }
  373. httpd->http.header.size += res;
  374. httpd->http.header.buf[ httpd->http.header.size ] = 0;
  375. res = http_parser_request( &httpd->http );
  376. if ( res < 0 ) {
  377. dbg_line();
  378. return res;
  379. } else if ( res > 0 ) {
  380. break;
  381. }
  382. }
  383. curr_clock = seconds();
  384. if ( ( start_clock + 10 ) < curr_clock ) {
  385. return NET_ERR_RECV_TIMEOUT;
  386. }
  387. }
  388. Socket_SetBlockMode( httpd->http_fd, 1 );
  389. return SUCCESS;
  390. }
  391. static void
  392. httpd_free( httpd_service_t *httpd )
  393. {
  394. httpd_service_remove( httpd );
  395. if ( httpd->http_fd > 0 ) {
  396. Socket_Disconnect( httpd->http_fd );
  397. }
  398. if ( httpd->https_fd > 0 ) {
  399. Socket_Disconnect( httpd->https_fd );
  400. }
  401. if ( httpd->http.fd > 0 ) {
  402. close( httpd->http.fd );
  403. }
  404. http_release( &httpd->http );
  405. my_free( httpd );
  406. }
  407. static void *
  408. httpd_service_proccess( void *arg )
  409. {
  410. httpd_service_t *httpd = ( httpd_service_t * )arg;
  411. while ( httpd->http.http_method == METHOD_NONE ) {
  412. if ( httpd_read_header( httpd ) != SUCCESS ) {
  413. break;
  414. } else if ( httpd_parse_request( httpd ) != SUCCESS ) {
  415. break;
  416. } else if ( httpd->http.http_method ) {
  417. if ( httpd_do_request( httpd ) != SUCCESS ) {
  418. break;
  419. }
  420. }
  421. }
  422. MSleep( 50 );
  423. httpd_free( httpd );
  424. return NULL;
  425. }
  426. static void *
  427. httpd_accept( void *arg )
  428. {
  429. int client_fd;
  430. struct sockaddr_in client_addr;
  431. // Receiving Streaming
  432. while ( 1 ) {
  433. if ( Socket_isReadable( httpd_server.http_fd ) > 0 ) {
  434. client_fd = Socket_Accept( httpd_server.http_fd, &client_addr, 1 );
  435. if ( client_fd > 0 ) {
  436. httpd_service_t *httpd = ( httpd_service_t * )my_malloc( sizeof( httpd_service_t ) );
  437. if ( httpd ) {
  438. httpd->http_fd = client_fd;
  439. httpd->client_addr = client_addr;
  440. httpd_service_insert( httpd );
  441. httpd->p_id = create_norm_thread( httpd_service_proccess, httpd, 0 );
  442. } else {
  443. dbg_line( "Do my_malloc Failed!!!" );
  444. httpd_send_system_error( client_fd, 503, "Service Unavailable" );
  445. }
  446. }
  447. }
  448. }
  449. return NULL;
  450. }
  451. //==========================================================================
  452. // APIs
  453. //==========================================================================
  454. const char *
  455. Httpd_GetHeaderField( HttpdHandle handle, char *field )
  456. {
  457. if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
  458. httpd_service_t *httpd = ( httpd_service_t * )handle;
  459. return http_get_field( httpd->http.http_env, field, MAX_HTTP_TAG );
  460. } else {
  461. return NULL;
  462. }
  463. }
  464. const char *
  465. Httpd_GetCGIField( HttpdHandle handle, char *field )
  466. {
  467. if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
  468. httpd_service_t *httpd = ( httpd_service_t * )handle;
  469. return http_get_field( httpd->http.env, field, MAX_HTTP_TAG );
  470. } else {
  471. return NULL;
  472. }
  473. }
  474. int
  475. Httpd_SendHttpHeader( HttpdHandle handle, char *url, int code )
  476. {
  477. if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
  478. httpd_service_t *httpd = ( httpd_service_t * )handle;
  479. if ( url ) {
  480. sprintf( httpd->http.uri, "%s", url );
  481. }
  482. return web_send_result( httpd, code );
  483. } else {
  484. return FAILURE;
  485. }
  486. }
  487. int
  488. Httpd_SendResponse( HttpdHandle handle, char *url, char *data, int size )
  489. {
  490. if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
  491. httpd_service_t *httpd = ( httpd_service_t * )handle;
  492. if ( url ) {
  493. sprintf( httpd->http.uri, "%s", url );
  494. }
  495. httpd->http.st.st_size = size;
  496. if ( web_send_result( httpd, 200 ) == SUCCESS ) {
  497. return Socket_Send( httpd->http_fd, data, size );
  498. } else {
  499. return FAILURE;
  500. }
  501. } else {
  502. return FAILURE;
  503. }
  504. }
  505. int
  506. Httpd_RecvHttpHeader( HttpdHandle handle )
  507. {
  508. if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
  509. httpd_service_t *httpd = ( httpd_service_t * )handle;
  510. httpd->http.header.size = 0;
  511. if ( httpd_read_header( httpd ) != SUCCESS ) {
  512. return FAILURE;
  513. } else if ( httpd_parse_request( httpd ) != SUCCESS ) {
  514. return FAILURE;
  515. } else {
  516. return SUCCESS;
  517. }
  518. } else {
  519. return FAILURE;
  520. }
  521. }
  522. int
  523. Httpd_RecvData( HttpdHandle handle, u8 **data )
  524. {
  525. if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
  526. httpd_service_t *httpd = ( httpd_service_t * )handle;
  527. if ( httpd->http.cclength ) {
  528. *data = ( u8 * )my_malloc( ( httpd->http.cclength + 4 ) );
  529. if ( *data ) {
  530. int size = 0, res;
  531. char *dst = ( char * )*data;
  532. if ( httpd->http.rw.size ) {
  533. if ( httpd->http.rw.size > httpd->http.cclength ) {
  534. memcpy( *data, httpd->http.rw.buf, httpd->http.cclength );
  535. httpd->http.rw.size -= httpd->http.cclength;
  536. memcpy( httpd->http.rw.buf, &httpd->http.rw.buf[ httpd->http.cclength ], httpd->http.rw.size );
  537. return httpd->http.cclength;
  538. } else {
  539. memcpy( *data, httpd->http.rw.buf, httpd->http.rw.size );
  540. size = httpd->http.rw.size;
  541. dst += size;
  542. }
  543. }
  544. while ( size < httpd->http.cclength ) {
  545. if ( Socket_isWritable( httpd->http_fd ) ) {
  546. res = Socket_Recv( httpd->http_fd, dst, ( httpd->http.cclength - size ) );
  547. if ( res <= 0 ) {
  548. my_free( *data );
  549. return FAILURE;
  550. }
  551. size += res;
  552. } else {
  553. MSleep( 50 );
  554. }
  555. }
  556. return httpd->http.cclength;
  557. } else {
  558. return 0;
  559. }
  560. } else {
  561. return 0;
  562. }
  563. } else {
  564. return FAILURE;
  565. }
  566. }
  567. int
  568. Httpd_RegCGIService( Httpd_CGIContext *context )
  569. {
  570. if ( context ) {
  571. httpd_cgi_t *cgi = ( httpd_cgi_t * )my_malloc( sizeof( httpd_cgi_t ) );
  572. if ( cgi ) {
  573. memcpy( &cgi->context, context, sizeof( Httpd_CGIContext ) );
  574. httpd_cgi_insert( cgi );
  575. return SUCCESS;
  576. }
  577. }
  578. return FAILURE;
  579. }
  580. int
  581. Httpd_SetContext( Httpd_ServerContext *context )
  582. {
  583. return SUCCESS;
  584. }
  585. int
  586. Httpd_AddLocation( char *location )
  587. {
  588. int res = FAILURE;
  589. if ( location ) {
  590. httpd_location *loc = ( httpd_location * )my_malloc( sizeof( httpd_location ) );
  591. if ( loc ) {
  592. loc->location = my_strdup( location );
  593. loc->len = strlen( location );
  594. pthread_mutex_lock( &httpd_location_mutex );
  595. if ( httpd_locations == NULL ) {
  596. httpd_locations = loc;
  597. res = SUCCESS;
  598. } else {
  599. httpd_location *l = httpd_locations;
  600. while ( l->next ) {
  601. l = l->next;
  602. }
  603. loc->next = NULL;
  604. l->next = loc;
  605. res = SUCCESS;
  606. }
  607. pthread_mutex_unlock( &httpd_location_mutex );
  608. }
  609. }
  610. return res;
  611. }
  612. int
  613. Httpd_ServerStart( Httpd_ServerContext *context )
  614. {
  615. if ( context ) {
  616. sprintf( httpd_server.server_name, ( context->server_name[ 0 ] )? context->server_name: "SigmaCam Web Server" );
  617. sprintf( httpd_server.root, ( context->root[ 0 ] )? context->root: "/var/www/" );
  618. sprintf( httpd_server.homepage, ( context->homepage[ 0 ] )? context->homepage: "/var/www/index.html" );
  619. if ( httpd_server.root[ strlen( httpd_server.root ) - 1 ] == '/' ) {
  620. httpd_server.root[ strlen( httpd_server.root ) - 1 ] = 0;
  621. }
  622. httpd_server.http_port = ( context->http_port )? context->http_port: 80;
  623. httpd_server.https_port = ( context->https_port )? context->https_port: 443;
  624. httpd_server.http_fd = Socket_CreateServer( httpd_server.http_port );
  625. if ( httpd_server.http_fd < 0 ) {
  626. dbg_line( "Do Socket_CreateServer Failed!!!" );
  627. return FAILURE;
  628. }
  629. httpd_server.p_id = create_norm_thread( httpd_accept, NULL, 0 );
  630. if ( httpd_server.p_id < 0 ) {
  631. dbg_line( "Do create_norm_thread Failed!!!" );
  632. Socket_Disconnect( httpd_server.http_fd );
  633. return FAILURE;
  634. }
  635. httpd_server.ready = TRUE;
  636. dbg_warm( "Httpd Start" );
  637. return SUCCESS;
  638. } else {
  639. return FAILURE;
  640. }
  641. }