Instrument Neutral Distributed Interface INDI 2.2.5
Utils.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
20#include "Utils.hpp"
21#include "Constants.hpp"
22#include "CommandLineArgs.hpp"
23
24#include <cstring>
25#include <csignal>
26#include <cstdarg>
27#include <ctime>
28#include <unistd.h>
29#include <sys/stat.h>
30#include <sys/mman.h>
31
32/* record we have started and our args */
33void logStartup(int ac, char *av[])
34{
35 int i;
36
37 std::string startupMsg = "startup:";
38 for (i = 0; i < ac; i++)
39 {
40 startupMsg += " ";
41 startupMsg += av[i];
42 }
43 startupMsg += '\n';
44 log(startupMsg);
45}
46
47/* turn off SIGPIPE on bad write so we can handle it inline */
49{
50 struct sigaction sa;
51 memset(&sa, 0, sizeof(sa));
52 sa.sa_handler = SIG_IGN;
53 sigemptyset(&sa.sa_mask);
54 (void)sigaction(SIGPIPE, &sa, NULL);
55}
56
57/* fill s with current UT string.
58* if no s, use a static buffer
59* return s or buffer.
60* N.B. if use our buffer, be sure to use before calling again
61*/
62char *indi_tstamp(char *s)
63{
64 static char sbuf[64];
65 struct tm *tp;
66 time_t t;
67
68 time(&t);
69 tp = gmtime(&t);
70 if (!s)
71 s = sbuf;
72 strftime(s, sizeof(sbuf), "%Y-%m-%dT%H:%M:%S", tp);
73 return (s);
74}
75
76/* log message in root known to be from device dev to loggingDir, if any.
77*/
78void logDMsg(XMLEle *root, const char *dev)
79{
80 char stamp[64];
81 char logfn[1024];
82 const char *ts, *ms;
83 FILE *fp;
84
85 /* get message, if any */
86 ms = findXMLAttValu(root, "message");
87 if (!ms[0])
88 return;
89
90 /* get timestamp now if not provided */
91 ts = findXMLAttValu(root, "timestamp");
92 if (!ts[0])
93 {
94 indi_tstamp(stamp);
95 ts = stamp;
96 }
97
98 /* append to log file, name is date portion of time stamp */
99 sprintf(logfn, "%s/%.10s.islog", userConfigurableArguments->loggingDir, ts);
100 fp = fopen(logfn, "a");
101 if (!fp)
102 return; /* oh well */
103 fprintf(fp, "%s: %s: %s\n", ts, dev, ms);
104 fclose(fp);
105}
106
107/* log when then exit */
108void Bye()
109{
110 fprintf(stderr, "%s: good bye\n", indi_tstamp(NULL));
111 exit(1);
112}
113
114bool parseBlobSize(XMLEle * blobWithAttachedBuffer, ssize_t &size)
115{
116 std::string sizeStr = findXMLAttValu(blobWithAttachedBuffer, "size");
117 if (sizeStr == "")
118 {
119 return false;
120 }
121 size_t pos;
122 size = std::stoll(sizeStr, &pos, 10);
123 if (pos != sizeStr.size())
124 {
125 log("Invalid size attribute value " + sizeStr);
126 return false;
127 }
128 return true;
129}
130
131int xmlReplacementMapFind(void * self, XMLEle * source, XMLEle * * replace)
132{
133 auto map = (const std::unordered_map<XMLEle*, XMLEle*> *) self;
134 auto idx = map->find(source);
135 if (idx == map->end())
136 {
137 return 0;
138 }
139 *replace = (XMLEle*)idx->second;
140 return 1;
141}
142
143XMLEle * cloneXMLEleWithReplacementMap(XMLEle * root, const std::unordered_map<XMLEle*, XMLEle*> &replacement)
144{
145 return cloneXMLEle(root, &xmlReplacementMapFind, (void*)&replacement);
146}
147
148std::vector<XMLEle *> findBlobElements(XMLEle * root)
149{
150 std::vector<XMLEle *> result;
151 for (auto ep = nextXMLEle(root, 1); ep; ep = nextXMLEle(root, 0))
152 {
153 if (strcmp(tagXMLEle(ep), "oneBLOB") == 0)
154 {
155 result.push_back(ep);
156 }
157 }
158 return result;
159}
160
161void log(const std::string &log)
162{
163 fprintf(stderr, "%s: ", indi_tstamp(NULL));
164 fprintf(stderr, "%s", log.c_str());
165}
166
168{
169#ifdef MSG_ERRQUEUE
170 char rcvbuf[128]; /* Buffer for normal data (not expected here...) */
171 char cbuf[512]; /* Buffer for ancillary data (errors) */
172 struct iovec iov;
173 struct msghdr msg;
174
175 iov.iov_base = &rcvbuf;
176 iov.iov_len = sizeof(rcvbuf);
177
178 msg.msg_name = nullptr;
179 msg.msg_namelen = 0;
180 msg.msg_iov = &iov;
181 msg.msg_iovlen = 1;
182 msg.msg_flags = 0;
183 msg.msg_control = cbuf;
184 msg.msg_controllen = sizeof(cbuf);
185
186 int recv_bytes = recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
187 if (recv_bytes == -1)
188 {
189 if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
190 return errno;
191 }
192
193 /* Receive auxiliary data in msgh */
194 for (struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
195 {
196 fprintf(stderr, "cmsg_len=%zu, cmsg_level=%u, cmsg_type=%u\n", cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type);
197
198 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
199 {
200 return ((struct sock_extended_err *)CMSG_DATA(cmsg))->ee_errno;
201 }
202 }
203#else
204 (void)fd;
205#endif
206
207 // Default to EIO as a generic error path
208 return EIO;
209}
210
211void * attachSharedBuffer(int fd, size_t &size)
212{
213 struct stat sb;
214 if (fstat(fd, &sb) == -1)
215 {
216 perror("invalid shared buffer fd");
217 Bye();
218 }
219 size = sb.st_size;
220 void * ret = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
221
222 if (ret == MAP_FAILED)
223 {
224 perror("mmap");
225 Bye();
226 }
227
228 return ret;
229}
230
231void dettachSharedBuffer(int fd, void * ptr, size_t size)
232{
233 (void)fd;
234 if (munmap(ptr, size) == -1)
235 {
236 perror("shared buffer munmap");
237 Bye();
238 }
239}
240
241std::string fmt(const char *fmt, ...)
242{
243 char buffer[128];
244 int size = sizeof(buffer);
245 char *p = buffer;
246 va_list ap;
247
248 /* Determine required size */
249 va_start(ap, fmt);
250 size = vsnprintf(p, size, fmt, ap);
251 va_end(ap);
252
253 if (size < 0)
254 {
255 perror("vnsprintf");
256 }
257
258 if ((unsigned)size < sizeof(buffer))
259 {
260 return std::string(buffer);
261 }
262
263 size++; /* For '\0' */
264 p = (char*)malloc(size);
265 if (p == NULL)
266 {
267 perror("malloc");
268 Bye();
269 }
270
271 va_start(ap, fmt);
272 size = vsnprintf(p, size, fmt, ap);
273 va_end(ap);
274
275 if (size < 0)
276 {
277 free(p);
278 perror("vnsprintf");
279 }
280 std::string ret(p);
281 free(p);
282 return ret;
283}
CommandLineArgs * userConfigurableArguments
void log(const std::string &log)
Definition Utils.cpp:161
void logDMsg(XMLEle *root, const char *dev)
Definition Utils.cpp:78
XMLEle * cloneXMLEleWithReplacementMap(XMLEle *root, const std::unordered_map< XMLEle *, XMLEle * > &replacement)
Definition Utils.cpp:143
bool parseBlobSize(XMLEle *blobWithAttachedBuffer, ssize_t &size)
Definition Utils.cpp:114
std::string fmt(const char *fmt,...)
Definition Utils.cpp:241
char * indi_tstamp(char *s)
Definition Utils.cpp:62
std::vector< XMLEle * > findBlobElements(XMLEle *root)
Definition Utils.cpp:148
int xmlReplacementMapFind(void *self, XMLEle *source, XMLEle **replace)
Definition Utils.cpp:131
void dettachSharedBuffer(int fd, void *ptr, size_t size)
Definition Utils.cpp:231
void Bye()
Definition Utils.cpp:108
int readFdError(int fd)
Definition Utils.cpp:167
void noSIGPIPE()
Definition Utils.cpp:48
void logStartup(int ac, char *av[])
Definition Utils.cpp:33
void * attachSharedBuffer(int fd, size_t &size)
Definition Utils.cpp:211
int errno
int fd
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition lilxml.cpp:644
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition lilxml.cpp:555
char * tagXMLEle(XMLEle *ep)
Return the tag of an XML element.
Definition lilxml.cpp:600
XMLEle * cloneXMLEle(XMLEle *ep)
Definition lilxml.cpp:479