Merge ~info-martin-konrad/epics-base:fix-log-issues into ~epics-core/epics-base/+git/epics-base:3.15

Proposed by Martin Konrad
Status: Merged
Approved by: Andrew Johnson
Approved revision: e6914f3b8089a417c9efc31940906854be182e6b
Merged at revision: 9df39475cd70ac8449cbc4406c08766fc8d9c0cc
Proposed branch: ~info-martin-konrad/epics-base:fix-log-issues
Merge into: ~epics-core/epics-base/+git/epics-base:3.15
Diff against target: 708 lines (+238/-153)
11 files modified
src/ioc/misc/dbCore.dbd (+3/-0)
src/libCom/log/iocLog.c (+25/-0)
src/libCom/log/logClient.c (+103/-152)
src/libCom/log/logClient.h (+0/-1)
src/libCom/osi/Makefile (+1/-0)
src/libCom/osi/os/Darwin/osdSockUnsentCount.c (+19/-0)
src/libCom/osi/os/Linux/osdSockUnsentCount.c (+19/-0)
src/libCom/osi/os/WIN32/osdSockUnsentCount.c (+26/-0)
src/libCom/osi/os/default/osdSockUnsentCount.c (+15/-0)
src/libCom/osi/os/iOS/osdSockUnsentCount.c (+19/-0)
src/libCom/osi/osiSock.h (+8/-0)
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
mdavidsaver Approve
Review via email: mp+375509@code.launchpad.net

Description of the change

Fix lp:1841608 + some other logging issues (cherry-picked from 7.0 branch).

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

appveyor test build fails, looks like a missing header. I recall seeing this before, so maybe a missing patch.

https://ci.appveyor.com/project/mdavidsaver/epics-base/builds/30809445/job/g7ql4ckj825c4sqm

Revision history for this message
Freddie Akeroyd (freddie-akeroyd) wrote :

I think the header is there, two possibilities:

The function wasn't available in original W10 so may need to check windows DDK version too i.e. add

#if NTDDI_VERSION >= NTDDI_WIN10_RS2

to the other macro checks.

The failed build is also an old Visual Studio, maybe the option isn't enabled in the MS header for that old a VC? If so then there would need to be a check on the value of the _MSC_VER macro too.

Revision history for this message
Freddie Akeroyd (freddie-akeroyd) wrote :

Or maybe just

#ifdef SIO_TCP_INFO

which might cover MinGW too

Revision history for this message
Andrew Johnson (anj) wrote :

My MinGW cross-build fails on RHEL-7.6, gcc version 4.9.3 20150626 (Fedora MinGW 4.9.3-1.el7):

../osi/os/WIN32/osdSockUnsentCount.c: In function 'epicsSocketUnsentCount':
../osi/os/WIN32/osdSockUnsentCount.c:19:5: error: unknown type name 'TCP_INFO_v0'
     TCP_INFO_v0 tcpInfo;
     ^
../osi/os/WIN32/osdSockUnsentCount.c:21:34: error: 'SIO_TCP_INFO' undeclared (first use in this function)
     if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion),
                                  ^
../osi/os/WIN32/osdSockUnsentCount.c:21:34: note: each undeclared identifier is reported only once for each function it appears in
../osi/os/WIN32/osdSockUnsentCount.c:23:23: error: request for member 'BytesInFlight' in something not a structure or union
         return tcpInfo.BytesInFlight;
                       ^
../osi/os/WIN32/osdSockUnsentCount.c:20:9: warning: variable 'status' set but not used [-Wunused-but-set-variable]
     int status;
         ^

review: Needs Fixing
Revision history for this message
Freddie Akeroyd (freddie-akeroyd) wrote :

I guess it gets compiled on MinGW as neither macro is defined and 0 >= 0 It may be simplest to use

#if defined(_WIN32) && defined(SIO_TCP_INFO)

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Sorry for the vague comment. It was 10 min. before I left for the airport. I think it will be sufficient to pick 5e6226e595975753f3f7a256982c0d77f6643394 as well. Please do a CI test run travis+appveyor to confirm.

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

Thanks Michael for the hint, I added this commit to my branch.

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

I need some help with AppVeyor. My builds keep failing due to some CI issue: https://ci.appveyor.com/project/MartinKonrad/epics-base-github/build/job/iotr6sf955irn1gh I guess something must be wrong with my AppVeyor configuration.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Have you somehow changed the default image? It seems to be 2019, however the assumed default is 2015 (the default default).

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

