/************************************************************************ * NAME: fnet_timer_delay * * DESCRIPTION: Do delay for a given number of timer ticks. * *************************************************************************/ void fnet_timer_delay( unsigned long delay_ticks ) { unsigned long start = fnet_current_time; while(fnet_timer_get_interval(start, fnet_timer_ticks()) < delay_ticks) { }; }
/************************************************************************ * NAME: fnet_timer_delay * * DESCRIPTION: Do delay for a given number of timer ticks. * *************************************************************************/ void fnet_timer_delay( fnet_time_t delay_ticks ) { fnet_time_t start_ticks = fnet_current_time; while(fnet_timer_get_interval(start_ticks, fnet_timer_ticks()) < delay_ticks) {} }
/************************************************************************ * NAME: fnet_nd6_dad_timer * RETURS: None. * DESCRIPTION: Timer routine used to detect increase of PMTU *************************************************************************/ static void fnet_netif_pmtu_timer( void *cookie ) { fnet_netif_t *netif = (fnet_netif_t *)cookie; if( fnet_timer_get_interval(netif->pmtu_timestamp, fnet_timer_ms()) > FNET_NETIF_PMTU_TIMEOUT) { fnet_netif_set_pmtu(netif, netif->mtu); } }
/************************************************************************ * NAME: fnet_timer_handler_bottom * * DESCRIPTION: Handles timer interrupts * *************************************************************************/ void fnet_timer_handler_bottom(void *cookie) { struct fnet_net_timer *timer = fnet_tl_head; FNET_COMP_UNUSED_ARG(cookie); while(timer) { if(fnet_timer_get_interval(timer->timer_cnt, fnet_current_time) >= timer->timer_rv) { timer->timer_cnt = fnet_current_time; if(timer->handler) timer->handler(timer->cookie); } timer = timer->next; } }
/************************************************************************ * DESCRIPTION: ************************************************************************/ static void fnet_telnet_send(struct fnet_telnet_session_if *session) { fnet_int32_t res; fnet_index_t tx_buffer_tail_index = 0u; fnet_time_t timeout = fnet_timer_get_ticks(); /* Send all data in the buffer.*/ while((tx_buffer_tail_index != session->tx_buffer_head_index) && (session->state != FNET_TELNET_STATE_CLOSING)) { if((res = fnet_socket_send(session->socket_foreign, &session->tx_buffer[tx_buffer_tail_index], (fnet_size_t)session->tx_buffer_head_index - tx_buffer_tail_index, 0u)) != FNET_ERR) { if(res) /* >0 */ { /* Update buffer pointers. */ tx_buffer_tail_index += (fnet_index_t)res; /* Reset timeout. */ timeout = fnet_timer_get_ticks(); } else if( fnet_timer_get_interval(timeout, fnet_timer_get_ticks()) > (FNET_TELNET_WAIT_SEND_MS / FNET_TIMER_PERIOD_MS) ) /* Check timeout */ { FNET_DEBUG_TELNET("TELNET:Send timeout."); break; /* Time-out. */ } else {} } else /* Error.*/ { FNET_DEBUG_TELNET("TELNET:Send error."); session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ } } /* Reset TX buffer index. */ session->tx_buffer_head_index = 0u; }
/************************************************************************ * NAME: fapp_bench_print_results * * DESCRIPTION: Print Benchmark results. ************************************************************************/ static void fapp_bench_print_results (fnet_shell_desc_t desc) { /* Print benchmark results.*/ unsigned long interval = fnet_timer_get_interval(fapp_bench.first_time, fapp_bench.last_time); fnet_shell_println(desc, "Results:"); if(fapp_bench.remote_bytes == 0) { fnet_shell_println(desc, "\t%d bytes in %d.%d seconds = %d Kbits/sec\n", fapp_bench.bytes, ((interval*FNET_TIMER_PERIOD_MS)/1000), ((interval*FNET_TIMER_PERIOD_MS)%1000)/100, (interval == 0) ? -1 : (int)((fapp_bench.bytes*8/**(1000*//FNET_TIMER_PERIOD_MS/*)*/)/interval)/*/1000*/); } else /* UDP TX only */ { fnet_shell_println(desc, "\t%d [%d] bytes in %d.%d seconds = %d [%d] Kbits/sec\n", fapp_bench.bytes, fapp_bench.remote_bytes, ((interval*FNET_TIMER_PERIOD_MS)/1000), ((interval*FNET_TIMER_PERIOD_MS)%1000)/100, (interval == 0) ? -1 : (int)((fapp_bench.bytes*8/**(1000*//FNET_TIMER_PERIOD_MS/*)*/)/interval)/*/1000*/, (interval == 0) ? -1 : (int)((fapp_bench.remote_bytes*8/**(1000*//FNET_TIMER_PERIOD_MS/*)*/)/interval)/*/1000*/); } }
/************************************************************************ * NAME: fnet_telnet_send * * DESCRIPTION: ************************************************************************/ static void fnet_telnet_send(struct fnet_telnet_session_if *session) { int res; int tx_buffer_tail_index = 0; unsigned long timeout = fnet_timer_ticks(); /* Send all data in the buffer.*/ while(tx_buffer_tail_index != session->tx_buffer_head_index) { if((res = send(session->socket_foreign, &session->tx_buffer[tx_buffer_tail_index], session->tx_buffer_head_index - tx_buffer_tail_index, 0)) != SOCKET_ERROR) { if(res) /* >0 */ { /* Update buffer pointers. */ tx_buffer_tail_index += res; /* Reset timeout. */ timeout = fnet_timer_ticks(); } else if( fnet_timer_get_interval(timeout, fnet_timer_ticks()) > (FNET_TELNET_WAIT_SEND_MS / FNET_TIMER_PERIOD_MS) ) /* Check timeout */ { FNET_DEBUG_TELNET("TELNET:Send timeout."); break; /* Time-out. */ } } else /* Error.*/ { FNET_DEBUG_TELNET("TELNET:Send error."); session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ break; } } /* Reset TX buffer index. */ session->tx_buffer_head_index = 0; }
/************************************************************************ * NAME: fapp_bench_udp_rx * * DESCRIPTION: Start Benchmark UDP server. ************************************************************************/ static void fapp_bench_udp_rx (fnet_shell_desc_t desc, fnet_address_family_t family, struct sockaddr *multicast_address /* optional, set to 0*/) { struct sockaddr local_addr; const unsigned long bufsize_option = FAPP_BENCH_SOCKET_BUF_SIZE; int received; char ip_str[FNET_IP_ADDR_STR_SIZE]; struct sockaddr addr; unsigned int addr_len; int is_first = 1; int exit_flag = 0; /* Create listen socket */ if((fapp_bench.socket_listen = socket(family, SOCK_DGRAM, 0)) == SOCKET_INVALID) { FNET_DEBUG("BENCH: Socket creation error.\n"); goto ERROR_1; } /*Bind.*/ fnet_memset_zero(&local_addr, sizeof(local_addr)); local_addr.sa_port = FAPP_BENCH_PORT; local_addr.sa_family = family; if(bind(fapp_bench.socket_listen, &local_addr, sizeof(local_addr)) == SOCKET_ERROR) { FNET_DEBUG("BENCH: Socket bind error.\n"); goto ERROR_2; } /* Set socket options. */ if( /* Set socket buffer size. */ (setsockopt(fapp_bench.socket_listen, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize_option, sizeof(bufsize_option))== SOCKET_ERROR) || (setsockopt(fapp_bench.socket_listen, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize_option, sizeof(bufsize_option))== SOCKET_ERROR) ) { FNET_DEBUG("BENCH: Socket setsockopt error.\n"); goto ERROR_2; } /* Join multicast group, if set. */ if(multicast_address) { #if FNET_CFG_IP4 if(multicast_address->sa_family == AF_INET) { struct ip_mreq mreq; /* Multicast group information.*/ mreq.imr_multiaddr.s_addr = ((struct sockaddr_in*)multicast_address)->sin_addr.s_addr; mreq.imr_interface.s_addr = FNET_HTONL(INADDR_ANY); /* Default Interface.*/ /* Join multicast group. */ if(setsockopt(fapp_bench.socket_listen, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == SOCKET_ERROR) { FNET_DEBUG("BENCH: Joining to multicast group is failed.\n"); goto ERROR_2; } } #endif #if FNET_CFG_IP6 if(multicast_address->sa_family == AF_INET6) { struct ipv6_mreq mreq6; /* Multicast group information.*/ FNET_IP6_ADDR_COPY(&((struct sockaddr_in6*)multicast_address)->sin6_addr.s6_addr, &mreq6.ipv6imr_multiaddr.s6_addr); mreq6.ipv6imr_interface = ((struct sockaddr_in6*)multicast_address)->sin6_scope_id; /* Join multicast group. */ if(setsockopt(fapp_bench.socket_listen, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) == SOCKET_ERROR) { FNET_DEBUG("BENCH: Joining to multicast group is failed.\n"); goto ERROR_2; } } #endif } /* ------ Start test.----------- */ fnet_shell_println(desc, FAPP_DELIMITER_STR); fnet_shell_println(desc, " UDP RX Test" ); fnet_shell_println(desc, FAPP_DELIMITER_STR); fapp_netif_addr_print(desc, family, fapp_default_netif, FNET_FALSE); if(multicast_address) { fnet_shell_println(desc, FAPP_SHELL_INFO_FORMAT_S, "Multicast Group", fnet_inet_ntop(multicast_address->sa_family, (char*)(multicast_address->sa_data), ip_str, sizeof(ip_str)) ); } fnet_shell_println(desc, FAPP_SHELL_INFO_FORMAT_D, "Local Port", FNET_NTOHS(FAPP_BENCH_PORT)); fnet_shell_println(desc, FAPP_TOCANCEL_STR); fnet_shell_println(desc, FAPP_DELIMITER_STR); while(exit_flag == 0) /* Main loop */ { fnet_shell_println(desc, "Waiting."); fapp_bench.bytes = 0; fapp_bench.remote_bytes = 0; addr_len = sizeof(addr); is_first = 1; while(exit_flag == 0) /* Test loop. */ { /* Receive data */ received = recvfrom (fapp_bench.socket_listen, (char*)(&fapp_bench.buffer[0]), FAPP_BENCH_BUFFER_SIZE, 0, &addr, &addr_len ); if(received >= FAPP_BENCH_UDP_END_BUFFER_LENGTH) { /* Reset timeout. */ fapp_bench.last_time = fnet_timer_ticks(); if(is_first) { if( received > FAPP_BENCH_UDP_END_BUFFER_LENGTH ) { fnet_shell_println(desc,"Receiving from %s:%d", fnet_inet_ntop(addr.sa_family, (char*)(addr.sa_data), ip_str, sizeof(ip_str)), fnet_ntohs(addr.sa_port)); fapp_bench.first_time = fnet_timer_ticks(); is_first = 0; } } else { if(received == FAPP_BENCH_UDP_END_BUFFER_LENGTH ) /* End of transfer. */ { /* Send ACK containing amount of received data.*/ unsigned long ack_bytes = fnet_htonl(fapp_bench.bytes); /* Send several times, just to be sure that it is received/not lost.*/ sendto(fapp_bench.socket_listen, (char*)(&ack_bytes), sizeof(ack_bytes), 0, (struct sockaddr*)&addr, sizeof(addr)); sendto(fapp_bench.socket_listen, (char*)(&ack_bytes), sizeof(ack_bytes), 0, (struct sockaddr*)&addr, sizeof(addr)); sendto(fapp_bench.socket_listen, (char*)(&ack_bytes), sizeof(ack_bytes), 0, (struct sockaddr*)&addr, sizeof(addr)); /* Print benchmark results.*/ fapp_bench_print_results (desc); break; } else fapp_bench.bytes += received; } } else { /* Check error. Check timeout */ if(received == SOCKET_ERROR) { fnet_shell_println(desc, "BENCH: Error (%d).", fnet_error_get()); break; } /* Check timeout. */ if((is_first == 0) && (fnet_timer_get_interval(fapp_bench.last_time, fnet_timer_ticks()) > (FAPP_UDP_TIMEOUT_MS/FNET_TIMER_PERIOD_MS))) { fnet_shell_println(desc, "BENCH: Exit on timeout."); fapp_bench_print_results (desc); break; } } exit_flag = fnet_shell_ctrlc (desc); } } ERROR_2: closesocket(fapp_bench.socket_listen); ERROR_1: fnet_shell_println(desc, FAPP_BENCH_COMPLETED_STR); }
/************************************************************************ * NAME: fnet_dns_state_machine * * DESCRIPTION: DNS-client state machine. ************************************************************************/ static void fnet_dns_state_machine( void *fnet_dns_if_p ) { int sent_size; int received; unsigned int i; fnet_dns_header_t *header; fnet_dns_rr_header_t *rr_header; fnet_dns_if_t *dns_if = (fnet_dns_if_t *)fnet_dns_if_p; switch(dns_if->state) { /*---- TX --------------------------------------------*/ case FNET_DNS_STATE_TX: FNET_DEBUG_DNS("Sending query..."); sent_size = send(dns_if->socket_cln, dns_if->message, dns_if->message_size, 0U); if (sent_size != (int)dns_if->message_size) { dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */ } else { dns_if->last_time = fnet_timer_ticks(); dns_if->state = FNET_DNS_STATE_RX; } break; /*---- RX -----------------------------------------------*/ case FNET_DNS_STATE_RX: /* Receive data */ received = recv(dns_if->socket_cln, dns_if->message, sizeof(dns_if->message), 0U); if(received > 0 ) { header = (fnet_dns_header_t *)fnet_dns_if.message; if((header->id == dns_if->id) && /* Check the ID.*/ ((header->flags & FNET_DNS_HEADER_FLAGS_QR)==FNET_DNS_HEADER_FLAGS_QR)) /* Is response.*/ { for (i=(sizeof(fnet_dns_header_t)-1U); i < (unsigned int)received; i++) { /* [RFC1035 4.1.4.] In order to reduce the size of messages, the domain system utilizes a * compression scheme which eliminates the repetition of domain names in a * message. In this scheme, an entire domain name or a list of labels at * the end of a domain name is replaced with a pointer to a prior occurance * of the same name. * The pointer takes the form of a two octet sequence: * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | 1 1| OFFSET | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ /* => Check for 0xC0. */ if ((unsigned char)dns_if->message[i] == FNET_DNS_NAME_COMPRESSED_MASK) /* look for the beginnig of the response (Question Name == 192 (label compression))*/ { rr_header = (fnet_dns_rr_header_t *)&dns_if->message[i]; /* Check Question Type, Class and Resource Data Length. */ if ( (rr_header->type == dns_if->dns_type) && (rr_header->rr_class == FNET_HTONS(FNET_DNS_HEADER_CLASS_IN))) { /* Resolved.*/ if(rr_header->type == FNET_HTONS(FNET_DNS_TYPE_A)) { dns_if->resolved_ip4_addr[dns_if->addr_number].ip4_addr = *((fnet_ip4_addr_t*)(&rr_header->rdata)); dns_if->resolved_ip4_addr[dns_if->addr_number].ttl = rr_header->ttl; } else /* AF_INET6 */ { FNET_IP6_ADDR_COPY( (fnet_ip6_addr_t*)(&rr_header->rdata), &dns_if->resolved_ip6_addr[dns_if->addr_number].ip6_addr ); dns_if->resolved_ip6_addr[dns_if->addr_number].ttl = rr_header->ttl; } dns_if->addr_number++; } i+=(unsigned int)(sizeof(fnet_dns_rr_header_t)+fnet_ntohs(rr_header->rdlength)-4U-1U); } } } /* else = wrong message.*/ dns_if->state = FNET_DNS_STATE_RELEASE; } else if(received == SOCKET_ERROR) /* Check error.*/ { dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */ } else /* No data. Check timeout */ if(fnet_timer_get_interval(dns_if->last_time, fnet_timer_ticks()) > ((FNET_CFG_DNS_RETRANSMISSION_TIMEOUT*1000U)/FNET_TIMER_PERIOD_MS)) { dns_if->iteration++; if(dns_if->iteration > FNET_CFG_DNS_RETRANSMISSION_MAX) { dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */ } else { dns_if->state = FNET_DNS_STATE_TX; } } else {} break; /*---- RELEASE -------------------------------------------------*/ case FNET_DNS_STATE_RELEASE: { struct fnet_dns_resolved_addr *addr_list = FNET_NULL; fnet_dns_release(); /* Fill fnet_dns_resolved_addr */ if(dns_if->addr_number > 0) { if(dns_if->addr_family == AF_INET) { for(i=0; i<dns_if->addr_number; i++) { fnet_memset_zero(&dns_if->resolved_ip4_addr_sock[i].resolved_addr, sizeof(dns_if->resolved_ip4_addr_sock[i].resolved_addr)); dns_if->resolved_ip4_addr_sock[i].resolved_addr.sa_family = AF_INET; ((struct sockaddr_in*)(&dns_if->resolved_ip4_addr_sock[i].resolved_addr))->sin_addr.s_addr = dns_if->resolved_ip4_addr[i].ip4_addr; dns_if->resolved_ip4_addr_sock[i].resolved_addr_ttl = dns_if->resolved_ip4_addr[i].ttl; } addr_list = dns_if->resolved_ip4_addr_sock; } else if(dns_if->addr_family == AF_INET6) { for(i=0; i<dns_if->addr_number; i++) { fnet_memset_zero(&dns_if->resolved_ip6_addr_sock[i].resolved_addr, sizeof(dns_if->resolved_ip4_addr_sock[i].resolved_addr)); dns_if->resolved_ip6_addr_sock[i].resolved_addr.sa_family = AF_INET6; FNET_IP6_ADDR_COPY(&dns_if->resolved_ip6_addr[i].ip6_addr, &((struct sockaddr_in6*)(&dns_if->resolved_ip6_addr_sock[i].resolved_addr))->sin6_addr.s6_addr); dns_if->resolved_ip6_addr_sock[i].resolved_addr_ttl = dns_if->resolved_ip6_addr[i].ttl; } addr_list = dns_if->resolved_ip6_addr_sock; } else {} } dns_if->handler(addr_list, dns_if->addr_number, dns_if->handler_cookie); /* User Callback.*/ } break; default: break; } }
/************************************************************************ * 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)*/ }
/************************************************************************ * NAME: fnet_ping_state_machine * * DESCRIPTION: PING service state machine. ************************************************************************/ static void fnet_ping_state_machine(void *fnet_ping_if_p) { fnet_int32_t received; fnet_icmp_echo_header_t *hdr; fnet_ping_if_t *ping_if = (fnet_ping_if_t *)fnet_ping_if_p; struct sockaddr addr; fnet_size_t addr_len = sizeof(addr); switch(ping_if->state) { /*===================================*/ case FNET_PING_STATE_SENDING_REQUEST: /* Build message.*/ hdr = (fnet_icmp_echo_header_t *)&fnet_ping_if.buffer[0]; /* Fill ICMP Echo request header.*/ fnet_memset_zero(hdr, sizeof(*hdr)); hdr->header.type = (fnet_uint8_t)((fnet_ping_if.family == AF_INET) ? FNET_ICMP_ECHO: FNET_ICMP6_TYPE_ECHO_REQ); hdr->identifier = FNET_CFG_PING_IDENTIFIER; fnet_ping_if.sequence_number++; hdr->sequence_number = fnet_htons(fnet_ping_if.sequence_number); /* Fill payload data by pattern.*/ fnet_memset(&fnet_ping_if.buffer[sizeof(*hdr)], ping_if->pattern, ping_if->packet_size); /* Checksum.*/ #if FNET_CFG_IP4 if(ping_if->family == AF_INET) { hdr->header.checksum = fnet_checksum_buf(&fnet_ping_if.buffer[0], (sizeof(*hdr) + ping_if->packet_size)); } else #endif #if FNET_CFG_IP6 if(ping_if->family == AF_INET6) { const fnet_ip6_addr_t *src_ip = fnet_ip6_select_src_addr(FNET_NULL, (fnet_ip6_addr_t *)ping_if->target_addr.sa_data); /*TBD Check result.*/ hdr->header.checksum = fnet_checksum_pseudo_buf(&fnet_ping_if.buffer[0], (fnet_uint16_t)(sizeof(*hdr) + ping_if->packet_size), FNET_HTONS((fnet_uint16_t)IPPROTO_ICMPV6), (const fnet_uint8_t *)src_ip, ping_if->target_addr.sa_data, sizeof(fnet_ip6_addr_t)); } else #endif {} /* Send request.*/ fnet_socket_sendto(fnet_ping_if.socket_foreign, (fnet_uint8_t*)(&fnet_ping_if.buffer[0]), (sizeof(*hdr) + ping_if->packet_size), 0u, &ping_if->target_addr, sizeof(ping_if->target_addr)); ping_if->packet_count--; fnet_ping_if.send_time = fnet_timer_ticks(); ping_if->state = FNET_PING_STATE_WAITING_REPLY; break; /*===================================*/ case FNET_PING_STATE_WAITING_REPLY: /* Receive data */ received = fnet_socket_recvfrom(ping_if->socket_foreign, (fnet_uint8_t*)(&ping_if->buffer[0]), FNET_PING_BUFFER_SIZE, 0u, &addr, &addr_len ); if(received > 0 ) { fnet_uint16_t checksum = 0u; hdr = (fnet_icmp_echo_header_t *)(ping_if->buffer); /* Check checksum.*/ #if FNET_CFG_IP4 if(ping_if->family == AF_INET) { checksum = fnet_checksum_buf(&fnet_ping_if.buffer[0], (fnet_size_t)received); } else #endif #if 0 /* #if FNET_CFG_IP6 */ /* TBD case to receive from multicast address ff02::1*/ if(ping_if->family == AF_INET6) { checksum = fnet_checksum_pseudo_buf(&fnet_ping_if.buffer[0], (fnet_uint16_t)(received), IPPROTO_ICMPV6, ping_if->local_addr.sa_data, ping_if->target_addr.sa_data, sizeof(fnet_ip6_addr_t)); } else #endif {} /* Check header.*/ if( checksum ||(hdr->header.type != ((addr.sa_family == AF_INET) ? FNET_ICMP_ECHOREPLY: FNET_ICMP6_TYPE_ECHO_REPLY)) ||(hdr->identifier != FNET_CFG_PING_IDENTIFIER) ||(hdr->sequence_number != fnet_htons(ping_if->sequence_number)) ) { goto NO_DATA; } /* Call handler.*/ if(ping_if->handler) { ping_if->handler(FNET_ERR_OK, ping_if->packet_count, &addr, ping_if->handler_cookie); } if(ping_if->packet_count) { ping_if->state = FNET_PING_STATE_WAITING_TIMEOUT; } else { fnet_ping_release(); } } else if(received == FNET_ERR) { /* Call handler.*/ if(ping_if->handler) { fnet_error_t sock_err ; fnet_size_t option_len; /* Get socket error.*/ option_len = sizeof(sock_err); fnet_socket_getopt(ping_if->socket_foreign, SOL_SOCKET, SO_ERROR, (fnet_uint8_t*)&sock_err, &option_len); ping_if->handler(sock_err, ping_if->packet_count, FNET_NULL, ping_if->handler_cookie); } if(ping_if->packet_count) { ping_if->state = FNET_PING_STATE_WAITING_TIMEOUT; } else { fnet_ping_release(); } } else /* No data. Check timeout */ { NO_DATA: if(fnet_timer_get_interval(fnet_ping_if.send_time, fnet_timer_ticks()) > fnet_ping_if.timeout_clk) { /* Call handler.*/ if(ping_if->handler) { ping_if->handler(FNET_ERR_TIMEDOUT, ping_if->packet_count, FNET_NULL, ping_if->handler_cookie); } if(ping_if->packet_count) { ping_if->state = FNET_PING_STATE_SENDING_REQUEST; } else { fnet_ping_release(); } } } break; /*===================================*/ case FNET_PING_STATE_WAITING_TIMEOUT: if(fnet_timer_get_interval(fnet_ping_if.send_time, fnet_timer_ticks()) > fnet_ping_if.timeout_clk) { ping_if->state = FNET_PING_STATE_SENDING_REQUEST; } break; default: break; /* do nothing, avoid compiler warning "enumeration value not handled in switch" */ } }