/************************************************************************ * NAME: fapp_http_string_buffer_respond * * DESCRIPTION: *************************************************************************/ static unsigned long fapp_http_string_buffer_respond(char * buffer, unsigned long buffer_size, char * eof, long *cookie) { unsigned long result = 0; char *string_buffer_ptr = (char *) *cookie; unsigned long send_size = fnet_strlen(string_buffer_ptr); *eof = 1; /* No aditional send by default. */ if(buffer && buffer_size) { if(send_size>buffer_size) send_size = buffer_size; fnet_memcpy(buffer, string_buffer_ptr, send_size); string_buffer_ptr += send_size; if(*string_buffer_ptr!='\0') /* If any data for sending.*/ *eof = 0; /* Need more itteration. */ result = send_size; *cookie = (long)string_buffer_ptr; /* Save cgi_buffer_ptr as cookie.*/ } return result; }
/************************************************************************ * NAME: fnet_dns_init * * DESCRIPTION: Initializes DNS client service and starts the host * name reolving. ************************************************************************/ static unsigned int fnet_dns_add_question( char *message, unsigned short type, char *host_name) { unsigned int total_length = 0U; unsigned int label_length; fnet_dns_q_tail_t *q_tail; char *strtok_pos = FNET_NULL; /* Set Question section : 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / QNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ /* QNAME */ /* a domain name represented as a sequence of labels, where * each label consists of a length octet followed by that * number of octets. The domain name terminates with the * zero length octet for the null label of the root. Note * that this field may be an odd number of octets; no * padding is used. */ /* Copy host_name string.*/ fnet_strcpy(&message[1], host_name); /* TBD PFI, use strtok_pos as pointer.*/ /* Replace '.' by zero.*/ fnet_strtok_r(&message[1], ".", &strtok_pos); while((label_length = fnet_strlen(&message[total_length]+1U)) > 0U) { message[total_length] = (char)label_length; /* Set length before (previous) label.*/ total_length += label_length + 1U; fnet_strtok_r(FNET_NULL,".", &strtok_pos); } q_tail = (fnet_dns_q_tail_t *)&message[total_length]; /* Skip 1 byte (zero). End of string. */ /* QTYPE */ q_tail->qtype = type; /* QCLASS */ q_tail->qclass = FNET_HTONS(FNET_DNS_HEADER_CLASS_IN); return (total_length+ sizeof(fnet_dns_q_tail_t)); }
/************************************************************************ * NAME: fapp_fs_view_cmd * * DESCRIPTION: *************************************************************************/ static void fapp_fs_view_cmd( fnet_shell_desc_t desc, fnet_index_t argc, fnet_char_t ** argv ) { FNET_FS_FILE file; fnet_char_t *path = argv[1]; fnet_char_t *path_end; fnet_size_t size_cd = fnet_strlen (fapp_fs_current_path); fnet_size_t size_path; fnet_char_t splitter[] = {FNET_FS_SPLITTER,'\0'}; fnet_uint8_t data; struct fnet_fs_dirent dirent; FNET_COMP_UNUSED_ARG(desc); FNET_COMP_UNUSED_ARG(argc); if (*path != FNET_FS_SPLITTER) /* Realative path.*/ { /* Add splitter if not yet.*/ if(fapp_fs_current_path[size_cd-1U] != FNET_FS_SPLITTER) { fnet_strncat( &fapp_fs_current_path[0], splitter, FAPP_FS_DIR_PATH_MAX); } fnet_strncat( &fapp_fs_current_path[0], path, FAPP_FS_DIR_PATH_MAX); path = fapp_fs_current_path; } else /* Full path. */ { /* Strip possible repetitive leading slashes. */ while ((path[0] == FNET_FS_SPLITTER) && (path[1] == FNET_FS_SPLITTER)) { path++; } } /* Strip possible ending slashes. */ if((size_path = fnet_strlen(path)) > 0U) { path_end = &path[size_path-1U]; while(*path_end == FNET_FS_SPLITTER) { *path_end = '\0'; path_end--; } } /* Open file. */ file = fnet_fs_fopen(path,"r"); if (file) { /* Print file info.*/ fnet_fs_finfo (file, &dirent); fnet_shell_println(desc, FAPP_FS_DIR_STR, "Content of:", dirent.d_size, dirent.d_name); while(fnet_fs_fread(&data, sizeof(data), file)) { fnet_shell_putchar(desc, data); } /* Close file. */ fnet_fs_fclose(file); } else { fnet_shell_println(desc, FAPP_FS_VIEW_ERR, argv[1]); } /* Restore cur path. */ fapp_fs_current_path[size_cd] = '\0'; }
/************************************************************************ * NAME: fapp_fs_cd_cmd * * DESCRIPTION: Change the current directory. *************************************************************************/ static void fapp_fs_cd_cmd( fnet_shell_desc_t desc, fnet_index_t argc, fnet_char_t ** argv ) { FNET_FS_DIR dir; fnet_char_t *path = argv[1]; fnet_char_t *path_end; fnet_size_t size_cd = fnet_strlen (fapp_fs_current_path); fnet_size_t size_path; fnet_char_t splitter[] = {FNET_FS_SPLITTER,'\0'}; FNET_COMP_UNUSED_ARG(argc); if (*path != FNET_FS_SPLITTER) /* Realative path.*/ { /* Add splitter if not yet.*/ if(fapp_fs_current_path[size_cd-1U] != FNET_FS_SPLITTER) { fnet_strncat( &fapp_fs_current_path[0], splitter, FAPP_FS_DIR_PATH_MAX); } fnet_strncat( &fapp_fs_current_path[0], path, FAPP_FS_DIR_PATH_MAX); path = fapp_fs_current_path; } else /* Full path. */ { /* Strip possible repetitive leading slashes. */ while ((path[0] == FNET_FS_SPLITTER) && (path[1] == FNET_FS_SPLITTER)) { path++; } } /* Strip possible ending slashes. */ if((size_path = fnet_strlen(path)) > 0U) { path_end = &path[size_path - 1U]; while(*path_end == FNET_FS_SPLITTER) { *path_end = '\0'; path_end--; } } /* Open dir. */ dir = fnet_fs_opendir(path); if (dir) { /* Update cur path. */ fnet_strncpy( &fapp_fs_current_path[0], path, FAPP_FS_DIR_PATH_MAX); if(fapp_fs_current_path[0] == '\0') /* root dir */ { fnet_strncat( &fapp_fs_current_path[0], splitter, FAPP_FS_DIR_PATH_MAX); } /* Change shell prompt. */ fnet_sprintf( FAPP_FS_PROMPT_STR, "%s%s%s", &FAPP_FS_PROMPT_STR_HEADER[0], &fapp_fs_current_path[0], &FAPP_FS_PROMPT_STR_TRAILER[0]); /* Close dir. */ fnet_fs_closedir(dir); } else { /* Restore cur path. */ fapp_fs_current_path[size_cd] = '\0'; fnet_shell_println(desc, FAPP_FS_CD_ERR, argv[1]); } }
/************************************************************************ * NAME: fnet_dns_init * * DESCRIPTION: Initializes DNS client service and starts the host * name resolving. ************************************************************************/ int fnet_dns_init( struct fnet_dns_params *params ) { const unsigned long bufsize_option = FNET_DNS_MESSAGE_SIZE; unsigned int total_length; unsigned long host_name_length; struct sockaddr remote_addr; fnet_dns_header_t *header; /* Check input parameters. */ if((params == 0) || (params->dns_server_addr.sa_family == AF_UNSPEC) || fnet_socket_addr_is_unspecified(¶ms->dns_server_addr) || (params->handler == 0) /* Check length of host_name.*/ || ((host_name_length = fnet_strlen(params->host_name)) == 0U) || (host_name_length >= FNET_DNS_MAME_SIZE)) { FNET_DEBUG_DNS(FNET_DNS_ERR_PARAMS); goto ERROR; } /* Check if DNS service is free.*/ if(fnet_dns_if.state != FNET_DNS_STATE_DISABLED) { FNET_DEBUG_DNS(FNET_DNS_ERR_IS_INITIALIZED); goto ERROR; } /* Save input parmeters.*/ fnet_dns_if.handler = params->handler; fnet_dns_if.handler_cookie = params->cookie; fnet_dns_if.addr_family = params->addr_family; fnet_dns_if.addr_number = 0; if(params->addr_family == AF_INET) { fnet_dns_if.dns_type = FNET_HTONS(FNET_DNS_TYPE_A); } else if(params->addr_family == AF_INET6) { fnet_dns_if.dns_type = FNET_HTONS(FNET_DNS_TYPE_AAAA); } else { FNET_DEBUG_DNS(FNET_DNS_ERR_PARAMS); goto ERROR; } fnet_dns_if.iteration = 0U; /* Reset iteration counter.*/ fnet_dns_if.id++; /* Change query ID.*/ /* Create socket */ if((fnet_dns_if.socket_cln = socket(params->dns_server_addr.sa_family, SOCK_DGRAM, 0)) == SOCKET_INVALID) { FNET_DEBUG_DNS(FNET_DNS_ERR_SOCKET_CREATION); goto ERROR; } /* Set socket options */ setsockopt(fnet_dns_if.socket_cln, SOL_SOCKET, SO_RCVBUF, (const char *)&bufsize_option, sizeof(bufsize_option)); setsockopt(fnet_dns_if.socket_cln, SOL_SOCKET, SO_SNDBUF, (const char *)&bufsize_option, sizeof(bufsize_option)); /* Bind/connect to the server.*/ FNET_DEBUG_DNS("Connecting to DNS Server."); fnet_memset_zero(&remote_addr, sizeof(remote_addr)); remote_addr = params->dns_server_addr; if(remote_addr.sa_port == 0U) { remote_addr.sa_port = FNET_CFG_DNS_PORT; } if(connect(fnet_dns_if.socket_cln, &remote_addr, sizeof(remote_addr))== FNET_ERR) { FNET_DEBUG_DNS(FNET_DNS_ERR_SOCKET_CONNECT); goto ERROR_1; } /* ==== Build message. ==== */ fnet_memset_zero(fnet_dns_if.message, sizeof(fnet_dns_if.message)); /* Clear buffer.*/ /* Set header fields: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ header = (fnet_dns_header_t *)fnet_dns_if.message; header->id = fnet_dns_if.id; /* Set ID. */ header->flags = FNET_HTONS(FNET_DNS_HEADER_FLAGS_RD); /* Recursion Desired.*/ header->qdcount = FNET_HTONS(1U); /* One Question. */ /* No Answer (ANCOUNT).*/ /* No Authority (NSCOUNT). */ /* No Additional (ARCOUNT). */ total_length = sizeof(fnet_dns_header_t); total_length += fnet_dns_add_question( &fnet_dns_if.message[total_length], fnet_dns_if.dns_type, params->host_name); fnet_dns_if.message_size = (unsigned long)(total_length); /* Register DNS service. */ fnet_dns_if.service_descriptor = fnet_poll_service_register(fnet_dns_state_machine, (void *) &fnet_dns_if); if(fnet_dns_if.service_descriptor == (fnet_poll_desc_t)FNET_ERR) { FNET_DEBUG_DNS(FNET_DNS_ERR_SERVICE); goto ERROR_1; } fnet_dns_if.state = FNET_DNS_STATE_TX; /* => Send request. */ return FNET_OK; ERROR_1: closesocket(fnet_dns_if.socket_cln); ERROR: return FNET_ERR; }
/************************************************************************ * NAME: fnet_http_state_machine * * DESCRIPTION: Http server state machine. ************************************************************************/ static void fnet_http_state_machine( void *http_if_p ) { struct sockaddr foreign_addr; int len; int res; struct fnet_http_if *http = (struct fnet_http_if *)http_if_p; int iteration; char *ch; int i; struct fnet_http_session_if *session; for(i=0; i<FNET_CFG_HTTP_SESSION_MAX; i++) { session = &http->session[i]; http->session_active = session; for(iteration = 0; iteration < FNET_HTTP_ITERATION_NUMBER; iteration++) { switch(session->state) { /*---- LISTENING ------------------------------------------------*/ case FNET_HTTP_STATE_LISTENING: len = sizeof(foreign_addr); if((session->socket_foreign = accept(http->socket_listen, &foreign_addr, &len)) != SOCKET_INVALID) { #if FNET_CFG_DEBUG_HTTP { char ip_str[FNET_IP_ADDR_STR_SIZE]; fnet_inet_ntop(foreign_addr.sa_family, (char*)(foreign_addr.sa_data), ip_str, sizeof(ip_str)); FNET_DEBUG_HTTP(""); FNET_DEBUG_HTTP("HTTP: RX Request From: %s; Port: %d.", ip_str, fnet_ntohs(foreign_addr.sa_port)); } #endif /* Reset response & request parameters.*/ fnet_memset_zero(&session->response, sizeof(struct fnet_http_response)); fnet_memset_zero(&session->request, sizeof(struct fnet_http_request)); #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ session->response.content_length = -1; /* No content length by default.*/ /* Default HTTP version response.*/ session->response.version.major = FNET_HTTP_VERSION_MAJOR; session->response.version.minor = FNET_HTTP_VERSION_MINOR; session->response.tx_data = fnet_http_tx_status_line; #endif session->state_time = fnet_timer_ticks(); /* Reset timeout. */ session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_RX_REQUEST; /* => WAITING HTTP REQUEST */ } break; /*---- RX_LINE -----------------------------------------------*/ case FNET_HTTP_STATE_RX_REQUEST: do { /* Read character by character.*/ ch = &session->buffer[session->buffer_actual_size]; if((res = recv(session->socket_foreign, ch, 1, 0) )!= SOCKET_ERROR) { if(res > 0) /* Received a data.*/ { session->state_time = fnet_timer_ticks(); /* Reset timeout.*/ session->buffer_actual_size++; if(*ch == '\r') *ch = '\0'; else if(*ch == '\n') /* Line received.*/ { char * req_buf = &session->buffer[0]; *ch = '\0'; if(session->request.method == 0) /* Parse Request line.*/ { const struct fnet_http_method **method = &fnet_http_method_list[0]; FNET_DEBUG_HTTP("HTTP: RX Request: %s", req_buf); /* Determine the method type. */ while(*method) { if ( !fnet_strcmp_splitter(req_buf, (*method)->token, ' ') ) { req_buf+=fnet_strlen((*method)->token); session->request.method = *method; break; } method++; } /* Check if the method is supported? */ if(session->request.method && session->request.method->handle) { /* Parse URI.*/ req_buf = fnet_http_uri_parse(req_buf, &session->request.uri); FNET_DEBUG_HTTP("HTTP: URI Path = %s; Query = %s", http->request.uri.path, http->request.uri.query); #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ /* Parse HTTP/x.x version.*/ fnet_http_version_parse(++req_buf, &session->response.version); /* Check the highest supported HTTP version.*/ if(((session->response.version.major<<8)|session->response.version.minor) > ((FNET_HTTP_VERSION_MAJOR<<8)|FNET_HTTP_VERSION_MINOR)) { session->response.version.major = FNET_HTTP_VERSION_MAJOR; session->response.version.minor = FNET_HTTP_VERSION_MINOR; } if(session->response.version.major == 0) /* HTTP/0.x */ { session->state = FNET_HTTP_STATE_CLOSING; /* Client does not support HTTP/1.x*/ break; } #if FNET_CFG_HTTP_AUTHENTICATION_BASIC /* Check Authentification.*/ fnet_http_auth_validate_uri(http); #endif #endif/*FNET_CFG_HTTP_VERSION_MAJOR*/ /* Call method initial handler.*/ res = session->request.method->handle(http, &session->request.uri); #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ if(fnet_http_status_ok(res) == FNET_OK) #else if((res == FNET_OK)) #endif { #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ session->buffer_actual_size = 0; /* => Parse Header line.*/ #else /* HTTP/0.9 */ session->response.tx_data = session->request.method->send; /* Reset buffer pointers.*/ session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_TX; /* Send data.*/ #endif } /* Method error.*/ else /* Error.*/ { #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ /* Default code = FNET_HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR. */ if(res != FNET_ERR) session->response.status.code = (fnet_http_status_code_t)res; /* Send status line.*/ session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_TX; /* Send error.*/ #else /* HTTP/0.9 */ session->state = FNET_HTTP_STATE_CLOSING; #endif } } /* Method is not supported.*/ else /* Error.*/ { #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ session->response.status.code = FNET_HTTP_STATUS_CODE_NOT_IMPLEMENTED; /* Send status line.*/ session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_TX; /* Send error.*/ #else /* HTTP/0.9 */ session->state = FNET_HTTP_STATE_CLOSING; #endif } } #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ /* Parse Header line.*/ else { if(session->request.skip_line == 0) { if(*req_buf == 0) /* === Empty line => End of the request header. ===*/ { #if FNET_CFG_HTTP_AUTHENTICATION_BASIC if(session->response.auth_entry) /* Send UNAUTHORIZED error.*/ session->response.status.code = FNET_HTTP_STATUS_CODE_UNAUTHORIZED; else /* Send Data.*/ #endif session->response.status.code = FNET_HTTP_STATUS_CODE_OK; #if FNET_CFG_HTTP_POST if(session->request.content_length > 0) /* RX Entity-Body.*/ { session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_RX; } else #endif /* TX Full-Responce.*/ { /* Send status line.*/ session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_TX; } break; } else /* === Parse header fields. ===*/ { FNET_DEBUG_HTTP("HTTP: RX Header: %s", req_buf); #if FNET_CFG_HTTP_AUTHENTICATION_BASIC /* --- Authorization: ---*/ if (session->response.auth_entry && fnet_strncmp(req_buf, FNET_HTTP_HEADER_FIELD_AUTHORIZATION, sizeof(FNET_HTTP_HEADER_FIELD_AUTHORIZATION)-1) == 0) /* Authetication is required.*/ { char *auth_str = &req_buf[sizeof(FNET_HTTP_HEADER_FIELD_AUTHORIZATION)-1]; /* Validate credentials.*/ if(fnet_http_auth_validate_credentials(http, auth_str) == FNET_OK) session->response.auth_entry = 0; /* Authorization is succesful.*/ } #endif #if FNET_CFG_HTTP_POST /* --- Content-Length: ---*/ if (session->request.method->receive && fnet_strncmp(req_buf, FNET_HTTP_HEADER_FIELD_CONTENT_LENGTH, sizeof(FNET_HTTP_HEADER_FIELD_CONTENT_LENGTH)-1) == 0) { char *p; char *length_str = &req_buf[sizeof(FNET_HTTP_HEADER_FIELD_CONTENT_LENGTH)-1]; session->request.content_length = (long)fnet_strtoul(length_str,&p,10); } #endif } } /* Line is skiped.*/ else session->request.skip_line = 0; /* Reset the Skip flag.*/ session->buffer_actual_size = 0; /* => Parse Next Header line.*/ } #endif/* FNET_CFG_HTTP_VERSION_MAJOR */ } /* Not whole line received yet.*/ else if (session->buffer_actual_size == FNET_HTTP_BUF_SIZE) /* Buffer is full.*/ { #if FNET_CFG_HTTP_VERSION_MAJOR /* HTTP/1.x*/ if(session->request.method != 0) /* For header, skip the line.*/ { /* Skip line.*/ session->request.skip_line = 1; session->buffer_actual_size = 0; } else /* Error.*/ { /* Default code = FNET_HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR. */ session->buffer_actual_size = 0; session->state = FNET_HTTP_STATE_TX; /* Send error.*/ } #else /* HTTP/0.9 */ session->state = FNET_HTTP_STATE_CLOSING; #endif } } /* No data.*/ else if(fnet_timer_get_interval(session->state_time, fnet_timer_ticks()) /* Time out? */ > (FNET_HTTP_WAIT_RX_MS / FNET_TIMER_PERIOD_MS)) { session->state = FNET_HTTP_STATE_CLOSING; /*=> CLOSING */ } /* else => WAITING REQUEST. */ } /* recv() error.*/ else { session->state = FNET_HTTP_STATE_CLOSING; /*=> CLOSING */ } } while ((res > 0) && (session->state == FNET_HTTP_STATE_RX_REQUEST)); /* Till receiving the request header.*/ break; #if FNET_CFG_HTTP_POST /*---- RX --------------------------------------------------*/ case FNET_HTTP_STATE_RX: /* Receive data (Entity-Body). */ if((res = recv(session->socket_foreign, &session->buffer[session->buffer_actual_size], (int)(FNET_HTTP_BUF_SIZE-session->buffer_actual_size), 0) )!= SOCKET_ERROR) { session->buffer_actual_size += res; session->request.content_length -= res; if(res > 0) /* Some Data.*/ { session->state_time = fnet_timer_ticks(); /* Reset timeout.*/ res = session->request.method->receive(http); if(fnet_http_status_ok(res) != FNET_OK) { if(res != FNET_ERR) session->response.status.code = (fnet_http_status_code_t)res; else session->response.status.code = FNET_HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR; session->request.content_length = 0; } if(session->request.content_length <= 0) /* The last data.*/ { session->state = FNET_HTTP_STATE_TX; /* Send data.*/ } session->buffer_actual_size = 0; } else /* No Data.*/ { if(fnet_timer_get_interval(session->state_time, fnet_timer_ticks()) > (FNET_HTTP_WAIT_RX_MS / FNET_TIMER_PERIOD_MS)) /* Time out.*/ { session->state = FNET_HTTP_STATE_CLOSING; /*=> CLOSING */ } } } else /* Socket error.*/ { session->state = FNET_HTTP_STATE_CLOSING; /*=> CLOSING */ } break; #endif /* FNET_CFG_HTTP_POST.*/ /*---- TX --------------------------------------------------*/ case FNET_HTTP_STATE_TX: /* Send data. */ if(fnet_timer_get_interval(session->state_time, fnet_timer_ticks()) < (FNET_HTTP_WAIT_TX_MS / FNET_TIMER_PERIOD_MS)) /* Check timeout */ { int send_size; if(session->buffer_actual_size == session->response.buffer_sent) { /* Reset counters.*/ session->buffer_actual_size =0; session->response.buffer_sent = 0; if(session->response.send_eof || session->response.tx_data(http) == FNET_ERR) /* get data for sending */ { session->state = FNET_HTTP_STATE_CLOSING; /*=> CLOSING */ break; } } send_size = (int)(session->buffer_actual_size - (int)session->response.buffer_sent); if(send_size > http->send_max) send_size = (int)http->send_max; if((res = send(session->socket_foreign, session->buffer + session->response.buffer_sent, send_size, 0)) != SOCKET_ERROR) { if(res) { FNET_DEBUG_HTTP("HTTP: TX %d bytes.", res); session->state_time = fnet_timer_ticks(); /* reset timeout */ session->response.buffer_sent += res; } break; /* => SENDING */ } } session->state = FNET_HTTP_STATE_CLOSING; /*=> CLOSING */ break; /*---- CLOSING --------------------------------------------------*/ case FNET_HTTP_STATE_CLOSING: if(session->request.method && session->request.method->close) session->request.method->close(http); closesocket(session->socket_foreign); session->socket_foreign = SOCKET_INVALID; session->state = FNET_HTTP_STATE_LISTENING; /*=> LISTENING */ break; default: break; } } } /*for(sessions)*/ }