1 /*=============================================================================
3 ===============================================================================
4 This is the implementation of TSocket for a standard Unix (POSIX)
5 stream socket -- what you create with a socket() C library call.
6 =============================================================================*/
8 #include "xmlrpc_config.h"
12 #include <sys/types.h>
16 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
21 #include <arpa/inet.h>
25 #include <sys/filio.h>
28 #include <sys/ioctl.h>
31 #include "xmlrpc-c/util_int.h"
32 #include "mallocvar.h"
35 #include "xmlrpc-c/abyss.h"
37 #include "socket_unix.h"
42 /*----------------------------------------------------------------------------
43 The properties/state of a TSocket unique to a Unix TSocket.
44 -----------------------------------------------------------------------------*/
46 /* File descriptor of the POSIX socket (such as is created by
47 socket() in the C library) on which the TSocket is based.
49 abyss_bool userSuppliedFd;
50 /* The file descriptor and associated POSIX socket belong to the
51 user; we did not create it.
57 SocketUnixInit(abyss_bool * const succeededP) {
65 SocketUnixTerm(void) {
71 static SocketDestroyImpl socketDestroy;
72 static SocketWriteImpl socketWrite;
73 static SocketReadImpl socketRead;
74 static SocketConnectImpl socketConnect;
75 static SocketBindImpl socketBind;
76 static SocketListenImpl socketListen;
77 static SocketAcceptImpl socketAccept;
78 static SocketErrorImpl socketError;
79 static SocketWaitImpl socketWait;
80 static SocketAvailableReadBytesImpl socketAvailableReadBytes;
81 static SocketGetPeerNameImpl socketGetPeerName;
84 static struct TSocketVtbl const vtbl = {
94 &socketAvailableReadBytes,
101 SocketUnixCreate(TSocket ** const socketPP) {
103 struct socketUnix * socketUnixP;
105 MALLOCVAR(socketUnixP);
109 rc = socket(AF_INET, SOCK_STREAM, 0);
113 socketUnixP->fd = rc;
114 socketUnixP->userSuppliedFd = FALSE;
119 rc = setsockopt(socketUnixP->fd, SOL_SOCKET, SO_REUSEADDR,
120 (char*)&n, sizeof(n));
124 SocketCreate(&vtbl, socketUnixP, socketPP);
127 close(socketUnixP->fd);
138 SocketUnixCreateFd(int const fd,
139 TSocket ** const socketPP) {
141 struct socketUnix * socketUnixP;
143 MALLOCVAR(socketUnixP);
146 socketUnixP->fd = fd;
147 socketUnixP->userSuppliedFd = TRUE;
149 SocketCreate(&vtbl, socketUnixP, socketPP);
160 socketDestroy(TSocket * const socketP) {
162 struct socketUnix * const socketUnixP = socketP->implP;
164 if (!socketUnixP->userSuppliedFd)
165 close(socketUnixP->fd);
173 socketWrite(TSocket * const socketP,
174 const unsigned char * const buffer,
176 abyss_bool * const failedP) {
178 struct socketUnix * const socketUnixP = socketP->implP;
183 assert(sizeof(size_t) >= sizeof(len));
185 for (bytesLeft = len, error = FALSE;
186 bytesLeft > 0 && !error;
188 size_t const maxSend = (size_t)(-1) >> 1;
192 rc = send(socketUnixP->fd, &buffer[len-bytesLeft],
193 MIN(maxSend, bytesLeft), 0);
195 if (SocketTraceIsActive) {
197 fprintf(stderr, "Abyss socket: send() failed. errno=%d (%s)",
198 errno, strerror(errno));
200 fprintf(stderr, "Abyss socket: send() failed. "
203 fprintf(stderr, "Abyss socket: sent %u bytes: '%.*s'\n",
204 rc, rc, &buffer[len-bytesLeft]);
207 /* 0 means connection closed; < 0 means severe error */
218 socketRead(TSocket * const socketP,
220 uint32_t const len) {
222 struct socketUnix * const socketUnixP = socketP->implP;
225 rc = recv(socketUnixP->fd, buffer, len, 0);
226 if (SocketTraceIsActive) {
228 fprintf(stderr, "Abyss socket: recv() failed. errno=%d (%s)",
229 errno, strerror(errno));
231 fprintf(stderr, "Abyss socket: read %u bytes: '%.*s'\n",
232 len, (int)len, buffer);
240 socketConnect(TSocket * const socketP,
241 TIPAddr * const addrP,
242 uint16_t const portNumber) {
244 struct socketUnix * const socketUnixP = socketP->implP;
246 struct sockaddr_in name;
249 name.sin_family = AF_INET;
250 name.sin_port = htons(portNumber);
251 name.sin_addr = *addrP;
253 rc = connect(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name));
261 socketBind(TSocket * const socketP,
262 TIPAddr * const addrP,
263 uint16_t const portNumber) {
265 struct socketUnix * const socketUnixP = socketP->implP;
267 struct sockaddr_in name;
270 name.sin_family = AF_INET;
271 name.sin_port = htons(portNumber);
273 name.sin_addr = *addrP;
275 name.sin_addr.s_addr = INADDR_ANY;
277 rc = bind(socketUnixP->fd, (struct sockaddr *)&name, sizeof(name));
285 socketListen(TSocket * const socketP,
286 uint32_t const backlog) {
288 struct socketUnix * const socketUnixP = socketP->implP;
290 int32_t const minus1 = -1;
294 /* Disable the Nagle algorithm to make persistant connections faster */
296 setsockopt(socketUnixP->fd, IPPROTO_TCP,TCP_NODELAY,
297 &minus1, sizeof(minus1));
299 rc = listen(socketUnixP->fd, backlog);
307 socketAccept(TSocket * const listenSocketP,
308 abyss_bool * const connectedP,
309 abyss_bool * const failedP,
310 TSocket ** const acceptedSocketPP,
311 TIPAddr * const ipAddrP) {
312 /*----------------------------------------------------------------------------
313 Accept a connection on the listening socket 'listenSocketP'. Return as
314 *acceptedSocketPP the socket for the accepted connection.
316 If no connection is waiting on 'listenSocketP', wait until one is.
318 If we receive a signal while waiting, return immediately.
320 Return *connectedP true iff we accepted a connection. Return
321 *failedP true iff we were unable to accept a connection for some
322 reason other than that we were interrupted. Return both false if
323 our wait for a connection was interrupted by a signal.
324 -----------------------------------------------------------------------------*/
325 struct socketUnix * const listenSocketUnixP = listenSocketP->implP;
327 abyss_bool connected, failed, interrupted;
333 while (!connected && !failed && !interrupted) {
334 struct sockaddr_in sa;
335 socklen_t size = sizeof(sa);
337 rc = accept(listenSocketUnixP->fd, (struct sockaddr *)&sa, &size);
339 int const acceptedFd = rc;
340 struct socketUnix * acceptedSocketUnixP;
342 MALLOCVAR(acceptedSocketUnixP);
344 if (acceptedSocketUnixP) {
345 acceptedSocketUnixP->fd = acceptedFd;
346 acceptedSocketUnixP->userSuppliedFd = FALSE;
348 SocketCreate(&vtbl, acceptedSocketUnixP, acceptedSocketPP);
349 if (!*acceptedSocketPP)
353 *ipAddrP = sa.sin_addr;
356 free(acceptedSocketUnixP);
361 } else if (errno == EINTR)
367 *connectedP = connected;
373 socketWait(TSocket * const socketP,
376 uint32_t const timems) {
378 struct socketUnix * const socketUnixP = socketP->implP;
383 if (SocketTraceIsActive)
384 fprintf(stderr, "Waiting %u milliseconds for %s %s of socket\n",
385 timems, rd ? "READ" : "", wr ? "WRITE" : "");
391 FD_SET(socketUnixP->fd, &rfds);
394 FD_SET(socketUnixP->fd, &wfds);
396 tv.tv_sec = timems / 1000;
397 tv.tv_usec = timems % 1000;
402 rc = select(socketUnixP->fd + 1, &rfds, &wfds, NULL,
403 (timems == TIME_INFINITE ? NULL : &tv));
406 case 0: /* time out */
409 case -1: /* socket error */
416 if (FD_ISSET(socketUnixP->fd, &rfds))
418 if (FD_ISSET(socketUnixP->fd, &wfds))
428 socketAvailableReadBytes(TSocket * const socketP) {
430 struct socketUnix * const socketUnixP = socketP->implP;
435 rc = ioctl(socketUnixP->fd, FIONREAD, &x);
437 if (SocketTraceIsActive) {
439 fprintf(stderr, "Socket has %u bytes available\n", x);
441 fprintf(stderr, "ioctl(FIONREAD) failed, errno=%d (%s)\n",
442 errno, strerror(errno));
444 return rc == 0 ? x : 0;
450 socketGetPeerName(TSocket * const socketP,
451 TIPAddr * const ipAddrP,
452 uint16_t * const portNumberP,
453 abyss_bool * const successP) {
455 struct socketUnix * const socketUnixP = socketP->implP;
459 struct sockaddr sockAddr;
461 addrlen = sizeof(sockAddr);
463 rc = getpeername(socketUnixP->fd, &sockAddr, &addrlen);
466 TraceMsg("getpeername() failed. errno=%d (%s)",
467 errno, strerror(errno));
470 if (addrlen != sizeof(sockAddr)) {
471 TraceMsg("getpeername() returned a socket address of the wrong "
472 "size: %u. Expected %u", addrlen, sizeof(sockAddr));
475 if (sockAddr.sa_family != AF_INET) {
476 TraceMsg("Socket does not use the Inet (IP) address "
477 "family. Instead it uses family %d",
481 struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)
484 *ipAddrP = sockAddrInP->sin_addr;
485 *portNumberP = sockAddrInP->sin_port;
496 socketError(TSocket * const socketP) {
498 if (socketP){} /* defeat compiler warning */