Skip to content

Commit 0523bff

Browse files
committed
Unix socket plugin:
Fix two failures and one error for socket tests on macOS. sendto(2) may fail with EISCONN if the socket is already connected and a perr address is supplied. So if sendto errors with EISCONN retry using send. Use poll(2) instead of select for determining writability of a single socket.
1 parent 7d1a55b commit 0523bff

File tree

1 file changed

+56
-23
lines changed

1 file changed

+56
-23
lines changed

platforms/unix/plugins/SocketPlugin/sqUnixSocket.c

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898
#endif
9999
# include <errno.h>
100100
# include <unistd.h>
101+
# include <poll.h>
102+
# define USE_POLL 1
101103

102104
#endif /* !ACORN */
103105

@@ -177,7 +179,10 @@ typedef struct privateSocketStruct
177179
socklen_t senderSize; /* dynamic sizeof(sender) */
178180
int multiListen; /* whether to listen for multiple connections */
179181
int acceptedSock; /* a connection that has been accepted */
180-
int notifiedOfWritability; /* flag compensates for select denying writable */
182+
int notifiedOfWritability;/* flag avoids calling select/poll a second time */
183+
#define notifiedOfWritability(pss) ((pss)->notifiedOfWritability)
184+
#define setNoticeOfWritability(pss) ((pss)->notifiedOfWritability = 1)
185+
#define clearNoticeOfWritability(pss) ((pss)->notifiedOfWritability = 0)
181186
} privateSocketStruct;
182187

183188
#define CONN_NOTIFY (1<<0)
@@ -344,19 +349,34 @@ socketReadable(int s)
344349
static int
345350
socketWritable(int s)
346351
{
352+
#if USE_POLL
353+
struct pollfd fd;
354+
355+
fd.fd = s;
356+
fd.events = POLLOUT;
357+
358+
# ifdef AIO_DEBUG
359+
if (poll(&fd, 1, 0) < 0)
360+
perror("socketWritable: poll(&fd, 1, 0)");
361+
# else
362+
poll(&fd, 1, 0);
363+
# endif
364+
return fd.revents & POLLOUT;
365+
#else
347366
struct timeval tv = { 0, 0 }; // i.e. poll
348367
fd_set fds;
349368

350369
FD_ZERO(&fds);
351370
FD_SET(s, &fds);
352-
#ifdef AIO_DEBUG
371+
# ifdef AIO_DEBUG
353372
{ int r = select(s + 1, 0, &fds, 0, &tv);
354373
if (r < 0)
355374
perror("socketWritable: select(1,0,&fd,0,&poll)");
356375
return r > 0;
357376
}
358-
#else
377+
# else
359378
return select(s + 1, 0, &fds, 0, &tv) > 0;
379+
# endif
360380
#endif
361381
}
362382

