Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:15

0001 /*
0002  * Copyright (c) 2016 Chris Johns <chrisj@rtems.org>.  All rights reserved.
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  * 1. Redistributions of source code must retain the above copyright
0008  *    notice, this list of conditions and the following disclaimer.
0009  * 2. Redistributions in binary form must reproduce the above copyright
0010  *    notice, this list of conditions and the following disclaimer in the
0011  *    documentation and/or other materials provided with the distribution.
0012  *
0013  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0014  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0016  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0017  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0018  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0019  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0020  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0021  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0022  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0023  * SUCH DAMAGE.
0024  */
0025 
0026 #include <errno.h>
0027 #include <stdlib.h>
0028 #include <unistd.h>
0029 
0030 #include <arpa/inet.h>
0031 #include <netinet/in.h>
0032 #include <netinet/tcp.h>
0033 #include <sys/types.h>
0034 #include <sys/socket.h>
0035 
0036 #include <rtems/rtems-debugger.h>
0037 #include <rtems/debugger/rtems-debugger-server.h>
0038 #include <rtems/debugger/rtems-debugger-remote.h>
0039 
0040 #include <rtems/rtems-debugger-remote-tcp.h>
0041 
0042 /**
0043  * Debugger default server port. 'RT' as ASCII.
0044  */
0045 #define RTEMS_DB_PORT_DEFAULT (8284)
0046 
0047 /**
0048  * TCP Remote data.
0049  */
0050 typedef struct
0051 {
0052   int fd;
0053   int port;
0054 } rtems_debugger_remote_tcp;
0055 
0056 static rtems_debugger_remote_tcp*
0057 tcp_remote(rtems_debugger_remote* remote)
0058 {
0059   rtems_debugger_remote_tcp* tcp = NULL;
0060   rtems_debugger_lock();
0061   if (remote != NULL && remote->data != NULL)
0062       tcp = (rtems_debugger_remote_tcp*) remote->data;
0063   rtems_debugger_unlock();
0064   return tcp;
0065 }
0066 
0067 static int
0068 tcp_remote_begin(rtems_debugger_remote* remote, const char* device)
0069 {
0070   rtems_debugger_remote_tcp* tcp;
0071   int                        port;
0072   char*                      end;
0073 
0074   rtems_debugger_lock();
0075 
0076   /*
0077    * Parse the port number.
0078    */
0079   port = strtoul(device, &end, 10);
0080   if (port == 0 || *end != '\0') {
0081     rtems_debugger_printf("error: rtems-db: tcp remote: invalid port: %s\n", device);
0082     return -1;
0083   }
0084 
0085   tcp = malloc(sizeof(rtems_debugger_remote_tcp));
0086   if (tcp == NULL) {
0087     errno = ENOMEM;
0088     return -1;
0089   }
0090 
0091   remote->data = tcp;
0092 
0093   tcp->fd = -1;
0094   tcp->port = port;
0095 
0096   rtems_debugger_unlock();
0097 
0098   return 0;
0099 }
0100 
0101 static int
0102 tcp_remote_end(rtems_debugger_remote* remote)
0103 {
0104   rtems_debugger_lock();
0105 
0106   if (remote != NULL && remote->data != NULL) {
0107     rtems_debugger_remote_tcp* tcp = (rtems_debugger_remote_tcp*) remote->data;
0108     if (tcp != NULL) {
0109       if (tcp->fd >= 0)
0110         close(tcp->fd);
0111       free(tcp);
0112       remote->data = NULL;
0113     }
0114   }
0115 
0116   rtems_debugger_unlock();
0117 
0118   return 0;
0119 }
0120 
0121 static int
0122 tcp_remote_connect(rtems_debugger_remote* remote)
0123 {
0124   int                        ld;
0125   struct sockaddr_in         addr = {0};
0126   socklen_t                  opt;
0127   socklen_t                  len;
0128   bool                       running;
0129   struct timeval             timeout;
0130   rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
0131   int                        r;
0132 
0133   if (rtems_debugger_verbose())
0134     rtems_debugger_printf("error: rtems-db: tcp remote: connect\n");
0135 
0136   ld = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
0137   if (ld < 0) {
0138     rtems_debugger_printf("error: rtems-db: tcp remote: socket: (%d) %s\n",
0139                           errno, strerror(errno));
0140     return -1;
0141   }
0142 
0143   opt = 1;
0144   r = setsockopt(ld,
0145                  SOL_SOCKET,
0146                  SO_REUSEADDR,
0147                  (char *) &opt,
0148                  sizeof(opt));
0149   if (r < 0) {
0150     close(ld);
0151     rtems_debugger_printf("error: rtems-db: tcp remote: setsocket: reuseaddr: (%d) %s\n",
0152                           errno, strerror(errno));
0153     return -1;
0154   }
0155 
0156   addr.sin_family = PF_INET;
0157   addr.sin_port = htons(tcp->port);
0158   addr.sin_addr.s_addr = INADDR_ANY;
0159 
0160   r = bind(ld, (struct sockaddr *) &addr, sizeof(addr));
0161   if (r < 0) {
0162     close(ld);
0163     rtems_debugger_printf("error: rtems-db: tcp remote: bind: (%d) %s\n",
0164                           errno, strerror(errno));
0165     return -1;
0166   }
0167 
0168   /*
0169    * Backlog of 1 connection.
0170    */
0171   r = listen(ld, 1);
0172   if (r < 0) {
0173     close(ld);
0174     rtems_debugger_printf("error: rtems-db: tcp remote: listen: (%d) %s\n",
0175                           errno, strerror(errno));
0176     return -1;
0177   }
0178 
0179   /*
0180    * Use a random port if the port is 0.
0181    */
0182   if (tcp->port == 0) {
0183     len = sizeof(addr);
0184     r = getsockname(ld, (struct sockaddr *) &addr, &len);
0185     if (r < 0 || len < sizeof(addr)) {
0186       close(ld);
0187       rtems_debugger_printf("error: rtems-db: tcp remote: getsockname: (%d) %s\n",
0188                             errno, strerror(errno));
0189       return -1;
0190     }
0191     tcp->port = ntohs(addr.sin_port);
0192   }
0193 
0194   rtems_debugger_printf("rtems-db: tcp remote: listing on port: %d\n",
0195                         tcp->port);
0196 
0197   len = sizeof(addr);
0198   tcp->fd = accept(ld, (struct sockaddr *) &addr, &len);
0199 
0200   running = rtems_debugger_server_running();
0201 
0202   close(ld);
0203 
0204   if (tcp->fd < 0) {
0205     /*
0206      * EBADF means the socket has been closed, ignore it.
0207      */
0208     if (errno != EBADF)
0209       rtems_debugger_printf("error: rtems-db: accept: (%d) %s\n",
0210                             errno, strerror(errno));
0211     return -1;
0212   }
0213 
0214   if (!running) {
0215     close(tcp->fd);
0216     errno = EIO;
0217     return -1;
0218   }
0219 
0220   opt = 1;
0221   r = setsockopt(tcp->fd,
0222                  SOL_SOCKET, SO_KEEPALIVE,
0223                  (char*) &opt,
0224                  sizeof(opt));
0225   if (r < 0) {
0226     int errno_ = errno;
0227     close(tcp->fd);
0228     rtems_debugger_printf("error: rtems-db: tcp remote: set keepalive: (%d) %s\n",
0229                           errno, strerror(errno));
0230     errno = errno_;
0231     return -1;
0232   }
0233 
0234   opt = 1;
0235   r = setsockopt(tcp->fd,
0236                  IPPROTO_TCP, TCP_NODELAY,
0237                  (char*) &opt, sizeof(opt));
0238   if (r < 0) {
0239     int errno_ = errno;
0240     close(tcp->fd);
0241     rtems_debugger_printf("error: rtems-db: tcp remote: set no-delay: (%d) %s\n",
0242                           errno, strerror(errno));
0243     errno = errno_;
0244     return -1;
0245   }
0246 
0247   timeout.tv_sec = rtems_debugger->timeout;
0248   timeout.tv_usec = 0;
0249 
0250   r = setsockopt(tcp->fd,
0251                  SOL_SOCKET, SO_RCVTIMEO,
0252                  (char*) &timeout, sizeof(timeout));
0253   if (r < 0) {
0254     int errno_ = errno;
0255     close(tcp->fd);
0256     rtems_debugger_printf("error: rtems-db: tcp remote: set rcv-timeout: (%d) %s\n",
0257                           errno, strerror(errno));
0258     errno = errno_;
0259     return -1;
0260   }
0261 
0262   rtems_debugger_printf("rtems-db: tcp remote: connect host: %s\n",
0263                         inet_ntoa(addr.sin_addr));
0264 
0265   return 0;
0266 }
0267 
0268 static int
0269 tcp_remote_disconnect(rtems_debugger_remote* remote)
0270 {
0271   rtems_debugger_remote_tcp* tcp;
0272 
0273   rtems_debugger_lock();
0274 
0275   rtems_debugger_printf("rtems-db: tcp remote: disconnect host\n");
0276 
0277   tcp = (rtems_debugger_remote_tcp*) remote->data;
0278   close(tcp->fd);
0279   tcp->fd = -1;
0280 
0281   rtems_debugger_unlock();
0282 
0283   return 0;
0284 }
0285 
0286 static bool
0287 tcp_remote_isconnected(rtems_debugger_remote* remote)
0288 {
0289   rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
0290   return tcp != NULL && tcp->fd >= 0;
0291 }
0292 
0293 static ssize_t
0294 tcp_remote_receive(rtems_debugger_remote* remote,
0295                    void*                  buf,
0296                    size_t                 nbytes)
0297 {
0298   rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
0299   ssize_t                    len;
0300   if (tcp != NULL) {
0301     len = read(tcp->fd, buf, nbytes);
0302   }
0303   else {
0304     errno = EIO;
0305     len = -1;
0306   }
0307   return len;
0308 }
0309 
0310 static ssize_t
0311 tcp_remote_send(rtems_debugger_remote* remote,
0312                 const void*            buf,
0313                 size_t                 nbytes)
0314 {
0315   rtems_debugger_remote_tcp* tcp = tcp_remote(remote);
0316   ssize_t                    len;
0317   if (tcp != NULL) {
0318     len = write(tcp->fd, buf, nbytes);
0319   }
0320   else {
0321     errno = EIO;
0322     len = -1;
0323   }
0324   return len;
0325 }
0326 
0327 static rtems_debugger_remote remote_tcp =
0328 {
0329   .name = "tcp",
0330   .begin = tcp_remote_begin,
0331   .end = tcp_remote_end,
0332   .connect = tcp_remote_connect,
0333   .disconnect = tcp_remote_disconnect,
0334   .isconnected = tcp_remote_isconnected,
0335   .read = tcp_remote_receive,
0336   .write = tcp_remote_send
0337 };
0338 
0339 int
0340 rtems_debugger_register_tcp_remote(void)
0341 {
0342   return rtems_debugger_remote_register(&remote_tcp);
0343 }