diff --git a/software/io/network/network_target.cc b/software/io/network/network_target.cc index 6c711d4e9..293924c19 100644 --- a/software/io/network/network_target.cc +++ b/software/io/network/network_target.cc @@ -4,7 +4,7 @@ * Created on: Jul 22, 2015 * Author: Gideon */ - +#include "../network/user_listener.h" #include "network_target.h" #include "network_interface.h" #include "socket.h" @@ -23,12 +23,19 @@ Message c_status_no_socket = { 23, true, (uint8_t *)"85,ERROR OPENING Message c_status_socket_closed = { 28, true, (uint8_t *)"01,CONNECTION CLOSED BY HOST" }; Message c_status_net_no_data = { 26, true, (uint8_t *)"03,MORE DATA NOT SUPPORTED" }; Message c_status_internal_error = { 17, true, (uint8_t *)"86,INTERNAL ERROR" }; +Message c_status_listen_bind_error = { 30, true, (uint8_t *)"87,LISTENER PORT BINDING ERROR" }; +Message c_status_listen_open_error = { 27, true, (uint8_t *)"88,LISTENER PORT OPEN ERROR" }; +Message c_status_listen_error = { 29, true, (uint8_t *)"88,LISTENER PORT LISTEN ERROR" }; +Message c_status_listen_accept_error = { 29, true, (uint8_t *)"88,LISTENER PORT ACCEPT ERROR" }; +Message c_status_listen_connected = { 29, true, (uint8_t *)"89,LISTENER ALREADY CONNECTED" }; NetworkTarget::NetworkTarget(int id) { command_targets[id] = this; data_message.message = new uint8_t[512]; status_message.message = new uint8_t[80]; + + userlistener.set_state(INCOMING_SOCKET_STATE_NOT_LISTENING); } NetworkTarget::~NetworkTarget() @@ -165,6 +172,84 @@ void NetworkTarget :: parse_command(Message *command, Message **reply, Message * case NET_CMD_WRITE_SOCKET: write_socket(command, reply, status); break; + case NET_CMD_START_LISTEN_SOCKET: + { + uint8_t lstnState = userlistener.get_state(); + int port_number = uint16_t(command->message[2]) | (uint16_t(command->message[3]) << 8); + + if (lstnState == INCOMING_SOCKET_STATE_NOT_LISTENING) + { + userlistener.set_port(port_number); + userlistener.set_state(INCOMING_SOCKET_STATE_LISTENING); + *reply = &c_message_empty; + *status = &c_status_ok; + break; + } + if (lstnState == INCOMING_SOCKET_STATE_LISTENING) + { + // user could change the listening port, so shut down current listener + userlistener.set_state(INCOMING_SOCKET_STATE_NOT_LISTENING); + userlistener.set_port(port_number); + userlistener.set_state(INCOMING_SOCKET_STATE_LISTENING); + *reply = &c_message_empty; + *status = &c_status_ok; + break; + } + if(lstnState == INCOMING_SOCKET_STATE_CONNECTED) + { + *reply = &c_message_empty; + *status = &c_status_listen_connected; + break; + } + if(lstnState == INCOMING_SOCKET_STATE_BIND_ERROR) + { + *reply = &c_message_empty; + *status = &c_status_listen_bind_error; + break; + } + if(lstnState == INCOMING_SOCKET_STATE_OPEN_ERROR) + { + *reply = &c_message_empty; + *status = &c_status_listen_open_error; + break; + } + if(lstnState == INCOMING_SOCKET_STATE_LISTEN_ERROR) + { + *reply = &c_message_empty; + *status = &c_status_listen_error; + break; + } + if(lstnState == INCOMING_SOCKET_STATE_ACCEPT_ERROR) + { + *reply = &c_message_empty; + *status = &c_status_listen_accept_error; + break; + } + break; + } + case NET_CMD_STOP_LISTEN_SOCKET: + userlistener.set_state(INCOMING_SOCKET_STATE_NOT_LISTENING); + *reply = &c_message_empty; + *status = &c_status_ok; + break; + case NET_CMD_GET_LISTEN_STATE: + uint8_t listenstate; + listenstate = userlistener.get_state(); + *status = &c_status_ok; + *reply = &data_message; + data_message.message[0] = listenstate; + data_message.length = 1; + data_message.last_part = true; + break; + case NET_CMD_GET_LISTEN_SOCKET: + int listensocket; + listensocket = userlistener.get_socket(); + *status = &c_status_ok; + *reply = &data_message; + data_message.message[0] = (uint8_t)listensocket; + data_message.length = 1; + data_message.last_part = true; + break; default: *reply = &c_message_empty; *status = &c_status_unknown_command; diff --git a/software/io/network/network_target.h b/software/io/network/network_target.h index 469b15818..cd8151e3a 100644 --- a/software/io/network/network_target.h +++ b/software/io/network/network_target.h @@ -22,12 +22,25 @@ #define NET_CMD_READ_SOCKET 0x10 #define NET_CMD_WRITE_SOCKET 0x11 +#define NET_CMD_START_LISTEN_SOCKET 0x12 +#define NET_CMD_STOP_LISTEN_SOCKET 0x13 +#define NET_CMD_GET_LISTEN_STATE 0x14 +#define NET_CMD_GET_LISTEN_SOCKET 0x15 + +#define LISTEN_STATE_NOT_LISTENING 0x00 +#define LISTEN_STATE_LISTENING 0x01 +#define LISTEN_STATE_CONNECTED 0x02 + + #define NET_CMD_BUFSIZE 2048 class NetworkTarget : public CommandTarget { Message data_message; Message status_message; uint8_t buffer[NET_CMD_BUFSIZE]; + UserListener userlistener; + bool isListening; + int connectedSocket; void open_socket(Message *command, Message **reply, Message **status, int); void read_socket(Message *command, Message **reply, Message **status); void write_socket(Message *command, Message **reply, Message **status); diff --git a/software/network/user_listener.cc b/software/network/user_listener.cc new file mode 100644 index 000000000..7f9762b54 --- /dev/null +++ b/software/network/user_listener.cc @@ -0,0 +1,116 @@ +/* + * user_listener.cc + * + * Created on: July 12, 2019 + * Author: Scott Hutter + */ + +#include "socket.h" +#include "errno.h" +#include "user_listener.h" + +static void user_listener_listen_task(void *a) +{ + UserListener *listener = (UserListener *)a; + listener->listenTask(); + vTaskDelete(NULL); +} + +UserListener :: UserListener() +{ + state = INCOMING_SOCKET_STATE_NOT_LISTENING; +} + +void UserListener :: listenTask(void) +{ + socklen_t clilen; + struct sockaddr_in serv_addr, cli_addr; + + listen_socket = socket(AF_INET, SOCK_STREAM, 0); + if (listen_socket < 0) { + puts("ERROR opening socket"); + close_all(); + state = INCOMING_SOCKET_STATE_OPEN_ERROR; + return; + } + + memset((char *) &serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(port); + if (bind(listen_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + puts("ERROR on binding"); + close_all(); + state = INCOMING_SOCKET_STATE_BIND_ERROR; + return; + } + + int err = listen(listen_socket, 2); + if(err < 0) + { + puts("ERROR on listen"); + close_all(); + state = INCOMING_SOCKET_STATE_LISTEN_ERROR; + return; + } + + while(1) { + clilen = sizeof(cli_addr); + answer_socket = accept(listen_socket, (struct sockaddr *) &cli_addr, &clilen); + + if (answer_socket < 0) { + puts("ERROR on accept"); + close_all(); + state = INCOMING_SOCKET_STATE_ACCEPT_ERROR; + return; + } + + struct timeval tv; + tv.tv_sec = 20; // bug in lwip; this is just used directly as tick value + tv.tv_usec = 20; + setsockopt(answer_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); + + shutdown(listen_socket, SHUT_RDWR); + closesocket(listen_socket); + state = INCOMING_SOCKET_STATE_CONNECTED; + return; + } + +} + +uint8_t UserListener :: get_state(void) +{ + return state; +} + +void UserListener :: set_port(uint16_t newport) +{ + port = newport; +} + +void UserListener :: set_state(uint8_t newstate) +{ + state = newstate; + + if(state == INCOMING_SOCKET_STATE_LISTENING) + { + xTaskCreate( user_listener_listen_task, "Socket User Listener", configMINIMAL_STACK_SIZE, this, tskIDLE_PRIORITY + 1, &listenTaskHandle ); + } +} + +int UserListener :: get_socket() +{ + if(state == INCOMING_SOCKET_STATE_CONNECTED) + return answer_socket; + else + return 0; +} + +int UserListener :: close_all(void) +{ + shutdown(answer_socket, SHUT_RDWR); + closesocket(answer_socket); + + shutdown(listen_socket, SHUT_RDWR); + closesocket(listen_socket); +} \ No newline at end of file diff --git a/software/network/user_listener.h b/software/network/user_listener.h new file mode 100644 index 000000000..4e57f0e6d --- /dev/null +++ b/software/network/user_listener.h @@ -0,0 +1,43 @@ +/* + * user_listener.h + * + * Created on: Jul 7 2019 + * Author: Scott Hutter + */ + +#ifndef NETWORK_USER_LISTENER_H_ +#define NETWORK_USER_LISTENER_H_ + +#include "FreeRTOS.h" +#include "task.h" + +#define INCOMING_SOCKET_STATE_NOT_LISTENING 0x00 +#define INCOMING_SOCKET_STATE_LISTENING 0x01 +#define INCOMING_SOCKET_STATE_CONNECTED 0x02 +#define INCOMING_SOCKET_STATE_BIND_ERROR 0x03 +#define INCOMING_SOCKET_STATE_OPEN_ERROR 0x04 +#define INCOMING_SOCKET_STATE_LISTEN_ERROR 0x05 +#define INCOMING_SOCKET_STATE_ACCEPT_ERROR 0x06 + +class UserListener +{ +private: + int listen_socket; + int answer_socket; + uint8_t state; + uint16_t port; + +public: + TaskHandle_t listenTaskHandle; + + UserListener(); + void listenTask(void); + void set_state(uint8_t); + uint8_t get_state(void); + int get_socket(void); + void set_port(uint16_t); + int close_all(void); + bool taskdeleted; +}; + +#endif /* NETWORK_SOCKET_GUI_H_ */ diff --git a/target/software/nios2_u64/Makefile b/target/software/nios2_u64/Makefile index 7227db62d..4598979b3 100755 --- a/target/software/nios2_u64/Makefile +++ b/target/software/nios2_u64/Makefile @@ -33,7 +33,7 @@ SRCS_C = itu.c \ sid_coeff.c \ nios_main.c \ alt_malloc_lock.c \ - alt_do_ctors.c + alt_do_ctors.c SRCS_CC = u2p_init.cc \ small_printf.cc \ @@ -136,6 +136,7 @@ SRCS_CC = u2p_init.cc \ filetype_tap.cc \ socket_stream.cc \ socket_gui.cc \ + user_listener.cc \ socket_dma.cc \ rmii_interface.cc \ home_directory.cc \ diff --git a/target/software/nios2_ultimate/Makefile b/target/software/nios2_ultimate/Makefile index fd3dfd0bc..2ae8fca3a 100755 --- a/target/software/nios2_ultimate/Makefile +++ b/target/software/nios2_ultimate/Makefile @@ -132,6 +132,7 @@ SRCS_CC = u2p_init.cc \ filetype_tap.cc \ socket_stream.cc \ socket_gui.cc \ + user_listener.cc \ socket_dma.cc \ socket_test.cc \ rmii_interface.cc \