/************************************************************************ * NAME: fnet_telnet_send_cmd * * DESCRIPTION: Wrie command to the TX buffer. ************************************************************************/ static void fnet_telnet_send_cmd(struct fnet_telnet_session_if *session, char command, char option ) { tx_buffer_write(session, (char)FNET_TELNET_CMD_IAC); tx_buffer_write(session, command); tx_buffer_write(session, option); /* Send the command.*/ fnet_telnet_send(session); FNET_DEBUG_TELNET("TELNET: Send option = %d", option); }
/************************************************************************ * 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: 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: fnet_telnet_init * * DESCRIPTION: Initialization of the Telnet server. *************************************************************************/ fnet_telnet_desc_t fnet_telnet_init( struct fnet_telnet_params *params ) { struct sockaddr local_addr; struct fnet_telnet_if *telnet_if = 0; /* Socket options. */ const struct linger linger_option ={1, /*l_onoff*/ 4 /*l_linger*/}; const unsigned long bufsize_option = FNET_CFG_TELNET_SOCKET_BUF_SIZE; const int keepalive_option = 1; const int keepcnt_option = FNET_TELNET_TCP_KEEPCNT; const int keepintvl_option = FNET_TELNET_TCP_KEEPINTVL; const int keepidle_option = FNET_TELNET_TCP_KEEPIDLE; int i; if(params == 0 ) { FNET_DEBUG_TELNET("TELNET: Wrong init parameters."); goto ERROR_1; } /* Try to find free Telnet server descriptor. */ #if (FNET_CFG_TELNET_MAX > 1) { int i; for(i=0; i<FNET_CFG_TELNET_MAX; i++) { if(telnet_if_list[i].enabled == FNET_FALSE) { telnet_if = &telnet_if_list[i]; break; } } } #else if(telnet_if_list[0].enabled == FNET_FALSE) telnet_if = &telnet_if_list[0]; #endif /* No free Telnet server descriptor. */ if(telnet_if == 0) { FNET_DEBUG_TELNET("TELNET: No free Telnet Server."); goto ERROR_1; } local_addr = params->address; if(local_addr.sa_port == 0) local_addr.sa_port = FNET_CFG_TELNET_PORT; /* Aply the default port. */ if(local_addr.sa_family == AF_UNSPEC) local_addr.sa_family = AF_SUPPORTED; /* Asign supported families.*/ /* Create listen socket */ if((telnet_if->socket_listen = socket(local_addr.sa_family, SOCK_STREAM, 0)) == SOCKET_INVALID) { FNET_DEBUG_TELNET("TELNET: Socket creation error."); goto ERROR_1; } if(bind(telnet_if->socket_listen, (struct sockaddr *)(&local_addr), sizeof(local_addr)) == SOCKET_ERROR) { FNET_DEBUG_TELNET("TELNET: Socket bind error."); goto ERROR_2; } /* Set socket options. */ if( /* Setup linger option. */ (setsockopt (telnet_if->socket_listen, SOL_SOCKET, SO_LINGER, (char *)&linger_option, sizeof(linger_option)) == SOCKET_ERROR) || /* Set socket buffer size. */ (setsockopt(telnet_if->socket_listen, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize_option, sizeof(bufsize_option))== SOCKET_ERROR) || (setsockopt(telnet_if->socket_listen, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize_option, sizeof(bufsize_option))== SOCKET_ERROR) || /* Enable keepalive_option option. */ (setsockopt (telnet_if->socket_listen, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive_option, sizeof(keepalive_option)) == SOCKET_ERROR) || /* Keepalive probe retransmit limit. */ (setsockopt (telnet_if->socket_listen, IPPROTO_TCP, TCP_KEEPCNT, (char *)&keepcnt_option, sizeof(keepcnt_option)) == SOCKET_ERROR) || /* Keepalive retransmit interval.*/ (setsockopt (telnet_if->socket_listen, IPPROTO_TCP, TCP_KEEPINTVL, (char *)&keepintvl_option, sizeof(keepintvl_option)) == SOCKET_ERROR) || /* Time between keepalive probes.*/ (setsockopt (telnet_if->socket_listen, IPPROTO_TCP, TCP_KEEPIDLE, (char *)&keepidle_option, sizeof(keepidle_option)) == SOCKET_ERROR) ) { FNET_DEBUG_TELNET("TELNET: Socket setsockopt() error."); goto ERROR_2; } telnet_if->backlog = FNET_CFG_TELNET_SESSION_MAX; if(listen(telnet_if->socket_listen, telnet_if->backlog) == SOCKET_ERROR) { FNET_DEBUG_TELNET("TELNET: Socket listen error."); goto ERROR_2; } /* Register service. */ telnet_if->service_descriptor = fnet_poll_service_register(fnet_telnet_state_machine, (void *) telnet_if); if(telnet_if->service_descriptor == (fnet_poll_desc_t)FNET_ERR) { FNET_DEBUG_TELNET("TELNET: Service registration error."); goto ERROR_2; } for(i=0; i<FNET_CFG_TELNET_SESSION_MAX; i++) { struct fnet_telnet_session_if *session = &telnet_if->session[i]; /* Reset buffer pointers. Move it to init state. */ session->tx_buffer_head_index = 0; session->rx_buffer_head = session->rx_buffer; session->rx_buffer_tail = session->rx_buffer; session->rx_buffer_end = &session->rx_buffer[FNET_TELNET_RX_BUFFER_SIZE]; /* Setup stream. */ session->stream.id = (long)(session); session->stream.putchar = fnet_telnet_putchar; session->stream.getchar = fnet_telnet_getchar; session->stream.flush = fnet_telnet_flush; /* Init shell. */ session->shell_params.shell = params->shell; session->shell_params.cmd_line_buffer = session->cmd_line_buffer; session->shell_params.cmd_line_buffer_size = sizeof(session->cmd_line_buffer); session->shell_params.stream = &session->stream; session->shell_params.echo = FNET_CFG_TELNET_SHELL_ECHO; session->socket_foreign = SOCKET_INVALID; session->state = FNET_TELNET_STATE_LISTENING; } telnet_if->session_active = FNET_NULL; telnet_if->enabled = FNET_TRUE; return (fnet_telnet_desc_t)telnet_if; ERROR_2: closesocket(telnet_if->socket_listen); ERROR_1: return (fnet_telnet_desc_t)FNET_ERR; }
/************************************************************************ * NAME: fnet_telnet_state_machine * * DESCRIPTION: Telnet server state machine. ************************************************************************/ static void fnet_telnet_state_machine( void *telnet_if_p ) { struct sockaddr foreign_addr; int res; struct fnet_telnet_if *telnet = (struct fnet_telnet_if *)telnet_if_p; char rx_data[1]; int len; int i; struct fnet_telnet_session_if *session; for(i=0; i<FNET_CFG_TELNET_SESSION_MAX; i++) { session = &telnet->session[i]; telnet->session_active = session; do { switch(session->state) { /*---- LISTENING ------------------------------------------------*/ case FNET_TELNET_STATE_LISTENING: len = sizeof(foreign_addr); session->socket_foreign = accept(telnet->socket_listen, (struct sockaddr *) &foreign_addr, &len); if(session->socket_foreign != SOCKET_INVALID) { #if FNET_CFG_DEBUG_TELNET { char ip_str[FNET_IP_ADDR_STR_SIZE]; fnet_inet_ntop(foreign_addr.sa_family, foreign_addr.sa_data, ip_str, sizeof(ip_str)); FNET_DEBUG_TELNET("\nTELNET: New connection: %s; Port: %d.", ip_str, fnet_ntohs(foreign_addr.sa_port)); } #endif /* Init Shell. */ session->shell_descriptor = fnet_shell_init(&session->shell_params); if(session->shell_descriptor == FNET_ERR) { session->shell_descriptor = 0; FNET_DEBUG_TELNET("TELNET: Shell Service registration error."); session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ } else { listen(telnet->socket_listen, --telnet->backlog); /* Ignor other connections.*/ /* Reset TX timeout. */ session->state = FNET_TELNET_STATE_RECEIVING; /* => WAITING data */ } } break; /*---- NORMAL -----------------------------------------------*/ case FNET_TELNET_STATE_RECEIVING: if(rx_buffer_free_space(session)>0) { res = recv(session->socket_foreign, rx_data, 1, 0); if(res == 1) { if(rx_data[0] == FNET_TELNET_CMD_IAC ) { session->state = FNET_TELNET_STATE_IAC; /*=> Handle IAC */ } else { rx_buffer_write (session, rx_data[0]); } } else if (res == SOCKET_ERROR) { session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ } } break; /*---- IAC -----------------------------------------------*/ case FNET_TELNET_STATE_IAC: FNET_DEBUG_TELNET("TELNET: STATE_IAC"); if((res = recv(session->socket_foreign, rx_data, 1, 0) )!= SOCKET_ERROR) { if(res) { switch(rx_data[0]) { case FNET_TELNET_CMD_WILL: session->state = FNET_TELNET_STATE_DONT; break; case FNET_TELNET_CMD_DO: session->state = FNET_TELNET_STATE_WONT; break; case FNET_TELNET_CMD_WONT: case FNET_TELNET_CMD_DONT: session->state = FNET_TELNET_STATE_SKIP ; break; case FNET_TELNET_CMD_IAC: /* the IAC need be doubled to be sent as data, and the other 255 codes may be passed transparently. */ rx_buffer_write (session, rx_data[0]); default: session->state = FNET_TELNET_STATE_RECEIVING; /*=> Ignore commands */ } } } else { session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ } break; /*---- DONT & WONT -----------------------------------------------*/ case FNET_TELNET_STATE_DONT: case FNET_TELNET_STATE_WONT: { char command; if(session->state == FNET_TELNET_STATE_DONT) { FNET_DEBUG_TELNET("TELNET: STATE_DONT"); command = FNET_TELNET_CMD_DONT; } else { FNET_DEBUG_TELNET("TELNET: STATE_WONT"); command = FNET_TELNET_CMD_WONT; } if(tx_buffer_free_space(session) >= 3) { res = recv(session->socket_foreign, rx_data, 1, 0); if(res == 1) { /* Send command. */ fnet_telnet_send_cmd(session, command, rx_data[0]); session->state = FNET_TELNET_STATE_RECEIVING; } else if (res == SOCKET_ERROR) { session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ } } } break; /*---- SKIP -----------------------------------------------*/ case FNET_TELNET_STATE_SKIP: FNET_DEBUG_TELNET("TELNET: STATE_SKIP"); res = recv(session->socket_foreign, rx_data, 1, 0); if(res == 1) { session->state = FNET_TELNET_STATE_RECEIVING; } else if (res == SOCKET_ERROR) { session->state = FNET_TELNET_STATE_CLOSING; /*=> CLOSING */ } break; /*---- CLOSING --------------------------------------------*/ case FNET_TELNET_STATE_CLOSING: FNET_DEBUG_TELNET("TELNET: STATE_CLOSING"); if(session->shell_descriptor) { fnet_shell_release(session->shell_descriptor); session->shell_descriptor = 0; } session->rx_buffer_head = session->rx_buffer; session->rx_buffer_tail = session->rx_buffer; closesocket(session->socket_foreign); session->socket_foreign = SOCKET_INVALID; listen(telnet->socket_listen, ++telnet->backlog); /* Allow connection.*/ session->state = FNET_TELNET_STATE_LISTENING; /*=> LISTENING */ break; default: break; } } while(session->state == FNET_TELNET_STATE_CLOSING); } }