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
28bool 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
37bool 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
56bool 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
78void 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
87bool GNet::SocketBase::error( int rc )
88{
89 return rc == SOCKET_ERROR ;
90}
91
93{
94 m_reason = WSAGetLastError() ;
95}
96
97bool GNet::SocketBase::sizeError( ssize_t size )
98{
99 return size == SOCKET_ERROR ;
100}
101
103{
104 return m_reason == WSAENOTCONN ;
105}
106
108{
109 return m_reason == WSAEWOULDBLOCK ;
110}
111
113{
114 return m_reason == WSAEWOULDBLOCK ; // sic -- WSAEINPROGRESS has different semantics wrt. Unix
115}
116
117bool GNet::SocketBase::eInUse() const
118{
119 return m_reason == WSAEADDRINUSE ;
120}
121
123{
124 return m_reason == WSAEMSGSIZE ;
125}
126
128{
129 return m_reason == WSAEMFILE ; // or WSAENOBUFS ?
130}
131
132bool 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
201void GNet::Socket::setOptionReuse()
202{
203 setOption( SOL_SOCKET , "so_reuseaddr" , SO_REUSEADDR , 1 ) ;
204}
205
206void GNet::Socket::setOptionExclusive()
207{
208 setOption( SOL_SOCKET , "so_exclusiveaddruse" , SO_EXCLUSIVEADDRUSE , 1 ) ;
209}
210
211void GNet::Socket::setOptionPureV6()
212{
213 // no-op
214}
215
216bool GNet::Socket::setOptionPureV6( std::nothrow_t )
217{
218 return true ; // no-op
219}
220
221bool 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
static int domain(Family) noexcept
Returns the address 'domain' for the given family, eg.
Definition: gaddress.cpp:466
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 ...
bool eNotConn() const
Returns true if the previous socket operation failed with the ENOTCONN error status,...
bool eInProgress() const
Returns true if the previous socket operation failed with the EINPROGRESS error status.
SOCKET fd() const noexcept override
Returns the socket file descriptor.
Definition: gsocket.cpp:200
static bool error(int rc)
Returns true if the given return code indicates an error.
bool eMsgSize() const
Returns true if the previous socket operation failed with the EMSGSIZE error status.
static bool sizeError(ssize_type size)
Returns true if the given write() return value indicates an error.
bool eInUse() const
Returns true if the previous socket bind operation failed because the socket was already in use.
static bool supports(Address::Family, int type, int protocol)
Returns true if sockets can be created with the given parameters.
bool eWouldBlock() const override
Returns true if the previous socket operation failed because the socket would have blocked.
bool eTooMany() const
Returns true if the previous socket operation failed with the EMFILE error status,...
void saveReason()
Saves the current errno following error()/sizeError().
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...
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
Definition: gstr.cpp:1415
static std::string fromInt(int i)
Converts int 'i' to a string.
Definition: gstr.h:594