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