1 /* Serial port emulation using sockets. 2 Copyright (C) 1998-2024 Free Software Foundation, Inc. 3 Contributed by Cygnus Solutions. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 /* FIXME: will obviously need to evolve. 19 - connectionless sockets might be more appropriate. */ 20 21 /* This must come before any other includes. */ 22 #include "defs.h" 23 24 #include <errno.h> 25 #ifdef HAVE_FCNTL_H 26 #include <fcntl.h> 27 #endif 28 #include <netdb.h> 29 #include <signal.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <arpa/inet.h> 34 #include <netinet/in.h> 35 #include <sys/select.h> 36 #include <sys/socket.h> 37 #include <sys/time.h> 38 #include <sys/types.h> 39 40 #include "sim-main.h" 41 #include "sim-assert.h" 42 #include "sim-options.h" 43 44 #include "dv-sockser.h" 45 46 #ifndef HAVE_SOCKLEN_T 47 typedef int socklen_t; 48 #endif 49 50 51 /* Compromise between eating cpu and properly busy-waiting. 52 One could have an option to set this but for now that seems 53 like featuritis. */ 54 #define DEFAULT_TIMEOUT 1000 /* microseconds */ 55 56 /* FIXME: These should allocated at run time and kept with other simulator 57 state (duh...). Later. */ 58 const char * sockser_addr = NULL; 59 /* Timeout in microseconds during status flag computation. 60 Setting this to zero achieves proper busy wait semantics but eats cpu. */ 61 static unsigned int sockser_timeout = DEFAULT_TIMEOUT; 62 static int sockser_listen_fd = -1; 63 static int sockser_fd = -1; 64 65 /* FIXME: use tree properties when they're ready. */ 66 67 typedef enum { 68 OPTION_ADDR = OPTION_START 69 } SOCKSER_OPTIONS; 70 71 static DECLARE_OPTION_HANDLER (sockser_option_handler); 72 73 static const OPTION sockser_options[] = 74 { 75 { { "sockser-addr", required_argument, NULL, OPTION_ADDR }, 76 '\0', "SOCKET ADDRESS", "Set serial emulation socket address", 77 sockser_option_handler, NULL }, 78 { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL, NULL } 79 }; 80 81 static SIM_RC 82 sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, 83 char *arg, int is_command) 84 { 85 switch (opt) 86 { 87 case OPTION_ADDR : 88 sockser_addr = arg; 89 break; 90 } 91 92 return SIM_RC_OK; 93 } 94 95 static SIM_RC 96 dv_sockser_init (SIM_DESC sd) 97 { 98 struct hostent *hostent; 99 struct sockaddr_in sockaddr; 100 char hostname[100]; 101 const char *port_str; 102 int tmp,port; 103 104 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT 105 || sockser_addr == NULL) 106 return SIM_RC_OK; 107 108 if (*sockser_addr == '/') 109 { 110 /* support for these can come later */ 111 sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n", 112 sockser_addr); 113 return SIM_RC_FAIL; 114 } 115 116 port_str = strchr (sockser_addr, ':'); 117 if (!port_str) 118 { 119 sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n", 120 sockser_addr); 121 return SIM_RC_FAIL; 122 } 123 tmp = port_str - sockser_addr; 124 if (tmp >= sizeof hostname) 125 tmp = sizeof (hostname) - 1; 126 strncpy (hostname, sockser_addr, tmp); 127 hostname[tmp] = '\000'; 128 port = atoi (port_str + 1); 129 130 hostent = gethostbyname (hostname); 131 if (! hostent) 132 { 133 sim_io_eprintf (sd, "sockser init: unknown host: %s\n", 134 hostname); 135 return SIM_RC_FAIL; 136 } 137 138 sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0); 139 if (sockser_listen_fd == -1) 140 { 141 sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n", 142 strerror (errno)); 143 return SIM_RC_FAIL; 144 } 145 146 sockaddr.sin_family = PF_INET; 147 sockaddr.sin_port = htons (port); 148 memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, 149 sizeof (struct in_addr)); 150 151 tmp = 1; 152 if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof (tmp)) < 0) 153 { 154 sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n", 155 strerror (errno)); 156 } 157 if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0) 158 { 159 sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n", 160 strerror (errno)); 161 close (sockser_listen_fd); 162 sockser_listen_fd = -1; 163 return SIM_RC_FAIL; 164 } 165 if (listen (sockser_listen_fd, 1) < 0) 166 { 167 sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n", 168 strerror (errno)); 169 close (sockser_listen_fd); 170 sockser_listen_fd = -1; 171 return SIM_RC_OK; 172 } 173 174 /* Handle writes to missing client -> SIGPIPE. 175 ??? Need a central signal management module. */ 176 #ifdef SIGPIPE 177 { 178 RETSIGTYPE (*orig) (); 179 orig = signal (SIGPIPE, SIG_IGN); 180 /* If a handler is already set up, don't mess with it. */ 181 if (orig != SIG_DFL && orig != SIG_IGN) 182 signal (SIGPIPE, orig); 183 } 184 #endif 185 186 return SIM_RC_OK; 187 } 188 189 static void 190 dv_sockser_uninstall (SIM_DESC sd) 191 { 192 if (sockser_listen_fd != -1) 193 { 194 close (sockser_listen_fd); 195 sockser_listen_fd = -1; 196 } 197 if (sockser_fd != -1) 198 { 199 close (sockser_fd); 200 sockser_fd = -1; 201 } 202 } 203 204 /* Provide a prototype to silence -Wmissing-prototypes. */ 205 extern MODULE_INIT_FN sim_install_dv_sockser; 206 207 SIM_RC 208 sim_install_dv_sockser (SIM_DESC sd) 209 { 210 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 211 if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK) 212 return SIM_RC_FAIL; 213 sim_module_add_init_fn (sd, dv_sockser_init); 214 sim_module_add_uninstall_fn (sd, dv_sockser_uninstall); 215 return SIM_RC_OK; 216 } 217 218 static int 219 connected_p (SIM_DESC sd) 220 { 221 int numfds,flags; 222 struct timeval tv; 223 fd_set readfds; 224 struct sockaddr sockaddr; 225 socklen_t addrlen; 226 227 if (sockser_listen_fd == -1) 228 return 0; 229 230 if (sockser_fd >= 0) 231 { 232 /* FIXME: has client gone away? */ 233 return 1; 234 } 235 236 /* Not connected. Connect with a client if there is one. */ 237 238 FD_ZERO (&readfds); 239 FD_SET (sockser_listen_fd, &readfds); 240 241 /* ??? One can certainly argue this should be done differently, 242 but for now this is sufficient. */ 243 tv.tv_sec = 0; 244 tv.tv_usec = sockser_timeout; 245 246 numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv); 247 if (numfds <= 0) 248 return 0; 249 250 addrlen = sizeof (sockaddr); 251 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen); 252 if (sockser_fd == -1) 253 return 0; 254 255 /* Set non-blocking i/o. */ 256 #if defined(F_GETFL) && defined(O_NONBLOCK) 257 flags = fcntl (sockser_fd, F_GETFL); 258 flags |= O_NONBLOCK; 259 if (fcntl (sockser_fd, F_SETFL, flags) == -1) 260 { 261 sim_io_eprintf (sd, "unable to set nonblocking i/o"); 262 close (sockser_fd); 263 sockser_fd = -1; 264 return 0; 265 } 266 #endif 267 return 1; 268 } 269 270 int 271 dv_sockser_status (SIM_DESC sd) 272 { 273 int numrfds,numwfds,status; 274 struct timeval tv; 275 fd_set readfds,writefds; 276 277 /* status to return if the socket isn't set up, or select fails */ 278 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY | 279 DV_SOCKSER_DISCONNECTED; 280 281 if (! connected_p (sd)) 282 return status; 283 284 FD_ZERO (&readfds); 285 FD_ZERO (&writefds); 286 FD_SET (sockser_fd, &readfds); 287 FD_SET (sockser_fd, &writefds); 288 289 /* ??? One can certainly argue this should be done differently, 290 but for now this is sufficient. The read is done separately 291 from the write to enforce the delay which we heuristically set to 292 once every SOCKSER_TIMEOUT_FREQ tries. 293 No, this isn't great for SMP situations, blah blah blah. */ 294 295 { 296 static int n; 297 #define SOCKSER_TIMEOUT_FREQ 42 298 if (++n == SOCKSER_TIMEOUT_FREQ) 299 n = 0; 300 if (n == 0) 301 { 302 tv.tv_sec = 0; 303 tv.tv_usec = sockser_timeout; 304 numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv); 305 tv.tv_sec = 0; 306 tv.tv_usec = 0; 307 numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv); 308 } 309 else /* do both selects at once */ 310 { 311 tv.tv_sec = 0; 312 tv.tv_usec = 0; 313 numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv); 314 } 315 } 316 317 status = 0; 318 if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds)) 319 status |= DV_SOCKSER_INPUT_EMPTY; 320 if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds)) 321 status |= DV_SOCKSER_OUTPUT_EMPTY; 322 return status; 323 } 324 325 int 326 dv_sockser_write_buffer (SIM_DESC sd, const unsigned char *buffer, 327 unsigned nr_bytes) 328 { 329 int n; 330 331 if (! connected_p (sd)) 332 return -1; 333 n = write (sockser_fd, buffer, nr_bytes); 334 if (n == -1) 335 { 336 if (errno == EPIPE) 337 { 338 close (sockser_fd); 339 sockser_fd = -1; 340 } 341 return -1; 342 } 343 if (n != nr_bytes) 344 return -1; 345 return nr_bytes; 346 } 347 348 int 349 dv_sockser_write (SIM_DESC sd, unsigned char c) 350 { 351 return dv_sockser_write_buffer (sd, &c, 1); 352 } 353 354 int 355 dv_sockser_read (SIM_DESC sd) 356 { 357 unsigned char c; 358 int n; 359 360 if (! connected_p (sd)) 361 return -1; 362 n = read (sockser_fd, &c, 1); 363 /* ??? We're assuming semantics that may not be correct for all hosts. 364 In particular (from cvssrc/src/server.c), this assumes that we are using 365 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if 366 there is nothing to read. */ 367 if (n == 0) 368 { 369 close (sockser_fd); 370 sockser_fd = -1; 371 return -1; 372 } 373 if (n != 1) 374 return -1; 375 return c; 376 } 377