source: rtems-libbsd/rtemsbsd/debugger/rtems-debugger-remote-tcp.c @ afda2c7

5-freebsd-12freebsd-9.3
Last change on this file since afda2c7 was afda2c7, checked in by Chris Johns <chrisj@…>, on Nov 29, 2016 at 5:13:52 AM

debugger: Set the fd to -1 to indicate being disconnected.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2016 Chris Johns <chrisj@rtems.org>.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <errno.h>
27#include <stdlib.h>
28#include <unistd.h>
29
30#include <arpa/inet.h>
31#include <netinet/in.h>
32#include <netinet/tcp.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35
36#include <rtems/rtems-debugger.h>
37#include <rtems/debugger/rtems-debugger-server.h>
38#include <rtems/debugger/rtems-debugger-remote.h>
39
40#include <rtems/rtems-debugger-remote-tcp.h>
41
42/**
43 * Debugger default server port. 'RT' as ASCII.
44 */
45#define RTEMS_DB_PORT_DEFAULT (8284)
46
47/**
48 * TCP Remote data.
49 */
50typedef struct
51{
52  int fd;
53  int port;
54} rtems_debugger_remote_tcp;
55
56static rtems_debugger_remote_tcp*
57tcp_remote(rtems_debugger_remote* remote)
58{
59  rtems_debugger_remote_tcp* tcp = NULL;
60  rtems_debugger_lock();
61  if (remote != NULL && remote->data != NULL)
62      tcp = (rtems_debugger_remote_tcp*) remote->data;
63  rtems_debugger_unlock();
64  return tcp;
65}
66
67static int
68tcp_remote_begin(rtems_debugger_remote* remote, const char* device)
69{
70  rtems_debugger_remote_tcp* tcp;
71  int                        port;
72  char*                      end;
73
74  rtems_debugger_lock();
75
76  /*
77   * Parse the port number.
78   */
79  port = strtoul(device, &end, 10);
80  if (port == 0 || *end != '\0') {
81    rtems_debugger_printf("error: rtems-db: tcp remote: invalid port: %s\n", device);
82    return -1;
83  }
84
85  tcp = malloc(sizeof(rtems_debugger_remote_tcp));
86  if (tcp == NULL) {
87    errno = ENOMEM;
88    return -1;
89  }
90
91  remote->data = tcp;
92
93  tcp->fd = -1;
94  tcp->port = port;
95
96  rtems_debugger_unlock();
97
98  return 0;
99}
100
101static int
102tcp_remote_end(rtems_debugger_remote* remote)
103{
104  rtems_debugger_lock();
105
106  if (remote != NULL && remote->data != NULL) {
107    rtems_debugger_remote_tcp* tcp = (rtems_debugger_remote_tcp*) remote->data;
108    if (tcp != NULL) {
109      if (tcp->fd >= 0)
110        close(tcp->fd);
111      free(tcp);
112      remote->data = NULL;
113    }
114  }
115
116  rtems_debugger_unlock();
117
118  return 0;
119}
120
121static int
122tcp_remote_connect(rtems_debugger_remote* remote)
123{
124  int                        ld;
125  struct sockaddr_in         addr;
126  socklen_t                  opt;
127  socklen_t                  len;
128  bool                       running;
129  struct timeval             timeout;
130  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
131  int                        r;
132
133  if (rtems_debugger_verbose())
134    rtems_debugger_printf("error: rtems-db: tcp remote: connect\n");
135
136  ld = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
137  if (ld < 0) {
138    rtems_debugger_printf("error: rtems-db: tcp remote: socket: (%d) %s\n",
139                          errno, strerror(errno));
140    return -1;
141  }
142
143  opt = 1;
144  r = setsockopt(ld,
145                 SOL_SOCKET,
146                 SO_REUSEADDR,
147                 (char *) &opt,
148                 sizeof(opt));
149  if (r < 0) {
150    close(ld);
151    rtems_debugger_printf("error: rtems-db: tcp remote: setsocket: reuseaddr: (%d) %s\n",
152                          errno, strerror(errno));
153    return -1;
154  }
155
156  addr.sin_family = PF_INET;
157  addr.sin_port = htons(tcp->port);
158  addr.sin_addr.s_addr = INADDR_ANY;
159
160  r = bind(ld, (struct sockaddr *) &addr, sizeof(addr));
161  if (r < 0) {
162    close(ld);
163    rtems_debugger_printf("error: rtems-db: tcp remote: bind: (%d) %s\n",
164                          errno, strerror(errno));
165    return -1;
166  }
167
168  /*
169   * Backlog of 1 connection.
170   */
171  r = listen(ld, 1);
172  if (r < 0) {
173    close(ld);
174    rtems_debugger_printf("error: rtems-db: tcp remote: listen: (%d) %s\n",
175                          errno, strerror(errno));
176    return -1;
177  }
178
179  /*
180   * Use a random port if the port is 0.
181   */
182  if (tcp->port == 0) {
183    len = sizeof(addr);
184    r = getsockname(ld, (struct sockaddr *) &addr, &len);
185    if (r < 0 || len < sizeof(addr)) {
186      close(ld);
187      rtems_debugger_printf("error: rtems-db: tcp remote: getsockname: (%d) %s\n",
188                            errno, strerror(errno));
189      return -1;
190    }
191    tcp->port = ntohs(addr.sin_port);
192  }
193
194  rtems_debugger_printf("rtems-db: tcp remote: listing on port: %d\n",
195                        tcp->port);
196
197  len = sizeof(addr);
198  tcp->fd = accept(ld, (struct sockaddr *) &addr, &len);
199
200  running = rtems_debugger_server_running();
201
202  close(ld);
203
204  if (tcp->fd < 0) {
205    /*
206     * EBADF means the socket has been closed, ignore it.
207     */
208    if (errno != EBADF)
209      rtems_debugger_printf("error: rtems-db: accept: (%d) %s\n",
210                            errno, strerror(errno));
211    return -1;
212  }
213
214  if (!running) {
215    close(tcp->fd);
216    errno = EIO;
217    return -1;
218  }
219
220  opt = 1;
221  r = setsockopt(tcp->fd,
222                 SOL_SOCKET, SO_KEEPALIVE,
223                 (char*) &opt,
224                 sizeof(opt));
225  if (r < 0) {
226    int errno_ = errno;
227    close(tcp->fd);
228    rtems_debugger_printf("error: rtems-db: tcp remote: set keepalive: (%d) %s\n",
229                          errno, strerror(errno));
230    errno = errno_;
231    return -1;
232  }
233
234  opt = 1;
235  r = setsockopt(tcp->fd,
236                 IPPROTO_TCP, TCP_NODELAY,
237                 (char*) &opt, sizeof(opt));
238  if (r < 0) {
239    int errno_ = errno;
240    close(tcp->fd);
241    rtems_debugger_printf("error: rtems-db: tcp remote: set no-delay: (%d) %s\n",
242                          errno, strerror(errno));
243    errno = errno_;
244    return -1;
245  }
246
247  timeout.tv_sec = rtems_debugger->timeout;
248  timeout.tv_usec = 0;
249
250  r = setsockopt(tcp->fd,
251                 SOL_SOCKET, SO_RCVTIMEO,
252                 (char*) &timeout, sizeof(timeout));
253  if (r < 0) {
254    int errno_ = errno;
255    close(tcp->fd);
256    rtems_debugger_printf("error: rtems-db: tcp remote: set rcv-timeout: (%d) %s\n",
257                          errno, strerror(errno));
258    errno = errno_;
259    return -1;
260  }
261
262  rtems_debugger_printf("rtems-db: tcp remote: connect host: %s\n",
263                        inet_ntoa(addr.sin_addr));
264
265  return 0;
266}
267
268static int
269tcp_remote_disconnect(rtems_debugger_remote* remote)
270{
271  rtems_debugger_remote_tcp* tcp;
272
273  rtems_debugger_lock();
274
275  rtems_debugger_printf("rtems-db: tcp remote: disconnect host\n");
276
277  tcp = (rtems_debugger_remote_tcp*) remote->data;
278  close(tcp->fd);
279  tcp->fd = -1;
280
281  rtems_debugger_unlock();
282
283  return 0;
284}
285
286static bool
287tcp_remote_isconnected(rtems_debugger_remote* remote)
288{
289  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
290  return tcp != NULL && tcp->fd >= 0;
291}
292
293static ssize_t
294tcp_remote_receive(rtems_debugger_remote* remote,
295                   void*                  buf,
296                   size_t                 nbytes)
297{
298  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
299  ssize_t                    len;
300  if (tcp != NULL) {
301    len = read(tcp->fd, buf, nbytes);
302  }
303  else {
304    errno = EIO;
305    len = -1;
306  }
307  return len;
308}
309
310static ssize_t
311tcp_remote_send(rtems_debugger_remote* remote,
312                const void*            buf,
313                size_t                 nbytes)
314{
315  rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
316  ssize_t                    len;
317  if (tcp != NULL) {
318    len = write(tcp->fd, buf, nbytes);
319  }
320  else {
321    errno = EIO;
322    len = -1;
323  }
324  return len;
325}
326
327static rtems_debugger_remote remote_tcp =
328{
329  .name = "tcp",
330  .begin = tcp_remote_begin,
331  .end = tcp_remote_end,
332  .connect = tcp_remote_connect,
333  .disconnect = tcp_remote_disconnect,
334  .isconnected = tcp_remote_isconnected,
335  .read = tcp_remote_receive,
336  .write = tcp_remote_send
337};
338
339int
340rtems_debugger_register_tcp_remote(void)
341{
342  return rtems_debugger_remote_register(&remote_tcp);
343}
Note: See TracBrowser for help on using the repository browser.