Instrument Neutral Distributed Interface INDI 2.2.5
Fifo.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 "Fifo.hpp"
20#include "Utils.hpp"
21#include "Constants.hpp"
22#include "DvrInfo.hpp"
23#include "LocalDrvInfo.hpp"
24#include "RemoteDvrInfo.hpp"
25#include "CommandLineArgs.hpp"
26
27#include <fcntl.h>
28#include <unistd.h>
29
30using namespace indiserver::constants;
31
32Fifo::Fifo(const std::string &name) : name(name)
33{
34 fdev.set<Fifo, &Fifo::ioCb>(this);
35}
36
37/* Attempt to open up FIFO */
38void Fifo::close(void)
39{
40 if (fd != -1)
41 {
42 ::close(fd);
43 fd = -1;
44 fdev.stop();
45 }
46 bufferPos = 0;
47}
48
49void Fifo::open()
50{
51 /* Open up FIFO, if available */
52 fd = ::open(name.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
53
54 if (fd < 0)
55 {
56 log(fmt("open(%s): %s.\n", name.c_str(), strerror(errno)));
57 Bye();
58 }
59
60 fdev.start(fd, EV_READ);
61}
62
63
64/* Handle one fifo command. Start/stop drivers accordingly */
65void Fifo::processLine(const char * line)
66{
67
69 log(fmt("FIFO: %s\n", line));
70
72 char arg[4][1];
73 char var[4][maxStringBufferLength];
74
75 char tDriver[maxStringBufferLength];
76 memset(&tDriver[0], 0, sizeof(char) * maxStringBufferLength);
77
78 char tName[maxStringBufferLength];
79 memset(&tName[0], 0, sizeof(char) * maxStringBufferLength);
80
81 char envConfig[maxStringBufferLength];
82 memset(&envConfig[0], 0, sizeof(char) * maxStringBufferLength);
83
84 char envSkel[maxStringBufferLength];
85 memset(&envSkel[0], 0, sizeof(char) * maxStringBufferLength);
86
87 char envPrefix[maxStringBufferLength];
88 memset(&envPrefix[0], 0, sizeof(char) * maxStringBufferLength);
89
90
91 int n = 0;
92
93 bool remoteDriver = !!strstr(line, "@");
94
95 // If remote driver
96 if (remoteDriver)
97 {
98 n = sscanf(line, "%s %511[^\n]", cmd, tDriver);
99
100 // Remove quotes if any
101 char *ptr = tDriver;
102 int len = strlen(tDriver);
103 while ((ptr = strstr(tDriver, "\"")))
104 {
105 memmove(ptr, ptr + 1, --len);
106 ptr[len] = '\0';
107 }
108 }
109 // If local driver
110 else
111 {
112 n = sscanf(line, "%s %s -%1c \"%511[^\"]\" -%1c \"%511[^\"]\" -%1c \"%511[^\"]\" -%1c \"%511[^\"]\"", cmd,
113 tDriver, arg[0], var[0], arg[1], var[1], arg[2], var[2], arg[3], var[3]);
114 }
115
116 int n_args = (n - 2) / 2;
117
118 int j = 0;
119 for (j = 0; j < n_args; j++)
120 {
121 if (arg[j][0] == 'n')
122 {
123 strncpy(tName, var[j], maxStringBufferLength - 1);
124 tName[maxStringBufferLength - 1] = '\0';
125
127 log(fmt("With name: %s\n", tName));
128 }
129 else if (arg[j][0] == 'c')
130 {
131 strncpy(envConfig, var[j], maxStringBufferLength - 1);
132 envConfig[maxStringBufferLength - 1] = '\0';
133
135 log(fmt("With config: %s\n", envConfig));
136 }
137 else if (arg[j][0] == 's')
138 {
139 strncpy(envSkel, var[j], maxStringBufferLength - 1);
140 envSkel[maxStringBufferLength - 1] = '\0';
141
143 log(fmt("With skeketon: %s\n", envSkel));
144 }
145 else if (arg[j][0] == 'p')
146 {
147 strncpy(envPrefix, var[j], maxStringBufferLength - 1);
148 envPrefix[maxStringBufferLength - 1] = '\0';
149
151 log(fmt("With prefix: %s\n", envPrefix));
152 }
153 }
154
155 bool startCmd;
156 if (!strcmp(cmd, "start"))
157 startCmd = 1;
158 else
159 startCmd = 0;
160
161 if (startCmd)
162 {
164 log(fmt("FIFO: Starting driver %s\n", tDriver));
165
166 DvrInfo * dp;
167 if (remoteDriver == 0)
168 {
169 auto * localDp = new LocalDvrInfo();
170 dp = localDp;
171 //strncpy(dp->dev, tName, MAXINDIDEVICE);
172 localDp->envDev = tName;
173 localDp->envConfig = envConfig;
174 localDp->envSkel = envSkel;
175 localDp->envPrefix = envPrefix;
176 }
177 else
178 {
179 dp = new RemoteDvrInfo();
180 }
181 dp->name = tDriver;
182 dp->start();
183 }
184 else
185 {
186 for (auto dp : DvrInfo::drivers)
187 {
188 if (dp == nullptr) continue;
189
190 if (dp->name == tDriver)
191 {
192 /* If device name is given, check against it before shutting down */
193 if (tName[0] && !dp->isHandlingDevice(tName))
194 continue;
196 log(fmt("FIFO: Shutting down driver: %s\n", tDriver));
197
198 dp->restart = false;
199 dp->close();
200 break;
201 }
202 }
203 }
204}
205
206void Fifo::read(void)
207{
208 int rd = ::read(fd, buffer + bufferPos, sizeof(buffer) - 1 - bufferPos);
209 if (rd == 0)
210 {
211 if (bufferPos > 0)
212 {
213 buffer[bufferPos] = '\0';
214 processLine(buffer);
215 }
216 close();
217 open();
218 return;
219 }
220 if (rd == -1)
221 {
222 if (errno == EAGAIN || errno == EWOULDBLOCK) return;
223
224 log(fmt("Fifo error: %s\n", strerror(errno)));
225 close();
226 open();
227 return;
228 }
229
230 bufferPos += rd;
231
232 for(int i = 0; i < bufferPos; ++i)
233 {
234 if (buffer[i] == '\n')
235 {
236 buffer[i] = 0;
237 processLine(buffer);
238 // shift the buffer
239 i++; /* count including nl */
240 bufferPos -= i; /* remove from nexbuf */
241 memmove(buffer, buffer + i, bufferPos); /* slide remaining to front */
242 i = -1; /* restart for loop scan */
243 }
244 }
245
246 if ((unsigned)bufferPos >= sizeof(buffer) - 1)
247 {
248 log(fmt("Fifo overflow"));
249 close();
250 open();
251 }
252}
253
254void Fifo::ioCb(ev::io &, int revents)
255{
256 if (EV_ERROR & revents)
257 {
258 int sockErrno = readFdError(this->fd);
259 if (sockErrno)
260 {
261 log(fmt("Error on fifo: %s\n", strerror(sockErrno)));
262 close();
263 open();
264 }
265 }
266 else if (revents & EV_READ)
267 {
268 read();
269 }
270}
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
bool restart
Definition DvrInfo.hpp:62
bool isHandlingDevice(const std::string &dev) const
Definition DvrInfo.cpp:315
virtual void start()=0
std::string name
Definition DvrInfo.hpp:57
void close() override
Definition DvrInfo.cpp:124
Definition Fifo.hpp:25
Fifo(const std::string &name)
Definition Fifo.cpp:32
int errno
constexpr unsigned maxStringBufferLength
Definition Constants.hpp:24
uint8_t cmd[4]
Definition pwc-ioctl.h:2