Instrument Neutral Distributed Interface INDI 2.2.5
TcpServer.cpp
Go to the documentation of this file.
1/* INDI Server for protocol version 1.7.
2 * Copyright (C) 2007 Elwood C. Downey <[email protected]>
3 2013 Jasem Mutlaq <[email protected]>
4 2022 Ludovic Pollet
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19#include "TcpServer.hpp"
20#include "Constants.hpp"
21#include "Utils.hpp"
22#include "ClInfo.hpp"
23#include "CommandLineArgs.hpp"
24
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <fcntl.h>
29
30TcpServer::TcpServer(int port): port(port)
31{
32 sfdev.set<TcpServer, &TcpServer::ioCb>(this);
33}
34
35void TcpServer::ioCb(ev::io &, int revents)
36{
37 if (revents & EV_ERROR)
38 {
39 int sockErrno = readFdError(this->sfd);
40 if (sockErrno)
41 {
42 log(fmt("Error on tcp server socket: %s\n", strerror(sockErrno)));
43 Bye();
44 }
45 }
46 if (revents & EV_READ)
47 {
48 accept();
49 }
50}
51
53{
54 struct sockaddr_in serv_socket;
55 int reuse = 1;
56
57 /* make socket endpoint */
58 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
59 {
60 log(fmt("socket: %s\n", strerror(errno)));
61 Bye();
62 }
63
64 /* bind to given port for any IP address */
65 memset(&serv_socket, 0, sizeof(serv_socket));
66 serv_socket.sin_family = AF_INET;
67#ifdef SSH_TUNNEL
68 serv_socket.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
69#else
70 serv_socket.sin_addr.s_addr = htonl(INADDR_ANY);
71#endif
72 serv_socket.sin_port = htons((unsigned short)port);
73 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
74 {
75 log(fmt("setsockopt: %s\n", strerror(errno)));
76 Bye();
77 }
78 if (bind(sfd, (struct sockaddr *)&serv_socket, sizeof(serv_socket)) < 0)
79 {
80 log(fmt("bind: %s\n", strerror(errno)));
81 Bye();
82 }
83
84 /* willing to accept connections with a backlog of 5 pending */
85 if (::listen(sfd, 5) < 0)
86 {
87 log(fmt("listen: %s\n", strerror(errno)));
88 Bye();
89 }
90
91 fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK);
92 sfdev.start(sfd, EV_READ);
93
94 /* ok */
96 log(fmt("listening to port %d on fd %d\n", port, sfd));
97}
98
99void TcpServer::accept()
100{
101 struct sockaddr_in cli_socket;
102 socklen_t cli_len;
103 int cli_fd;
104
105 /* get a private connection to new client */
106 cli_len = sizeof(cli_socket);
107 cli_fd = ::accept(sfd, (struct sockaddr *)&cli_socket, &cli_len);
108 if (cli_fd < 0)
109 {
110 if (errno == EAGAIN || errno == EWOULDBLOCK) return;
111
112 log(fmt("accept: %s\n", strerror(errno)));
113 Bye();
114 }
115
116 ClInfo * cp = new ClInfo(false);
117
118 /* rig up new clinfo entry */
119 cp->setFds(cli_fd, cli_fd);
120
122 {
123 cp->log(fmt("new arrival from %s:%d - welcome!\n",
124 inet_ntoa(cli_socket.sin_addr), ntohs(cli_socket.sin_port)));
125 }
126#ifdef OSX_EMBEDED_MODE
127 fprintf(stderr, "CLIENTS %d\n", clients.size());
128 fflush(stderr);
129#endif
130}
CommandLineArgs * userConfigurableArguments
void log(const std::string &log)
Definition Utils.cpp:161
std::string fmt(const char *fmt,...)
Definition Utils.cpp:241
void Bye()
Definition Utils.cpp:108
int readFdError(int fd)
Definition Utils.cpp:167
virtual void log(const std::string &log) const
Definition ClInfo.cpp:320
void setFds(int rFd, int wFd)
Definition MsgQueue.cpp:284
void listen()
Definition TcpServer.cpp:52
TcpServer(int port)
Definition TcpServer.cpp:30
int errno