4 Copyright (C) 2022 by Ludovic Pollet
6 This library is free software;
7 you can redistribute it and / or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation;
11 version 2.1 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT
ANY WARRANTY;
15 without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License
for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with
this library;
21 if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 - 1301 USA
31 #include <sys/types.h>
32 #include <sys/socket.h>
45 #define OUTPUTBUFF_ALLOC 32768
48 #define OUTPUTBUFF_FLUSH_THRESOLD 65536
50 #define MAXFD_PER_MESSAGE 16
52 static void driverio_flush(
driverio * dio,
const void * additional,
size_t add_size);
54 static pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER;
57 static unsigned int outBuffRequired(
unsigned int storage)
62 static int outBuffAllocated(
struct driverio * dio)
64 return outBuffRequired(dio->
outPos);
67 static void outBuffGrow(
struct driverio * dio,
int required)
77 static ssize_t driverio_write(
void *user,
const void * ptr,
size_t count)
83 driverio_flush(dio, ptr, count);
87 unsigned int allocated = outBuffAllocated(dio);
88 unsigned int required = outBuffRequired(dio->
outPos + count);
89 if (required != allocated)
91 outBuffGrow(dio, required);
100 static int driverio_vprintf(
void *
user,
const char * fmt, va_list arg)
106 unsigned int allocated = outBuffAllocated(dio);
109 available = allocated - dio->
outPos;
111 size = vsnprintf(dio->
outBuff + dio->
outPos, available, fmt, arg);
116 if (size < available)
120 allocated = outBuffRequired(available + size + 1);
121 outBuffGrow(dio, allocated);
127 static void driverio_join(
void *
user,
const char * xml,
void * blob,
size_t bloblen)
137 driverio_write(
user, xml, strlen(xml));
141 static void driverio_flush(
driverio * dio,
const void * additional,
size_t add_size)
146 struct cmsghdr * cmsgh;
148 if (dio->
outPos + add_size)
151 void ** temporaryBuffers = NULL;
163 cmsghdrlength = CMSG_SPACE((fdCount *
sizeof(
int)));
164 cmsgh = (
struct cmsghdr*)malloc(cmsghdrlength);
166 temporaryBuffers = (
void**)malloc(
sizeof(
void*)*fdCount);
169 cmsgh->cmsg_len = CMSG_LEN(
sizeof(
int));
170 cmsgh->cmsg_level = SOL_SOCKET;
171 cmsgh->cmsg_type = SCM_RIGHTS;
172 msgh.msg_control = cmsgh;
173 msgh.msg_controllen = cmsghdrlength;
174 for(
int i = 0; i < fdCount; ++i)
176 void * blob = dio->
joins[i];
184 memcpy(temporaryBuffers[i], blob, size);
189 temporaryBuffers[i] = NULL;
192 ((
int *) CMSG_DATA(CMSG_FIRSTHDR(&msgh)))[i] =
fd;
199 msgh.msg_control = cmsgh;
200 msgh.msg_controllen = cmsghdrlength;
203 iov[0].iov_base = dio->
outBuff;
204 iov[0].iov_len = dio->
outPos;
207 iov[1].iov_base = (
void*)additional;
208 iov[1].iov_len = add_size;
212 msgh.msg_name = NULL;
213 msgh.msg_namelen = 0;
215 msgh.msg_iovlen = add_size ? 2 : 1;
219 pthread_mutex_lock(&stdout_mutex);
223 ret = sendmsg(1, &msgh, 0);
230 else if ((
unsigned)ret != dio->
outPos + add_size)
233 fprintf(stderr,
"short write\n");
239 for(
int i = 0; i < fdCount; ++i)
241 if (temporaryBuffers[i] != NULL)
247 free(temporaryBuffers);
251 if (dio->
joins != NULL)
272 static int driverio_is_unix = -1;
274 static int is_unix_io()
276 #ifndef ENABLE_INDI_SHARED_MEMORY
279 if (driverio_is_unix != -1)
281 return driverio_is_unix;
286 socklen_t result =
sizeof(domain);
288 if (getsockopt(1, SOL_SOCKET, SO_DOMAIN, (
void*)&domain, &result) == -1)
290 driverio_is_unix = 0;
292 else if (result !=
sizeof(domain) || domain != AF_UNIX)
294 driverio_is_unix = 0;
298 driverio_is_unix = 1;
301 struct sockaddr_un sockName;
302 socklen_t sockNameLen =
sizeof(sockName);
304 if (getsockname(1, (
struct sockaddr*)&sockName, &sockNameLen) == -1)
306 driverio_is_unix = 0;
308 else if (sockName.sun_family == AF_UNIX)
310 driverio_is_unix = 1;
314 driverio_is_unix = 0;
317 return driverio_is_unix;
321 static void driverio_init_unix(
driverio * dio)
326 dio->
user = (
void*)dio;
335 static void driverio_finish_unix(
driverio * dio)
337 driverio_flush(dio, NULL, 0);
340 pthread_mutex_unlock(&stdout_mutex);
345 static void driverio_init_stdout(
driverio * dio)
349 pthread_mutex_lock(&stdout_mutex);
352 static void driverio_finish_stdout(
driverio * dio)
356 pthread_mutex_unlock(&stdout_mutex);
363 driverio_init_unix(dio);
367 driverio_init_stdout(dio);
375 driverio_finish_unix(dio);
379 driverio_finish_stdout(dio);
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)
void * IDSharedBlobAlloc(size_t size)
int IDSharedBlobGetFd(void *ptr)
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()