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