Instrument Neutral Distributed Interface INDI 2.2.5
UnixServer.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 "UnixServer.hpp"
20#include "Utils.hpp"
21#include "Constants.hpp"
22#include "ClInfo.hpp"
23#include "CommandLineArgs.hpp"
24
25#include <sys/un.h>
26#include <sys/socket.h>
27#include <fcntl.h>
28#include <unistd.h>
29#ifdef ENABLE_INDI_SHARED_MEMORY
30
31std::string UnixServer::unixSocketPath = INDIUNIXSOCK;
32
33UnixServer::UnixServer(const std::string &path): path(path)
34{
35 sfdev.set<UnixServer, &UnixServer::ioCb>(this);
36}
37
38void UnixServer::log(const std::string &str) const
39{
40 std::string logLine = "Local server: ";
41 logLine += str;
42 ::log(logLine);
43}
44
45void UnixServer::ioCb(ev::io &, int revents)
46{
47 if (revents & EV_ERROR)
48 {
49 int sockErrno = readFdError(this->sfd);
50 if (sockErrno)
51 {
52 log(fmt("Error on unix socket: %s\n", strerror(sockErrno)));
53 Bye();
54 }
55 }
56 if (revents & EV_READ)
57 {
58 accept();
59 }
60}
61
62void initUnixSocketAddr(const std::string &unixAddr, struct sockaddr_un &serv_addr_un, socklen_t &addrlen, bool bind)
63{
64 memset(&serv_addr_un, 0, sizeof(serv_addr_un));
65 serv_addr_un.sun_family = AF_UNIX;
66
67#ifdef __linux__
68 (void) bind;
69
70 // Using abstract socket path to avoid filesystem boilerplate
71 strncpy(serv_addr_un.sun_path + 1, unixAddr.c_str(), sizeof(serv_addr_un.sun_path) - 2);
72
73 int len = offsetof(struct sockaddr_un, sun_path) + unixAddr.size() + 1;
74
75 addrlen = len;
76#else
77 // Using filesystem socket path
78 strncpy(serv_addr_un.sun_path, unixAddr.c_str(), sizeof(serv_addr_un.sun_path) - 1);
79
80 int len = offsetof(struct sockaddr_un, sun_path) + unixAddr.size();
81
82 if (bind)
83 {
84 unlink(unixAddr.c_str());
85 }
86#endif
87 addrlen = len;
88}
89
90void UnixServer::listen()
91{
92 struct sockaddr_un serv_socket;
93
94 /* make socket endpoint */
95 if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
96 {
97 log(fmt("socket: %s\n", strerror(errno)));
98 Bye();
99 }
100
101 int reuse = 1;
102 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
103 {
104 log(fmt("setsockopt: %s\n", strerror(errno)));
105 Bye();
106 }
107
108 /* bind to given path as unix address */
109 socklen_t len;
110 initUnixSocketAddr(path, serv_socket, len, true);
111
112 if (bind(sfd, (struct sockaddr *)&serv_socket, len) < 0)
113 {
114 log(fmt("bind: %s\n", strerror(errno)));
115 Bye();
116 }
117
118 /* willing to accept connections with a backlog of 5 pending */
119 if (::listen(sfd, 5) < 0)
120 {
121 log(fmt("listen: %s\n", strerror(errno)));
122 Bye();
123 }
124
125 fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK);
126 sfdev.start(sfd, EV_READ);
127
128 /* ok */
130 log(fmt("listening on local domain at: @%s\n", path.c_str()));
131}
132
133void UnixServer::accept()
134{
135 int cli_fd;
136
137 /* get a private connection to new client */
138 cli_fd = ::accept(sfd, 0, 0);
139 if (cli_fd < 0)
140 {
141 if (errno == EAGAIN || errno == EWOULDBLOCK) return;
142
143 log(fmt("accept: %s\n", strerror(errno)));
144 Bye();
145 }
146
147 ClInfo * cp = new ClInfo(true);
148
149 /* rig up new clinfo entry */
150 cp->setFds(cli_fd, cli_fd);
151
153 {
154#ifdef SO_PEERCRED
155#ifdef __OpenBSD__
156 struct sockpeercred ucred;
157 socklen_t len = sizeof(struct sockpeercred);
158#else
159 struct ucred ucred;
160 socklen_t len = sizeof(struct ucred);
161#endif
162
163 if (getsockopt(cli_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
164 {
165 log(fmt("getsockopt failed: %s\n", strerror(errno)));
166 Bye();
167 }
168
169 cp->log(fmt("new arrival from local pid %ld (user: %ld:%ld) - welcome!\n", (long)ucred.pid, (long)ucred.uid,
170 (long)ucred.gid));
171#else
172 cp->log(fmt("new arrival from local domain - welcome!\n"));
173#endif
174 }
175
176#ifdef OSX_EMBEDED_MODE
177 fprintf(stderr, "CLIENTS %d\n", clients.size());
178 fflush(stderr);
179#endif
180}
181
182#endif // ENABLE_INDI_SHARED_MEMORY
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
int errno