1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /**
21  * Abstractions over OS-dependent socket functionality.
22  */
23 module thrift.internal.socket;
24 
25 import std.conv : to;
26 
27 // FreeBSD and OS X return -1 and set ECONNRESET if socket was closed by
28 // the other side, we need to check for that before throwing an exception.
version(FreeBSD)29 version (FreeBSD) {
30   enum connresetOnPeerShutdown = true;
31 } else version (OSX) {
32   enum connresetOnPeerShutdown = true;
33 } else {
34   enum connresetOnPeerShutdown = false;
35 }
36 
version(Windows)37 version (Windows) {
38   import core.sys.windows.winsock2 : WSAGetLastError, WSAEINTR, WSAEWOULDBLOCK;
39   import std.windows.syserror : sysErrorString;
40 
41   // These are unfortunately not defined in std.c.windows.winsock, see
42   // http://msdn.microsoft.com/en-us/library/ms740668.aspx.
43   enum WSAECONNRESET = 10054;
44   enum WSAENOTCONN = 10057;
45   enum WSAETIMEDOUT = 10060;
46 } else {
47   import core.stdc.errno : errno, EAGAIN, ECONNRESET, EINPROGRESS, EINTR,
48     ENOTCONN, EPIPE;
49   import core.stdc.string : strerror;
50 }
51 
52 /*
53  * CONNECT_INPROGRESS_ERRNO: set by connect() for non-blocking sockets if the
54  *   connection could not be immediately established.
55  * INTERRUPTED_ERRNO: set when blocking system calls are interrupted by
56  *   signals or similar.
57  * TIMEOUT_ERRNO: set when a socket timeout has been exceeded.
58  * WOULD_BLOCK_ERRNO: set when send/recv would block on non-blocking sockets.
59  *
60  * isSocetCloseErrno(errno): returns true if errno indicates that the socket
61  *   is logically in closed state now.
62  */
version(Windows)63 version (Windows) {
64   alias WSAGetLastError getSocketErrno;
65   enum CONNECT_INPROGRESS_ERRNO = WSAEWOULDBLOCK;
66   enum INTERRUPTED_ERRNO = WSAEINTR;
67   enum TIMEOUT_ERRNO = WSAETIMEDOUT;
68   enum WOULD_BLOCK_ERRNO = WSAEWOULDBLOCK;
69 
70   bool isSocketCloseErrno(typeof(getSocketErrno()) errno) {
71     return (errno == WSAECONNRESET || errno == WSAENOTCONN);
72   }
73 } else {
74   alias errno getSocketErrno;
75   enum CONNECT_INPROGRESS_ERRNO = EINPROGRESS;
76   enum INTERRUPTED_ERRNO = EINTR;
77   enum WOULD_BLOCK_ERRNO = EAGAIN;
78 
79   // TODO: The C++ TSocket implementation mentions that EAGAIN can also be
80   // set (undocumentedly) in out of resource conditions; it would be a good
81   // idea to contact the original authors of the C++ code for details and adapt
82   // the code accordingly.
83   enum TIMEOUT_ERRNO = EAGAIN;
84 
isSocketCloseErrno(typeof (getSocketErrno ())errno)85   bool isSocketCloseErrno(typeof(getSocketErrno()) errno) {
86     return (errno == EPIPE || errno == ECONNRESET || errno == ENOTCONN);
87   }
88 }
89 
socketErrnoString(uint errno)90 string socketErrnoString(uint errno) {
91   version (Windows) {
92     return sysErrorString(errno);
93   } else {
94     return to!string(strerror(errno));
95   }
96 }
97