@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
2828static volatile xemusock_socket_t sock = XS_INVALID_SOCKET ;
2929static volatile bool running = false;
3030static volatile bool exited = false;
31+ static volatile const char * failed = NULL ;
3132static SDL_Thread * thread_id = NULL ;
3233static Uint8 rx_buffer [BUFFER_SIZE ];
3334static Uint8 tx_buffer [BUFFER_SIZE ];
@@ -36,6 +37,8 @@ static SDL_SpinLock lock = 0;
3637static Uint8 serial_regs [0x10 ];
3738static int bitrate_divisor , baudrate ;
3839static int bitrate_divisor_reported = -1 ;
40+ static char * connection_desc = NULL , * connection_string = NULL ;
41+ static volatile int tx_bytes_sum , rx_bytes_sum ;
3942
4043
4144static void close_socket ( void )
@@ -53,6 +56,7 @@ static int the_thread ( void *unused )
5356{
5457 DEBUGPRINT ("SERIALTCP: thread: begin" NL );
5558 Uint8 rx_temp [BUFFER_SIZE ];
59+ static const char zero_transfer_error [] = "Cannot read/write, connection closed by peer?" ;
5660 while (running ) {
5761 const int tx_size = SDL_AtomicGet (& tx_fill );
5862 const int rx_size = SDL_AtomicGet (& rx_fill );
@@ -63,29 +67,61 @@ static int the_thread ( void *unused )
6367 }
6468 int xerr , ret_write = -1 , ret_read = -1 ;
6569 const int ret = xemusock_select_1 (sock , 1000 , what , & xerr );
66- // TODO: error handling, end of connection / lost connection ...
70+ if (!ret )
71+ continue ; // timeout on select
72+ if (ret < 0 ) {
73+ // XSEINTR is handled already inside xemusock_select_1(), so other errors are kind of fatal ...
74+ failed = xemusock_strerror (xerr );
75+ DEBUGPRINT ("SERIALTCP: thread: select() error (%d): %s" NL , xerr , failed );
76+ break ;
77+ }
6778 if ((ret & XEMUSOCK_SELECT_W )) {
6879 ret_write = xemusock_send (sock , tx_buffer , tx_size , & xerr );
80+ if (ret_write < 0 ) {
81+ if (xemusock_should_repeat_from_error (xerr ))
82+ continue ;
83+ failed = xemusock_strerror (xerr );
84+ DEBUGPRINT ("SERIALTCP: thread: send error ret=%d error_code=(%d) error_str=\"%s\"" NL , ret_write , xerr , failed );
85+ break ;
86+ }
87+ if (ret_write == 0 ) {
88+ failed = zero_transfer_error ;
89+ break ;
90+ }
6991 }
7092 if ((ret & XEMUSOCK_SELECT_R )) {
7193 ret_read = xemusock_recv (sock , rx_temp , BUFFER_SIZE - rx_size , & xerr );
94+ if (ret_read < 0 ) {
95+ if (xemusock_should_repeat_from_error (xerr ))
96+ continue ;
97+ failed = xemusock_strerror (xerr );
98+ DEBUGPRINT ("SERIALTCP: thread: recv error ret=%d error_code=(%d) error_str=\"%s\"" NL , ret_read , xerr , failed );
99+ break ;
100+ }
101+ if (ret_read == 0 ) {
102+ failed = zero_transfer_error ;
103+ break ;
104+ }
72105 }
73106 if (ret_read > 0 || ret_write > 0 ) {
74107 SDL_AtomicLock (& lock );
75108 if (ret_read > 0 ) {
76109 const int size = SDL_AtomicGet (& rx_fill );
77110 memcpy (rx_buffer + size , rx_temp , ret_read );
78111 SDL_AtomicSet (& rx_fill , size + ret_read );
112+ rx_bytes_sum += ret_read ;
79113 }
80114 if (ret_write > 0 ) {
81115 const int size = SDL_AtomicGet (& tx_fill );
82116 if (size > ret_write )
83117 memmove (tx_buffer , tx_buffer + ret_write , size - ret_write );
84118 SDL_AtomicSet (& tx_fill , size - ret_write );
119+ tx_bytes_sum += ret_write ;
85120 }
86121 SDL_AtomicUnlock (& lock );
87122 }
88123 }
124+ running = false;
89125 DEBUGPRINT ("SERIALTCP: thread: end" NL );
90126 close_socket ();
91127 exited = true;
@@ -102,63 +138,103 @@ int serialtcp_init ( const char *connection )
102138 ERROR_WINDOW ("%s cannot init connection as it's already on-going!" , error_prefix );
103139 return -1 ;
104140 }
105- unsigned int ip , port ;
106- const char * errmsg = xemusock_parse_string_connection_parameters (connection , & ip , & port );
141+ // Network init must go first, as xemusock_parse_string_connection_parameters() use socket API already.
142+ // It makes a difference on Windows, where winsock initialization must be done first.
143+ const char * errmsg = xemusock_init ();
107144 if (errmsg ) {
108- ERROR_WINDOW ("%s parsing: %s" , error_prefix , errmsg );
109- return -1 ;
110- }
111- if (port < 1 || port >= 0x10000 || !ip ) {
112- ERROR_WINDOW ("%s parsing: bad IP and/or port: %s" , error_prefix , connection );
145+ ERROR_WINDOW ("%s network init problem:\n%s" , error_prefix , errmsg );
113146 return -1 ;
114147 }
115- errmsg = xemusock_init ();
148+ unsigned int ip , port ;
149+ errmsg = xemusock_parse_string_connection_parameters (connection , & ip , & port );
116150 if (errmsg ) {
117- ERROR_WINDOW ("%s network init problem: %s" , error_prefix , errmsg );
151+ ERROR_WINDOW ("%s target parsing:\n %s" , error_prefix , errmsg );
118152 return -1 ;
119153 }
120154 int xerr ;
121155 sock = xemusock_create_for_inet (XEMUSOCK_TCP , XEMUSOCK_BLOCKING , & xerr );
122156 if (sock == XS_INVALID_SOCKET ) {
123- ERROR_WINDOW ("%s cannot create TCP socket: %s" , error_prefix , xemusock_strerror (xerr ));
157+ ERROR_WINDOW ("%s cannot create TCP socket:\n %s" , error_prefix , xemusock_strerror (xerr ));
124158 return -1 ;
125159 }
126160 struct sockaddr_in sock_st ;
127161 xemusock_fill_servaddr_for_inet_ip_netlong (& sock_st , ip , port );
128162 if (xemusock_connect (sock , & sock_st , & xerr )) {
129- ERROR_WINDOW ("%s cannot connect to TCP target: %s" , error_prefix , xemusock_strerror (xerr ));
163+ ERROR_WINDOW ("%s cannot connect to TCP target:\n %s" , error_prefix , xemusock_strerror (xerr ));
130164 close_socket ();
131165 return -1 ;
132166 }
133167 if (xemusock_setsockopt_keepalive (sock , & xerr ))
134- ERROR_WINDOW ("%s warning, could not set KEEPALIVE: %s" , error_prefix , xemusock_strerror (xerr ));
168+ ERROR_WINDOW ("%s warning, could not set KEEPALIVE:\n %s" , error_prefix , xemusock_strerror (xerr ));
135169 if (xemusock_set_nonblocking (sock , 1 , & xerr )) {
136- ERROR_WINDOW ("%s cannot set unblock for TCP target: %s" , error_prefix , xemusock_strerror (xerr ));
170+ ERROR_WINDOW ("%s cannot set unblock for TCP target:\n %s" , error_prefix , xemusock_strerror (xerr ));
137171 close_socket ();
138172 return -1 ;
139173 }
140174 // Reset data structures
141175 SDL_AtomicSet (& rx_fill , 0 );
142176 SDL_AtomicSet (& tx_fill , 0 );
143177 SDL_AtomicUnlock (& lock );
144- running = true;
145- exited = false;
146178 memset (serial_regs , 0 , sizeof serial_regs );
179+ rx_bytes_sum = 0 ;
180+ tx_bytes_sum = 0 ;
147181 bitrate_divisor = 0 ;
148182 baudrate = 19200 ;
183+ const unsigned int ip_native = ntohl (ip );
184+ char ip_string [16 ];
185+ snprintf (ip_string , sizeof ip_string , "%u.%u.%u.%u" , (ip_native >> 24 ) & 0xFF , (ip_native >> 16 ) & 0xFF , (ip_native >> 8 ) & 0xFF , ip_native & 0xFF );
186+ free (connection_string );
187+ connection_string = xemu_strdup (connection );
188+ if (strncmp (ip_string , connection , strlen (ip_string ))) {
189+ const int size = strlen (connection ) + strlen (ip_string ) + 10 ;
190+ connection_desc = xemu_realloc (connection_desc , size );
191+ snprintf (connection_desc , size , "%s (%s)" , connection , ip_string );
192+ } else {
193+ connection_desc = xemu_realloc (connection_desc , strlen (connection ) + 1 );
194+ strcpy (connection_desc , connection );
195+ }
196+ exited = false;
197+ running = true;
198+ failed = NULL ;
149199 // Start thread
200+ DEBUGPRINT ("SERIALTCP: starting connection thread to %s" NL , connection_desc );
150201 thread_id = SDL_CreateThread (the_thread , "Xemu-SerialTCP" , NULL );
151202 if (!thread_id ) {
152203 running = false;
153204 close_socket ();
154- ERROR_WINDOW ("%s cannot create thread: %s" , error_prefix , SDL_GetError ());
205+ ERROR_WINDOW ("%s cannot create thread:\n %s" , error_prefix , SDL_GetError ());
155206 return -1 ;
156207 }
157- OSD (-1 , -1 , "SerialTCP connection established to\n%s" , connection );
208+ OSD (-1 , -1 , "SerialTCP connection established to\n%s" , connection_desc );
158209 return 0 ;
159210}
160211
161212
213+ bool serialtcp_get_connection_desc ( char * param , const unsigned int param_size , char * desc , const unsigned int desc_size , int * tx , int * rx )
214+ {
215+ if (param )
216+ snprintf (param , param_size , "%s" , connection_string ? connection_string : "" );
217+ if (desc )
218+ snprintf (desc , desc_size , "%s" , connection_desc ? connection_desc : "" );
219+ if (tx )
220+ * tx = tx_bytes_sum ;
221+ if (rx )
222+ * rx = rx_bytes_sum ;
223+ return running ;
224+ }
225+
226+
227+ const char * serialtcp_get_connection_error ( const bool remove_error )
228+ {
229+ if (running )
230+ return NULL ;
231+ const char * err = (const char * )failed ;
232+ if (remove_error )
233+ failed = NULL ;
234+ return err ;
235+ }
236+
237+
162238int serialtcp_shutdown ( void )
163239{
164240 if (!running ) {
@@ -189,7 +265,7 @@ int serialtcp_shutdown ( void )
189265int serialtcp_restart ( const char * connection )
190266{
191267 if (!connection || !* connection ) {
192- ERROR_WINDOW ("Cannot restart SerialTCP: no target specification" );
268+ ERROR_WINDOW ("Cannot restart SerialTCP:\nno target specification" );
193269 return -1 ;
194270 }
195271 DEBUGPRINT ("SERIALTCP: restarting connection ..." NL );
@@ -209,7 +285,7 @@ static int send_byte ( const Uint8 byte )
209285 tx_buffer [size ] = byte ;
210286 SDL_AtomicSet (& tx_fill , size + 1 );
211287 SDL_AtomicUnlock (& lock );
212- DEBUGPRINT ("SERIALTCP: byte sent: $%02X" NL , byte );
288+ // DEBUGPRINT("SERIALTCP: byte sent: $%02X" NL, byte);
213289 return 0 ;
214290}
215291
@@ -230,7 +306,7 @@ static int recv_byte ( const bool also_remove )
230306 SDL_AtomicSet (& rx_fill , size - 1 );
231307 }
232308 SDL_AtomicUnlock (& lock );
233- DEBUGPRINT ("SERIALTCP: byte %s $%02X" NL , also_remove ? "removed" : "received" , byte );
309+ // DEBUGPRINT("SERIALTCP: byte %s $%02X" NL, also_remove ? "removed" : "received", byte);
234310 return byte ;
235311}
236312
0 commit comments