@@ -503,7 +523,7 @@ dataHandler(int fd, void *data, int flags)
503523
* in sqSocketSendDone answering false for new sockets. So we subvert select
504524
* by setting the notifiedOfWritability flag, tested in sqSocketSendDone.
505525
*/
506-
pss->notifiedOfWritability = true;
526+
setNoticeOfWritability(pss);
507527
}
508528
if (flags & AIO_X)
509529
{
@@ -1148,9 +1168,8 @@ sqSocketSendDone(SocketPtr s)
11481168
* in sqSocketSendDone answering false for new sockets. So we subvert select
11491169
* by testing the notifiedOfWritability flag, set in dataHandler.
11501170
*/
1151-
if (PSP(s)->notifiedOfWritability)
1152-
return true;
1153-
if (socketWritable(SOCKET(s)))
1171+
if (notifiedOfWritability(PSP(s))
1172+
|| socketWritable(SOCKET(s)))
11541173
return true;
11551174
FPRINTF((stderr, "sqSocketSendDone(%d) !socketWritable\n", SOCKET(s)));
11561175
aioHandle(SOCKET(s), dataHandler, AIO_WX);
@@ -1220,22 +1239,37 @@ sqSocketReceiveDataBufCount(SocketPtr s, char *buf, sqInt bufSize)
12201239
sqInt
12211240
sqSocketSendDataBufCount(SocketPtr s, char *buf, sqInt bufSize)
12221241
{
1223-
int nsent= 0;
1242+
int nsent, err = 0;
12241243

12251244
if (!socketValid(s))
12261245
return -1;
12271246

1228-
PSP(s)->notifiedOfWritability = false;
1247+
clearNoticeOfWritability(PSP(s));
12291248
if (TCPSocketType != s->socketType)
12301249
{
12311250
/* --- UDP/RAW --- */
12321251
FPRINTF((stderr, "UDP sendData(%d, %ld)\n", SOCKET(s), bufSize));
12331252
if ((nsent= sendto(SOCKET(s), buf, bufSize, 0, (struct sockaddr *)&SOCKETPEER(s), sizeof(SOCKETPEER(s)))) <= 0)
12341253
{
1235-
int err = errno;
1236-
if (err == EWOULDBLOCK) /* asynchronous write in progress */
1254+
if (nsent < 0
1255+
&& (err = errno) == EWOULDBLOCK) /* asynchronous write in progress */
12371256
return 0;
1238-
FPRINTF((stderr, "UDP send failed %d %s\n", err, strerror(err)));
1257+
FPRINTF((stderr, "UDP sendto failed %d %s\n", err, strerror(err)));
1258+
/* IEEE Std 1003.1, 2004 Edition, sendto - send a message on a socket
1259+
* [EISCONN] A destination address was specified and the socket
1260+
* is already connected. This error may or may not be
1261+
* returned for connection mode sockets.
1262+
* Hence use send if socket is connected.
1263+
*/
1264+
if (nsent < 0 && err == EISCONN) {
1265+
FPRINTF((stderr, "UDP retry sendData(%d, %ld)\n", SOCKET(s), bufSize));
1266+
if ((nsent = send(SOCKET(s), buf, bufSize, 0)) > 0)
1267+
goto completed;
1268+
if (nsent < 0
1269+
&& (err = errno) == EWOULDBLOCK) /* asynchronous write in progress */
1270+
return 0;
1271+
FPRINTF((stderr, "UDP send failed %d %s\n", err, strerror(err)));
1272+
}
12391273
SOCKETERROR(s)= err;
12401274
return 0;
12411275
}
@@ -1246,22 +1280,21 @@ sqSocketSendDataBufCount(SocketPtr s, char *buf, sqInt bufSize)
12461280
FPRINTF((stderr, "TCP sendData(%d, %ld)\n", SOCKET(s), bufSize));
12471281
if ((nsent= write(SOCKET(s), buf, bufSize)) <= 0)
12481282
{
1249-
if ((nsent == -1) && (errno == EWOULDBLOCK))
1283+
err = nsent < 0 ? errno : 0;
1284+
if (err == EWOULDBLOCK)
12501285
{
12511286
FPRINTF((stderr, "TCP sendData(%d, %ld) -> %d [blocked]",
12521287
SOCKET(s), bufSize, nsent));
12531288
return 0;
12541289
}
1255-
else
1256-
{
1257-
/* error: most likely "connection closed by peer" */
1258-
SOCKETSTATE(s)= OtherEndClosed;
1259-
SOCKETERROR(s)= errno;
1260-
FPRINTF((stderr, "TCP write failed -> %d", SOCKETERROR(s)));
1261-
return 0;
1262-
}
1290+
/* error: most likely "connection closed by peer" */
1291+
SOCKETSTATE(s)= OtherEndClosed;
1292+
SOCKETERROR(s)= err;
1293+
FPRINTF((stderr, "TCP write failed -> %d", SOCKETERROR(s)));
1294+
return 0;
12631295
}
12641296
}
1297+
completed:
12651298
/* write completed synchronously */
12661299
FPRINTF((stderr, "sendData(%d) done = %d\n", SOCKET(s), nsent));
12671300
return nsent;
@@ -1315,7 +1348,7 @@ sqSockettoHostportSendDataBufCount(SocketPtr s, sqInt address, sqInt port, char
13151348
saddr.sin_family= AF_INET;
13161349
saddr.sin_port= htons((short)port);
13171350
saddr.sin_addr.s_addr= htonl(address);
1318-
PSP(s)->notifiedOfWritability = false;
1351+
clearNoticeOfWritability(PSP(s));
13191352
{
13201353
int nsent= sendto(SOCKET(s), buf, bufSize, 0, (struct sockaddr *)&saddr, sizeof(saddr));
13211354
if (nsent >= 0)
@@ -2376,7 +2409,7 @@ sqSocketSendUDPToSizeDataBufCount(SocketPtr s, char *addr, sqInt addrSize, char
23762409
if (socketValid(s) && addressValid(addr, addrSize) && (TCPSocketType != s->socketType)) /* --- UDP/RAW --- */
23772410
{
23782411
int nsent= sendto(SOCKET(s), buf, bufSize, 0, socketAddress(addr), addrSize - AddressHeaderSize);
2379-
PSP(s)->notifiedOfWritability = false;
2412+
clearNoticeOfWritability(PSP(s));
23802413
if (nsent >= 0)
23812414
return nsent;
23822415

0 commit comments

Comments
 (0)