E-MailRelay

gsocket_win32.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gsocket_win32.cpp
19///
20
21#include "gdef.h"
22#include "gsocket.h"
23#include "gprocess.h"
24#include "gstr.h"
25#include "gassert.h"
26#include <errno.h>
27
28 bool GNet::SocketBase::supports( Address::Family af , int type , int protocol )
29{
30 SOCKET fd = ::socket( Address::domain(af) , type , protocol ) ;
31 if( fd == INVALID_SOCKET )
32 return false ;
33 ::closesocket( fd ) ;
34 return true ;
35}
36
37 bool GNet::SocketBase::create( int domain , int type , int protocol )
38{
39 m_fd = Descriptor( ::socket( domain , type , protocol ) , 0 ) ;
40 if( !m_fd.validfd() )
41 {
42 saveReason() ;
43 return false ;
44 }
45
46 m_fd = Descriptor( m_fd.fd() , WSACreateEvent() ) ;
47 if( m_fd.h() == HNULL )
48 {
49 saveReason() ;
50 ::closesocket( m_fd.fd() ) ;
51 return false ;
52 }
53 return true ;
54}
55
56 bool GNet::SocketBase::prepare( bool accepted )
57{
58 if( accepted )
59 {
60 G_ASSERT( m_fd.h() == HNULL ) ;
61 HANDLE h = WSACreateEvent() ;
62 if( h == HNULL )
63 {
64 saveReason() ;
65 return false ;
66 }
67 m_fd = Descriptor( m_fd.fd() , h ) ;
68 }
69
70 if( !setNonBlocking() )
71 {
72 saveReason() ;
73 return false ;
74 }
75 return true ;
76}
77
78 void GNet::SocketBase::destroy() noexcept
79{
80 if( m_fd.h() != HNULL )
81 WSACloseEvent( m_fd.h() ) ;
82
83 if( m_fd.validfd() )
84 ::closesocket( m_fd.fd() ) ;
85}
86
87 bool GNet::SocketBase::error( int rc )
88{
89 return rc == SOCKET_ERROR ;
90}
91
92 void GNet::SocketBase::saveReason()
93{
94 m_reason = WSAGetLastError() ;
95}
96
97 bool GNet::SocketBase::sizeError( ssize_t size )
98{
99 return size == SOCKET_ERROR ;
100}
101
102 bool GNet::SocketBase::eNotConn() const
103{
104 return m_reason == WSAENOTCONN ;
105}
106
107 bool GNet::SocketBase::eWouldBlock() const
108{
109 return m_reason == WSAEWOULDBLOCK ;
110}
111
112 bool GNet::SocketBase::eInProgress() const
113{
114 return m_reason == WSAEWOULDBLOCK ; // sic -- WSAEINPROGRESS has different semantics wrt. Unix
115}
116
117 bool GNet::SocketBase::eInUse() const
118{
119 return m_reason == WSAEADDRINUSE ;
120}
121
122 bool GNet::SocketBase::eMsgSize() const
123{
124 return m_reason == WSAEMSGSIZE ;
125}
126
127 bool GNet::SocketBase::eTooMany() const
128{
129 return m_reason == WSAEMFILE ; // or WSAENOBUFS ?
130}
131
132 bool GNet::SocketBase::setNonBlocking()
133{
134 unsigned long ul = 1 ;
135 return ioctlsocket( m_fd.fd() , FIONBIO , &ul ) != SOCKET_ERROR ;
136}
137
138std::string GNet::SocketBase::reasonString( int e )
139{
140 const char * p = nullptr ;
141 if( e == WSAEINTR ) p = "interupted" ;
142 //if( e == WSAEBADF ) p = "" ;
143 if( e == WSAEACCES ) p = "access denied" ;
144 //if( e == WSAEFAULT ) p = "" ;
145 if( e == WSAEINVAL ) p = "invalid parameter" ;
146 //if( e == WSAEMFILE ) p = "" ;
147 //if( e == WSAEWOULDBLOCK ) p = "" ;
148 //if( e == WSAEINPROGRESS ) p = "" ;
149 //if( e == WSAEALREADY ) p = "" ;
150 //if( e == WSAENOTSOCK ) p = "" ;
151 //if( e == WSAEDESTADDRREQ ) p = "" ;
152 //if( e == WSAEMSGSIZE ) p = "" ;
153 //if( e == WSAEPROTOTYPE ) p = "" ;
154 //if( e == WSAENOPROTOOPT ) p = "" ;
155 //if( e == WSAEPROTONOSUPPORT ) p = "" ;
156 //if( e == WSAESOCKTNOSUPPORT ) p = "" ;
157 //if( e == WSAEOPNOTSUPP ) p = "" ;
158 //if( e == WSAEPFNOSUPPORT ) p = "" ;
159 //if( e == WSAEAFNOSUPPORT ) p = "" ;
160 if( e == WSAEADDRINUSE ) p = "address already in use" ;
161 if( e == WSAEADDRNOTAVAIL ) p = "address not available" ;
162 if( e == WSAENETDOWN ) p = "network down" ;
163 if( e == WSAENETUNREACH ) p = "network unreachable" ;
164 if( e == WSAENETRESET ) p = "network reset" ;
165 //if( e == WSAECONNABORTED ) p = "" ;
166 //if( e == WSAECONNRESET ) p = "" ;
167 //if( e == WSAENOBUFS ) p = "" ;
168 //if( e == WSAEISCONN ) p = "" ;
169 if( e == WSAENOTCONN ) p = "cannot connect" ;
170 //if( e == WSAESHUTDOWN ) p = "" ;
171 //if( e == WSAETOOMANYREFS ) p = "" ;
172 if( e == WSAETIMEDOUT ) p = "timed out" ;
173 if( e == WSAECONNREFUSED ) p = "connection refused" ;
174 //if( e == WSAELOOP ) p = "" ;
175 //if( e == WSAENAMETOOLONG ) p = "" ;
176 if( e == WSAEHOSTDOWN ) p = "host down" ;
177 if( e == WSAEHOSTUNREACH ) p = "host unreachable" ;
178 //if( e == WSAENOTEMPTY ) p = "" ;
179 //if( e == WSAEPROCLIM ) p = "" ;
180 //if( e == WSAEUSERS ) p = "" ;
181 //if( e == WSAEDQUOT ) p = "" ;
182 //if( e == WSAESTALE ) p = "" ;
183 //if( e == WSAEREMOTE ) p = "" ;
184 if( p )
185 return std::string( p ) ;
186
187 std::string s = G::Process::strerror( e ) ;
188 if( G::Str::imatch(s,"unknown error") )
189 return s.append(" (").append(G::Str::fromInt(e)).append(1U,')') ;
190 else
191 return s ;
192}
193
194// ==
195
196std::string GNet::Socket::canBindHint( const Address & , bool , const Config & )
197{
198 return std::string() ; // not implemented
199}
200
201 void GNet::Socket::setOptionReuse()
202{
203 setOption( SOL_SOCKET , "so_reuseaddr" , SO_REUSEADDR , 1 ) ;
204}
205
206 void GNet::Socket::setOptionExclusive()
207{
208 setOption( SOL_SOCKET , "so_exclusiveaddruse" , SO_EXCLUSIVEADDRUSE , 1 ) ;
209}
210
211 void GNet::Socket::setOptionPureV6()
212{
213 // no-op
214}
215
216 bool GNet::Socket::setOptionPureV6( std::nothrow_t )
217{
218 return true ; // no-op
219}
220
221 bool GNet::Socket::setOptionImp( int level , int op , const void * arg , socklen_t n )
222{
223 const char * cp = static_cast<const char*>(arg) ;
224 int rc = ::setsockopt( fd() , level , op , cp , n ) ;
225 bool ok = !error( rc ) ;
226 return ok ;
227}
228
229// ==
230
231std::size_t GNet::DatagramSocket::limit( std::size_t default_in ) const
232{
233 return default_in ;
234}
235
GNet::Address::domain
static int domain(Family) noexcept
Returns the address 'domain' for the given family, eg.
Definition: gaddress.cpp:466
GNet::DatagramSocket::limit
std::size_t limit(std::size_t default_=1024U) const
Returns the systems's maximum datagram size if the value is known and greater than the given default ...
Definition: gsocket_unix.cpp:245
GNet::SocketBase::eNotConn
bool eNotConn() const
Returns true if the previous socket operation failed with the ENOTCONN error status,...
Definition: gsocket_unix.cpp:120
GNet::SocketBase::eInProgress
bool eInProgress() const
Returns true if the previous socket operation failed with the EINPROGRESS error status.
Definition: gsocket_unix.cpp:130
GNet::SocketBase::fd
SOCKET fd() const noexcept override
Returns the socket file descriptor.
Definition: gsocket.cpp:200
GNet::SocketBase::error
static bool error(int rc)
Returns true if the given return code indicates an error.
Definition: gsocket_unix.cpp:95
GNet::SocketBase::eMsgSize
bool eMsgSize() const
Returns true if the previous socket operation failed with the EMSGSIZE error status.
Definition: gsocket_unix.cpp:141
GNet::SocketBase::sizeError
static bool sizeError(ssize_type size)
Returns true if the given write() return value indicates an error.
Definition: gsocket_unix.cpp:115
GNet::SocketBase::eInUse
bool eInUse() const
Returns true if the previous socket bind operation failed because the socket was already in use.
Definition: gsocket_unix.cpp:135
GNet::SocketBase::supports
static bool supports(Address::Family, int type, int protocol)
Returns true if sockets can be created with the given parameters.
Definition: gsocket_unix.cpp:34
GNet::SocketBase::eWouldBlock
bool eWouldBlock() const override
Returns true if the previous socket operation failed because the socket would have blocked.
Definition: gsocket_unix.cpp:125
GNet::SocketBase::eTooMany
bool eTooMany() const
Returns true if the previous socket operation failed with the EMFILE error status,...
Definition: gsocket_unix.cpp:147
GNet::SocketBase::saveReason
void saveReason()
Saves the current errno following error()/sizeError().
Definition: gsocket_unix.cpp:100
GNet::Socket::canBindHint
static std::string canBindHint(const Address &address, bool stream_socket, const Config &)
Returns the empty string if a socket could probably be bound with the given address or a failure reas...
Definition: gsocket_unix.cpp:160
G::Process::strerror
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
Definition: gprocess_unix.cpp:142
G::Str::imatch
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
Definition: gstr.cpp:1415
G::Str::fromInt
static std::string fromInt(int i)
Converts int 'i' to a string.
Definition: gstr.h:594
gassert.h
gprocess.h
gsocket.h
gstr.h