From fee1fb8ac40e27e1b517e69e1941b34851bdbf07 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 23 May 2017 12:55:20 -0400 Subject: [PATCH 20/28] Add server.h and server.c This patch adds a "server" abstract base class for listening on a port, for use by the later patches to implement an LSP server. gcc/ChangeLog: * Makefile.in (OBJS): Add server.o. * server.c: New file. * server.h: New file. --- gcc/Makefile.in | 1 + gcc/server.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/server.h | 46 +++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 gcc/server.c create mode 100644 gcc/server.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 77ecbd6..4e60bc0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1454,6 +1454,7 @@ OBJS = \ sel-sched.o \ selftest-rtl.o \ selftest-run-tests.o \ + server.o \ sese.o \ shrink-wrap.o \ simplify-rtx.o \ diff --git a/gcc/server.c b/gcc/server.c new file mode 100644 index 0000000..871a95f --- /dev/null +++ b/gcc/server.c @@ -0,0 +1,152 @@ +/* Abstract server implementation. + Copyright (C) 2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "server.h" + +/* adapted from GNU libc docs. */ +#include +#include +#include +#include +#include + +#define MAXMSG 512 + +static int +make_socket (uint16_t port) +{ + int sock; + struct sockaddr_in name; + + /* Create the socket. */ + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + perror ("socket"); + exit (EXIT_FAILURE); + } + + /* Give the socket a name. */ + name.sin_family = AF_INET; + name.sin_port = htons (port); + name.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) + { + perror ("bind"); + exit (EXIT_FAILURE); + } + + return sock; +} + +/* Serve on PORT. */ + +void +server::serve (int port) +{ + int sock; + fd_set active_fd_set, read_fd_set; + int i; + struct sockaddr_in clientname; + socklen_t size; + + /* Create the socket and set it up to accept connections. */ + sock = make_socket (port); + if (listen (sock, 1) < 0) + { + perror ("listen"); + exit (EXIT_FAILURE); + } + + /* Initialize the set of active sockets. */ + FD_ZERO (&active_fd_set); + FD_SET (sock, &active_fd_set); + + while (1) + { + /* Block until input arrives on one or more active sockets. */ + read_fd_set = active_fd_set; + if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0) + { + perror ("select"); + exit (EXIT_FAILURE); + } + + /* Service all the sockets with input pending. */ + for (i = 0; i < FD_SETSIZE; ++i) + if (FD_ISSET (i, &read_fd_set)) + { + if (i == sock) + { + /* Connection request on original socket. */ + int new_; + size = sizeof (clientname); + new_ = accept (sock, + (struct sockaddr *) &clientname, + &size); + if (new_ < 0) + { + perror ("accept"); + exit (EXIT_FAILURE); + } + fprintf (stderr, + "Server: connect from host %s, port %hd.\n", + inet_ntoa (clientname.sin_addr), + ntohs (clientname.sin_port)); + FD_SET (new_, &active_fd_set); + } + else + { + /* Data arriving on an already-connected socket. */ + if (read_from_client (file_descriptor (i)) < 0) + { + close (i); + FD_CLR (i, &active_fd_set); + } + } + } + } +} + +int +server::read_from_client (file_descriptor fd) +{ + char buffer[MAXMSG]; + int nbytes; + + nbytes = read (fd.m_fd, buffer, MAXMSG); + if (nbytes < 0) + { + /* Read error. */ + perror ("read"); + exit (EXIT_FAILURE); + } + else if (nbytes == 0) + /* End-of-file. */ + return -1; + else + { + /* Data read. */ + on_read (fd, nbytes, buffer); + return 0; + } +} diff --git a/gcc/server.h b/gcc/server.h new file mode 100644 index 0000000..3bcf9f6e --- /dev/null +++ b/gcc/server.h @@ -0,0 +1,46 @@ +/* Abstract server implementation. + Copyright (C) 2017 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_SERVER_H +#define GCC_SERVER_H + +/* Wrapper aroung "int" for file descriptors. */ + +struct file_descriptor +{ + explicit file_descriptor (int fd) : m_fd (fd) {} + + int m_fd; +}; + +/* Abstract base class for implementing a server. */ + +class server +{ + public: + virtual ~server () {} + void serve (int port); + + virtual void on_read (file_descriptor fd, size_t length, const char *buf) = 0; + + private: + int read_from_client (file_descriptor fd); +}; + +#endif /* GCC_SERVER_H */ -- 1.8.5.3