4Copyright (C) 2022 by Ludovic Pollet
6This library is free software;
7you can redistribute it and / or
8modify it under the terms of the GNU Lesser General Public
9License as published by the Free Software Foundation;
11version 2.1 of the License, or (at your option) any later version.
13This library is distributed in the hope that it will be useful,
14 but WITHOUT
ANY WARRANTY;
15without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17Lesser General Public License
for more details.
19You should have received a copy of the GNU Lesser General Public
20License along with
this library;
21if not, write to the Free Software
22Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
32#include <sys/socket.h>
46#define OUTPUTBUFF_ALLOC 32768
49#define OUTPUTBUFF_FLUSH_THRESOLD 65536
51#define MAXFD_PER_MESSAGE 16
53static void driverio_flush(
driverio * dio,
const void * additional,
size_t add_size);
55static pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
58static unsigned int outBuffRequired(
unsigned int storage)
63static int outBuffAllocated(
struct driverio * dio)
65 return outBuffRequired(dio->
outPos);
68static void outBuffGrow(
struct driverio * dio,
int required)
78static ssize_t driverio_write(
void *user,
const void * ptr,
size_t count)
84 driverio_flush(dio, ptr, count);
88 unsigned int allocated = outBuffAllocated(dio);
89 unsigned int required = outBuffRequired(dio->
outPos + count);
90 if (required != allocated)
92 outBuffGrow(dio, required);
101static int driverio_vprintf(
void *
user,
const char *
fmt, va_list arg)
107 unsigned int allocated = outBuffAllocated(dio);
110 available = allocated - dio->
outPos;
117 if (size < available)
121 allocated = outBuffRequired(available + size + 1);
122 outBuffGrow(dio, allocated);
128static void driverio_join(
void *
user,
const char * xml,
void * blob,
size_t bloblen)
138 driverio_write(
user, xml, strlen(xml));
142static void driverio_flush(
driverio * dio,
const void * additional,
size_t add_size)
147 struct cmsghdr * cmsgh;
149 if (dio->
outPos + add_size)
152 void ** temporaryBuffers = NULL;
164 cmsghdrlength = CMSG_SPACE((fdCount *
sizeof(
int)));
165 cmsgh = (
struct cmsghdr*)malloc(cmsghdrlength);
167 temporaryBuffers = (
void**)malloc(
sizeof(
void*)*fdCount);
170 cmsgh->cmsg_len = CMSG_LEN(
sizeof(
int));
171 cmsgh->cmsg_level = SOL_SOCKET;
172 cmsgh->cmsg_type = SCM_RIGHTS;
173 msgh.msg_control = cmsgh;
174 msgh.msg_controllen = cmsghdrlength;
175 for(
int i = 0; i < fdCount; ++i)
177 void * blob = dio->
joins[i];
185 memcpy(temporaryBuffers[i], blob, size);
190 temporaryBuffers[i] = NULL;
193 ((
int *) CMSG_DATA(CMSG_FIRSTHDR(&msgh)))[i] =
fd;
200 msgh.msg_control = cmsgh;
201 msgh.msg_controllen = cmsghdrlength;
204 iov[0].iov_base = dio->
outBuff;
205 iov[0].iov_len = dio->
outPos;
208 iov[1].iov_base = (
void*)additional;
209 iov[1].iov_len = add_size;
213 msgh.msg_name = NULL;
214 msgh.msg_namelen = 0;
216 msgh.msg_iovlen = add_size ? 2 : 1;
220 pthread_mutex_lock(&stdout_mutex);
224 ret = sendmsg(1, &msgh, 0);
231 else if ((
unsigned)ret != dio->
outPos + add_size)
234 fprintf(stderr,
"short write\n");
240 for(
int i = 0; i < fdCount; ++i)
242 if (temporaryBuffers[i] != NULL)
248 free(temporaryBuffers);
252 if (dio->
joins != NULL)
273static int driverio_is_unix = -1;
275static int is_unix_io()
277#ifndef ENABLE_INDI_SHARED_MEMORY
280 if (driverio_is_unix != -1)
282 return driverio_is_unix;
287 socklen_t result =
sizeof(domain);
289 if (getsockopt(1, SOL_SOCKET, SO_DOMAIN, (
void*)&domain, &result) == -1)
291 driverio_is_unix = 0;
293 else if (result !=
sizeof(domain) || domain != AF_UNIX)
295 driverio_is_unix = 0;
299 driverio_is_unix = 1;
302 struct sockaddr_un sockName;
303 socklen_t sockNameLen =
sizeof(sockName);
305 if (getsockname(1, (
struct sockaddr*)&sockName, &sockNameLen) == -1)
307 driverio_is_unix = 0;
309 else if (sockName.sun_family == AF_UNIX)
311 driverio_is_unix = 1;
315 driverio_is_unix = 0;
318 return driverio_is_unix;
322static void driverio_init_unix(
driverio * dio)
327 dio->
user = (
void*)dio;
333 pthread_mutex_lock(&stdout_mutex);
337static void driverio_finish_unix(
driverio * dio)
339 driverio_flush(dio, NULL, 0);
342 pthread_mutex_unlock(&stdout_mutex);
347static void driverio_init_stdout(
driverio * dio)
351 pthread_mutex_lock(&stdout_mutex);
354static void driverio_finish_stdout(
driverio * dio)
358 pthread_mutex_unlock(&stdout_mutex);
365 driverio_init_unix(dio);
369 driverio_init_stdout(dio);
377 driverio_finish_unix(dio);
381 driverio_finish_stdout(dio);
std::string fmt(const char *fmt,...)
void driverio_init(driverio *dio)
#define OUTPUTBUFF_FLUSH_THRESOLD
void driverio_finish(driverio *dio)
#define MAXFD_PER_MESSAGE
Namespace to encapsulate INDI client, drivers, and mediator classes.
void IDSharedBlobFree(void *ptr)
Free a buffer allocated using IDSharedBlobAlloc. Fall back to free for buffer that are not shared blo...
void * IDSharedBlobAlloc(size_t size)
Allocate a buffer suitable for fast exchange over local links. Warning : the buffer will be sealed (r...
int IDSharedBlobGetFd(void *ptr)
Return the filedescriptor backing up the given shared buffer.
void(* joinbuff)(void *user, const char *xml, void *buffer, size_t bloblen)
int(* vprintf)(void *user, const char *format, va_list arg)
ssize_t(* write)(void *user, const void *ptr, size_t count)
const struct userio * userio_file()