AppVeyor build succeeded: https://ci.appveyor.com/project/MartinKonrad/epics-base/builds/32153795 Ready for final review.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

That's enough for me.

review: Approve
Revision history for this message
Andrew Johnson (anj) wrote :

Merging.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd
2index 9d5ae94..898bb59 100644
3--- a/src/ioc/misc/dbCore.dbd
4+++ b/src/ioc/misc/dbCore.dbd
5@@ -25,3 +25,6 @@ variable(callbackParallelThreadsDefault,int)
6
7 # Real-time operation
8 variable(dbThreadRealtimeLock,int)
9+
10+# show logClient network activity
11+variable(logClientDebug,int)
12diff --git a/src/libCom/log/iocLog.c b/src/libCom/log/iocLog.c
13index e62da20..ba78041 100644
14--- a/src/libCom/log/iocLog.c
15+++ b/src/libCom/log/iocLog.c
16@@ -18,8 +18,10 @@
17
18 #define epicsExportSharedSymbols
19 #include "envDefs.h"
20+#include "errlog.h"
21 #include "logClient.h"
22 #include "iocLog.h"
23+#include "epicsExit.h"
24
25 int iocLogDisable = 0;
26
27@@ -75,6 +77,24 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void)
28 }
29
30 /*
31+ * logClientSendMessage ()
32+ */
33+static void logClientSendMessage ( logClientId id, const char * message )
34+{
35+ if ( !iocLogDisable ) {
36+ logClientSend (id, message);
37+ }
38+}
39+
40+/*
41+ * iocLogClientDestroy()
42+ */
43+static void iocLogClientDestroy (logClientId id)
44+{
45+ errlogRemoveListeners (logClientSendMessage, id);
46+}
47+
48+/*
49 * iocLogClientInit()
50 */
51 static logClientId iocLogClientInit (void)
52@@ -89,6 +109,10 @@ static logClientId iocLogClientInit (void)
53 return NULL;
54 }
55 id = logClientCreate (addr, port);
56+ if (id != NULL) {
57+ errlogAddListener (logClientSendMessage, id);
58+ epicsAtExit (iocLogClientDestroy, id);
59+ }
60 return id;
61 }
62
63@@ -135,3 +159,4 @@ logClientId epicsShareAPI logClientInit (void)
64 {
65 return iocLogClientInit ();
66 }
67+
68diff --git a/src/libCom/log/logClient.c b/src/libCom/log/logClient.c
69index 99ee671..9a09ef7 100644
70--- a/src/libCom/log/logClient.c
71+++ b/src/libCom/log/logClient.c
72@@ -21,11 +21,11 @@
73 #include <string.h>
74 #include <stdio.h>
75
76+#define EPICS_PRIVATE_API
77 #define epicsExportSharedSymbols
78 #include "dbDefs.h"
79 #include "epicsEvent.h"
80 #include "iocLog.h"
81-#include "errlog.h"
82 #include "epicsMutex.h"
83 #include "epicsThread.h"
84 #include "epicsTime.h"
85@@ -33,9 +33,13 @@
86 #include "epicsAssert.h"
87 #include "epicsExit.h"
88 #include "epicsSignal.h"
89+#include "epicsExport.h"
90
91 #include "logClient.h"
92
93+int logClientDebug = 0;
94+epicsExportAddress (int, logClientDebug);
95+
96 typedef struct {
97 char msgBuf[0x4000];
98 struct sockaddr_in addr;
99@@ -44,8 +48,10 @@ typedef struct {
100 SOCKET sock;
101 epicsThreadId restartThreadId;
102 epicsEventId stateChangeNotify;
103+ epicsEventId shutdownNotify;
104 unsigned connectCount;
105 unsigned nextMsgIndex;
106+ unsigned backlog;
107 unsigned connected;
108 unsigned shutdown;
109 unsigned shutdownConfirm;
110@@ -53,7 +59,6 @@ typedef struct {
111 } logClient;
112
113 static const double LOG_RESTART_DELAY = 5.0; /* sec */
114-static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */
115 static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */
116
117 /*
118@@ -66,10 +71,10 @@ static char* logClientPrefix = NULL;
119 */
120 static void logClientClose ( logClient *pClient )
121 {
122-# ifdef DEBUG
123+ if (logClientDebug) {
124 fprintf (stderr, "log client: lingering for connection close...");
125 fflush (stderr);
126-# endif
127+ }
128
129 /*
130 * mutex on
131@@ -84,8 +89,6 @@ static void logClientClose ( logClient *pClient )
132 pClient->sock = INVALID_SOCKET;
133 }
134
135- pClient->nextMsgIndex = 0u;
136- memset ( pClient->msgBuf, '\0', sizeof ( pClient->msgBuf ) );
137 pClient->connected = 0u;
138
139 /*
140@@ -93,9 +96,8 @@ static void logClientClose ( logClient *pClient )
141 */
142 epicsMutexUnlock (pClient->mutex);
143
144-# ifdef DEBUG
145+ if (logClientDebug)
146 fprintf (stderr, "done\n");
147-# endif
148 }
149
150 /*
151@@ -113,6 +115,7 @@ static void logClientDestroy (logClientId id)
152 epicsMutexMustLock ( pClient->mutex );
153 pClient->shutdown = 1u;
154 epicsMutexUnlock ( pClient->mutex );
155+ epicsEventSignal ( pClient->shutdownNotify );
156
157 /* unblock log client thread blocking in send() or connect() */
158 interruptInfo =
159@@ -154,13 +157,11 @@ static void logClientDestroy (logClientId id)
160 return;
161 }
162
163- errlogRemoveListeners ( logClientSendMessage, (void *) pClient );
164-
165 logClientClose ( pClient );
166
167 epicsMutexDestroy ( pClient->mutex );
168-
169 epicsEventDestroy ( pClient->stateChangeNotify );
170+ epicsEventDestroy ( pClient->shutdownNotify );
171
172 free ( pClient );
173 }
174@@ -176,61 +177,26 @@ static void sendMessageChunk(logClient * pClient, const char * message) {
175 unsigned msgBufBytesLeft =
176 sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
177
178- if ( strSize > msgBufBytesLeft ) {
179- int status;
180-
181- if ( ! pClient->connected ) {
182- break;
183- }
184-
185- if ( msgBufBytesLeft > 0u ) {
186- memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
187- message, msgBufBytesLeft );
188- pClient->nextMsgIndex += msgBufBytesLeft;
189- strSize -= msgBufBytesLeft;
190- message += msgBufBytesLeft;
191- }
192-
193- status = send ( pClient->sock, pClient->msgBuf,
194- pClient->nextMsgIndex, 0 );
195- if ( status > 0 ) {
196- unsigned nSent = (unsigned) status;
197- if ( nSent < pClient->nextMsgIndex ) {
198- unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
199- memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
200- newNextMsgIndex );
201- pClient->nextMsgIndex = newNextMsgIndex;
202- }
203- else {
204- pClient->nextMsgIndex = 0u;
205- }
206- }
207- else {
208- if ( ! pClient->shutdown ) {
209- char sockErrBuf[64];
210- if ( status ) {
211- epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
212- }
213- else {
214- strcpy ( sockErrBuf, "server initiated disconnect" );
215- }
216- fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
217- pClient->name, sockErrBuf );
218- }
219- logClientClose ( pClient );
220- break;
221- }
222+ if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected)
223+ {
224+ /* buffer is full, thus flush it */
225+ logClientFlush ( pClient );
226+ msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
227 }
228- else {
229- memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
230- message, strSize );
231- pClient->nextMsgIndex += strSize;
232+ if ( msgBufBytesLeft == 0u ) {
233+ fprintf ( stderr, "log client: messages to \"%s\" are lost\n",
234+ pClient->name );
235 break;
236 }
237+ if ( msgBufBytesLeft > strSize) msgBufBytesLeft = strSize;
238+ memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
239+ message, msgBufBytesLeft );
240+ pClient->nextMsgIndex += msgBufBytesLeft;
241+ strSize -= msgBufBytesLeft;
242+ message += msgBufBytesLeft;
243 }
244 }
245
246-
247 /*
248 * logClientSend ()
249 */
250@@ -255,43 +221,54 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message )
251
252 void epicsShareAPI logClientFlush ( logClientId id )
253 {
254+ unsigned nSent;
255+ int status = 0;
256+
257 logClient * pClient = ( logClient * ) id;
258
259- if ( ! pClient ) {
260+ if ( ! pClient || ! pClient->connected ) {
261 return;
262 }
263
264 epicsMutexMustLock ( pClient->mutex );
265
266- while ( pClient->nextMsgIndex && pClient->connected ) {
267- int status = send ( pClient->sock, pClient->msgBuf,
268- pClient->nextMsgIndex, 0 );
269- if ( status > 0 ) {
270- unsigned nSent = (unsigned) status;
271- if ( nSent < pClient->nextMsgIndex ) {
272- unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
273- memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
274- newNextMsgIndex );
275- pClient->nextMsgIndex = newNextMsgIndex;
276- }
277- else {
278- pClient->nextMsgIndex = 0u;
279- }
280+ nSent = pClient->backlog;
281+ while ( nSent < pClient->nextMsgIndex && pClient->connected ) {
282+ status = send ( pClient->sock, pClient->msgBuf + nSent,
283+ pClient->nextMsgIndex - nSent, 0 );
284+ if ( status < 0 ) break;
285+ nSent += status;
286+ }
287+
288+ if ( pClient->backlog > 0 && status >= 0 )
289+ {
290+ /* On Linux send 0 bytes can detect EPIPE */
291+ /* NOOP on Windows, fails on vxWorks */
292+ errno = 0;
293+ status = send ( pClient->sock, NULL, 0, 0 );
294+ if (!(errno == ECONNRESET || errno == EPIPE)) status = 0;
295+ }
296+
297+ if ( status < 0 ) {
298+ if ( ! pClient->shutdown ) {
299+ char sockErrBuf[128];
300+ epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
301+ fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
302+ pClient->name, sockErrBuf );
303 }
304- else {
305- if ( ! pClient->shutdown ) {
306- char sockErrBuf[64];
307- if ( status ) {
308- epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
309- }
310- else {
311- strcpy ( sockErrBuf, "server initiated disconnect" );
312- }
313- fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
314- pClient->name, sockErrBuf );
315- }
316- logClientClose ( pClient );
317- break;
318+ pClient->backlog = 0;
319+ logClientClose ( pClient );
320+ }
321+ else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
322+ int backlog = epicsSocketUnsentCount ( pClient->sock );
323+ if (backlog >= 0) {
324+ pClient->backlog = backlog;
325+ nSent -= backlog;
326+ }
327+ pClient->nextMsgIndex -= nSent;
328+ if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
329+ memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
330+ pClient->nextMsgIndex );
331 }
332 }
333 epicsMutexUnlock ( pClient->mutex );
334@@ -302,10 +279,10 @@ void epicsShareAPI logClientFlush ( logClientId id )
335 */
336 static void logClientMakeSock (logClient *pClient)
337 {
338-
339-# ifdef DEBUG
340+ if (logClientDebug) {
341 fprintf (stderr, "log client: creating socket...");
342-# endif
343+ fflush (stderr);
344+ }
345
346 epicsMutexMustLock (pClient->mutex);
347
348@@ -314,7 +291,7 @@ static void logClientMakeSock (logClient *pClient)
349 */
350 pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 );
351 if ( pClient->sock == INVALID_SOCKET ) {
352- char sockErrBuf[64];
353+ char sockErrBuf[128];
354 epicsSocketConvertErrnoToString (
355 sockErrBuf, sizeof ( sockErrBuf ) );
356 fprintf ( stderr, "log client: no socket error %s\n",
357@@ -323,10 +300,8 @@ static void logClientMakeSock (logClient *pClient)
358
359 epicsMutexUnlock (pClient->mutex);
360
361-# ifdef DEBUG
362+ if (logClientDebug)
363 fprintf (stderr, "done\n");
364-# endif
365-
366 }
367
368 /*
369@@ -366,7 +341,7 @@ static void logClientConnect (logClient *pClient)
370 }
371 else {
372 if ( pClient->connFailStatus != errnoCpy && ! pClient->shutdown ) {
373- char sockErrBuf[64];
374+ char sockErrBuf[128];
375 epicsSocketConvertErrnoToString (
376 sockErrBuf, sizeof ( sockErrBuf ) );
377 fprintf (stderr,
378@@ -392,7 +367,7 @@ static void logClientConnect (logClient *pClient)
379 optval = TRUE;
380 status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));
381 if (status<0) {
382- char sockErrBuf[64];
383+ char sockErrBuf[128];
384 epicsSocketConvertErrnoToString (
385 sockErrBuf, sizeof ( sockErrBuf ) );
386 fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf);
387@@ -404,11 +379,11 @@ static void logClientConnect (logClient *pClient)
388 */
389 status = shutdown (pClient->sock, SHUT_RD);
390 if (status < 0) {
391- char sockErrBuf[64];
392+ char sockErrBuf[128];
393 epicsSocketConvertErrnoToString (
394 sockErrBuf, sizeof ( sockErrBuf ) );
395- fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n",
396- __FILE__, __LINE__, pClient->sock, sockErrBuf);
397+ fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was \"%s\"\n",
398+ __FILE__, __LINE__, sockErrBuf);
399 /* not fatal (although it shouldn't happen) */
400 }
401
402@@ -425,7 +400,7 @@ static void logClientConnect (logClient *pClient)
403 lingerval.l_linger = 60*5;
404 status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval));
405 if (status<0) {
406- char sockErrBuf[64];
407+ char sockErrBuf[128];
408 epicsSocketConvertErrnoToString (
409 sockErrBuf, sizeof ( sockErrBuf ) );
410 fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf);
411@@ -457,14 +432,10 @@ static void logClientRestart ( logClientId id )
412
413 epicsMutexUnlock ( pClient->mutex );
414
415- if ( isConn ) {
416- logClientFlush ( pClient );
417- }
418- else {
419- logClientConnect ( pClient );
420- }
421-
422- epicsThreadSleep ( LOG_RESTART_DELAY );
423+ if ( ! isConn ) logClientConnect ( pClient );
424+ logClientFlush ( pClient );
425+
426+ epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY);
427
428 epicsMutexMustLock ( pClient->mutex );
429 }
430@@ -480,9 +451,7 @@ static void logClientRestart ( logClientId id )
431 logClientId epicsShareAPI logClientCreate (
432 struct in_addr server_addr, unsigned short server_port)
433 {
434- epicsTimeStamp begin, current;
435 logClient *pClient;
436- double diff;
437
438 pClient = calloc (1, sizeof (*pClient));
439 if (pClient==NULL) {
440@@ -507,14 +476,22 @@ logClientId epicsShareAPI logClientCreate (
441 pClient->shutdownConfirm = 0;
442
443 epicsAtExit (logClientDestroy, (void*) pClient);
444-
445+
446 pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty);
447 if ( ! pClient->stateChangeNotify ) {
448 epicsMutexDestroy ( pClient->mutex );
449 free ( pClient );
450 return NULL;
451 }
452-
453+
454+ pClient->shutdownNotify = epicsEventCreate (epicsEventEmpty);
455+ if ( ! pClient->shutdownNotify ) {
456+ epicsMutexDestroy ( pClient->mutex );
457+ epicsEventDestroy ( pClient->stateChangeNotify );
458+ free ( pClient );
459+ return NULL;
460+ }
461+
462 pClient->restartThreadId = epicsThreadCreate (
463 "logRestart", epicsThreadPriorityLow,
464 epicsThreadGetStackSize(epicsThreadStackSmall),
465@@ -522,35 +499,12 @@ logClientId epicsShareAPI logClientCreate (
466 if ( pClient->restartThreadId == NULL ) {
467 epicsMutexDestroy ( pClient->mutex );
468 epicsEventDestroy ( pClient->stateChangeNotify );
469+ epicsEventDestroy ( pClient->shutdownNotify );
470 free (pClient);
471 fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");
472 return NULL;
473 }
474
475- /*
476- * attempt to synchronize with circuit connect
477- */
478- epicsTimeGetCurrent ( & begin );
479- epicsMutexMustLock ( pClient->mutex );
480- do {
481- epicsMutexUnlock ( pClient->mutex );
482- epicsEventWaitWithTimeout (
483- pClient->stateChangeNotify,
484- LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 );
485- epicsTimeGetCurrent ( & current );
486- diff = epicsTimeDiffInSeconds ( & current, & begin );
487- epicsMutexMustLock ( pClient->mutex );
488- }
489- while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
490- epicsMutexUnlock ( pClient->mutex );
491-
492- if ( ! pClient->connected ) {
493- fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n",
494- pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
495- }
496-
497- errlogAddListener ( logClientSendMessage, (void *) pClient );
498-
499 return (void *) pClient;
500 }
501
502@@ -568,24 +522,21 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
503 printf ("log client: disconnected from log server at \"%s\"\n", pClient->name);
504 }
505
506- if (level>1) {
507- printf ("log client: sock=%s, connect cycles = %u\n",
508- pClient->sock==INVALID_SOCKET?"INVALID":"OK",
509- pClient->connectCount);
510- }
511-
512 if (logClientPrefix) {
513 printf ("log client: prefix is \"%s\"\n", logClientPrefix);
514 }
515-}
516
517-/*
518- * logClientSendMessage (); deprecated
519- */
520-void logClientSendMessage ( logClientId id, const char * message )
521-{
522- if ( !iocLogDisable ) {
523- logClientSend (id, message);
524+ if (level>0) {
525+ printf ("log client: sock %s, connect cycles = %u\n",
526+ pClient->sock==INVALID_SOCKET?"INVALID":"OK",
527+ pClient->connectCount);
528+ }
529+ if (level>1) {
530+ printf ("log client: %u bytes in buffer\n", pClient->nextMsgIndex);
531+ if (pClient->nextMsgIndex)
532+ printf("-------------------------\n"
533+ "%.*s-------------------------\n",
534+ (int)(pClient->nextMsgIndex), pClient->msgBuf);
535 }
536 }
537
538diff --git a/src/libCom/log/logClient.h b/src/libCom/log/logClient.h
539index 1797bbb..3b3f63a 100644
540--- a/src/libCom/log/logClient.h
541+++ b/src/libCom/log/logClient.h
542@@ -38,7 +38,6 @@ epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix);
543 /* deprecated interface; retained for backward compatibility */
544 /* note: implementations are in iocLog.c, not logClient.c */
545 epicsShareFunc logClientId epicsShareAPI logClientInit (void);
546-epicsShareFunc void logClientSendMessage (logClientId id, const char *message);
547
548 #ifdef __cplusplus
549 }
550diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile
551index e05aec3..00685d8 100644
552--- a/src/libCom/osi/Makefile
553+++ b/src/libCom/osi/Makefile
554@@ -86,6 +86,7 @@ endif
555
556 Com_SRCS += osdSock.c
557 Com_SRCS += osdSockAddrReuse.cpp
558+Com_SRCS += osdSockUnsentCount.c
559 Com_SRCS += osiSock.c
560 Com_SRCS += systemCallIntMech.cpp
561 Com_SRCS += epicsSocketConvertErrnoToString.cpp
562diff --git a/src/libCom/osi/os/Darwin/osdSockUnsentCount.c b/src/libCom/osi/os/Darwin/osdSockUnsentCount.c
563new file mode 100644
564index 0000000..20bd82b
565--- /dev/null
566+++ b/src/libCom/osi/os/Darwin/osdSockUnsentCount.c
567@@ -0,0 +1,19 @@
568+/*************************************************************************\
569+* EPICS BASE is distributed subject to a Software License Agreement found
570+* in file LICENSE that is included with this distribution.
571+\*************************************************************************/
572+
573+#define EPICS_PRIVATE_API
574+#include "osiSock.h"
575+
576+/*
577+ * epicsSocketUnsentCount ()
578+ * See https://www.unix.com/man-page/osx/2/setsockopt
579+ */
580+int epicsSocketUnsentCount(SOCKET sock) {
581+ int unsent;
582+ socklen_t len = sizeof(unsent);
583+ if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0)
584+ return unsent;
585+ return -1;
586+}
587diff --git a/src/libCom/osi/os/Linux/osdSockUnsentCount.c b/src/libCom/osi/os/Linux/osdSockUnsentCount.c
588new file mode 100644
589index 0000000..3c0a8f9
590--- /dev/null
591+++ b/src/libCom/osi/os/Linux/osdSockUnsentCount.c
592@@ -0,0 +1,19 @@
593+/*************************************************************************\
594+* EPICS BASE is distributed subject to a Software License Agreement found
595+* in file LICENSE that is included with this distribution.
596+\*************************************************************************/
597+
598+#include <linux/sockios.h>
599+#define EPICS_PRIVATE_API
600+#include "osiSock.h"
601+
602+/*
603+ * epicsSocketUnsentCount ()
604+ * See https://linux.die.net/man/7/tcp
605+ */
606+int epicsSocketUnsentCount(SOCKET sock) {
607+ int unsent;
608+ if (ioctl(sock, SIOCOUTQ, &unsent) == 0)
609+ return unsent;
610+ return -1;
611+}
612diff --git a/src/libCom/osi/os/WIN32/osdSockUnsentCount.c b/src/libCom/osi/os/WIN32/osdSockUnsentCount.c
613new file mode 100644
614index 0000000..3f4ab3e
615--- /dev/null
616+++ b/src/libCom/osi/os/WIN32/osdSockUnsentCount.c
617@@ -0,0 +1,26 @@
618+/*************************************************************************\
619+* EPICS BASE is distributed subject to a Software License Agreement found
620+* in file LICENSE that is included with this distribution.
621+\*************************************************************************/
622+
623+#define epicsExportSharedSymbols
624+#define EPICS_PRIVATE_API
625+#include "osiSock.h"
626+#include <mstcpip.h>
627+
628+/*
629+ * epicsSocketUnsentCount ()
630+ * See https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0
631+ */
632+int epicsSocketUnsentCount(SOCKET sock) {
633+#ifdef SIO_TCP_INFO
634+/* Windows 10 Version 1703 / Server 2016 */
635+ DWORD infoVersion = 0, bytesReturned;
636+ TCP_INFO_v0 tcpInfo;
637+ int status;
638+ if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion),
639+ &tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0)
640+ return tcpInfo.BytesInFlight;
641+#endif
642+ return -1;
643+}
644diff --git a/src/libCom/osi/os/default/osdSockUnsentCount.c b/src/libCom/osi/os/default/osdSockUnsentCount.c
645new file mode 100644
646index 0000000..ef01e9b
647--- /dev/null
648+++ b/src/libCom/osi/os/default/osdSockUnsentCount.c
649@@ -0,0 +1,15 @@
650+/*************************************************************************\
651+* EPICS BASE is distributed subject to a Software License Agreement found
652+* in file LICENSE that is included with this distribution.
653+\*************************************************************************/
654+
655+#define EPICS_PRIVATE_API
656+#include "osiSock.h"
657+
658+/*
659+ * epicsSocketUnsentCount ()
660+ */
661+int epicsSocketUnsentCount(SOCKET sock) {
662+ /* not implemented */
663+ return -1;
664+}
665diff --git a/src/libCom/osi/os/iOS/osdSockUnsentCount.c b/src/libCom/osi/os/iOS/osdSockUnsentCount.c
666new file mode 100644
667index 0000000..20bd82b
668--- /dev/null
669+++ b/src/libCom/osi/os/iOS/osdSockUnsentCount.c
670@@ -0,0 +1,19 @@
671+/*************************************************************************\
672+* EPICS BASE is distributed subject to a Software License Agreement found
673+* in file LICENSE that is included with this distribution.
674+\*************************************************************************/
675+
676+#define EPICS_PRIVATE_API
677+#include "osiSock.h"
678+
679+/*
680+ * epicsSocketUnsentCount ()
681+ * See https://www.unix.com/man-page/osx/2/setsockopt
682+ */
683+int epicsSocketUnsentCount(SOCKET sock) {
684+ int unsent;
685+ socklen_t len = sizeof(unsent);
686+ if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0)
687+ return unsent;
688+ return -1;
689+}
690diff --git a/src/libCom/osi/osiSock.h b/src/libCom/osi/osiSock.h
691index 061619e..6e3b053 100644
692--- a/src/libCom/osi/osiSock.h
693+++ b/src/libCom/osi/osiSock.h
694@@ -52,6 +52,14 @@ enum epicsSocketSystemCallInterruptMechanismQueryInfo {
695 epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo
696 epicsSocketSystemCallInterruptMechanismQuery ();
697
698+#ifdef EPICS_PRIVATE_API
699+/*
700+ * Some systems (e.g Linux and Windows 10) allow to check the amount
701+ * of unsent data in the output queue.
702+ * Returns -1 if the information is not available.
703+ */
704+epicsShareFunc int epicsSocketUnsentCount(SOCKET sock);
705+#endif
706
707 /*
708 * convert socket address to ASCII in this order

Subscribers

People subscribed via source and target branches