/************************************************************************ * NAME: net_if_find * * DESCRIPTION: Returns a network interface given its name. *************************************************************************/ fnet_netif_desc_t fnet_netif_get_by_name( char *name ) { fnet_netif_t *netif; fnet_netif_desc_t result = (fnet_netif_desc_t)FNET_NULL; fnet_os_mutex_lock(); if(name) for (netif = fnet_netif_list; netif != 0; netif = netif->next) { if(fnet_strncmp(name, netif->name, FNET_NETIF_NAMELEN) == 0) { result = (fnet_netif_desc_t)netif; break; } } fnet_os_mutex_unlock(); return result; }
/************************************************************************ * 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)*/ }