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