E-MailRelay
gsocket_win32.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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.valid() )
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.valid() )
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
118{
119 return m_reason == WSAEMSGSIZE ;
120}
121
123{
124 return m_reason == WSAEMFILE ; // or WSAENOBUFS ?
125}
126
127bool GNet::SocketBase::setNonBlocking()
128{
129 unsigned long ul = 1 ;
130 return ioctlsocket( m_fd.fd() , FIONBIO , &ul ) != SOCKET_ERROR ;
131}
132
133std::string GNet::SocketBase::reasonString( int e )
134{
135 const char * p = nullptr ;
136 if( e == WSAEINTR ) p = "interupted" ;
137 //if( e == WSAEBADF ) p = "" ;
138 if( e == WSAEACCES ) p = "access denied" ;
139 //if( e == WSAEFAULT ) p = "" ;
140 if( e == WSAEINVAL ) p = "invalid parameter" ;
141 //if( e == WSAEMFILE ) p = "" ;
142 //if( e == WSAEWOULDBLOCK ) p = "" ;
143 //if( e == WSAEINPROGRESS ) p = "" ;
144 //if( e == WSAEALREADY ) p = "" ;
145 //if( e == WSAENOTSOCK ) p = "" ;
146 //if( e == WSAEDESTADDRREQ ) p = "" ;
147 //if( e == WSAEMSGSIZE ) p = "" ;
148 //if( e == WSAEPROTOTYPE ) p = "" ;
149 //if( e == WSAENOPROTOOPT ) p = "" ;
150 //if( e == WSAEPROTONOSUPPORT ) p = "" ;
151 //if( e == WSAESOCKTNOSUPPORT ) p = "" ;
152 //if( e == WSAEOPNOTSUPP ) p = "" ;
153 //if( e == WSAEPFNOSUPPORT ) p = "" ;
154 //if( e == WSAEAFNOSUPPORT ) p = "" ;
155 if( e == WSAEADDRINUSE ) p = "address already in use" ;
156 if( e == WSAEADDRNOTAVAIL ) p = "address not available" ;
157 if( e == WSAENETDOWN ) p = "network down" ;
158 if( e == WSAENETUNREACH ) p = "network unreachable" ;
159 if( e == WSAENETRESET ) p = "network reset" ;
160 //if( e == WSAECONNABORTED ) p = "" ;
161 //if( e == WSAECONNRESET ) p = "" ;
162 //if( e == WSAENOBUFS ) p = "" ;
163 //if( e == WSAEISCONN ) p = "" ;
164 if( e == WSAENOTCONN ) p = "cannot connect" ;
165 //if( e == WSAESHUTDOWN ) p = "" ;
166 //if( e == WSAETOOMANYREFS ) p = "" ;
167 if( e == WSAETIMEDOUT ) p = "timed out" ;
168 if( e == WSAECONNREFUSED ) p = "connection refused" ;
169 //if( e == WSAELOOP ) p = "" ;
170 //if( e == WSAENAMETOOLONG ) p = "" ;
171 if( e == WSAEHOSTDOWN ) p = "host down" ;
172 if( e == WSAEHOSTUNREACH ) p = "host unreachable" ;
173 //if( e == WSAENOTEMPTY ) p = "" ;
174 //if( e == WSAEPROCLIM ) p = "" ;
175 //if( e == WSAEUSERS ) p = "" ;
176 //if( e == WSAEDQUOT ) p = "" ;
177 //if( e == WSAESTALE ) p = "" ;
178 //if( e == WSAEREMOTE ) p = "" ;
179 if( p )
180 return std::string( p ) ;
181
182 std::string s = G::Process::strerror( e ) ;
183 if( G::Str::imatch(s,"unknown error") )
184 return s.append(" (").append(G::Str::fromInt(e)).append(1U,')') ;
185 else
186 return s ;
187}
188
189// ==
190
191std::string GNet::Socket::canBindHint( const Address & , bool , const Config & )
192{
193 return std::string() ; // not implemented
194}
195
196void GNet::Socket::setOptionReuse()
197{
198 setOption( SOL_SOCKET , "so_reuseaddr" , SO_REUSEADDR , 1 ) ;
199}
200
201void GNet::Socket::setOptionExclusive()
202{
203 setOption( SOL_SOCKET , "so_exclusiveaddruse" , SO_EXCLUSIVEADDRUSE , 1 ) ;
204}
205
206void GNet::Socket::setOptionPureV6()
207{
208 // no-op
209}
210
211bool GNet::Socket::setOptionPureV6( std::nothrow_t )
212{
213 return true ; // no-op
214}
215
216bool GNet::Socket::setOptionImp( int level , int op , const void * arg , socklen_t n )
217{
218 const char * cp = static_cast<const char*>(arg) ;
219 int rc = ::setsockopt( fd() , level , op , cp , n ) ;
220 bool ok = !error( rc ) ;
221 return ok ;
222}
223
224// ==
225
226std::size_t GNet::DatagramSocket::limit( std::size_t default_in ) const
227{
228 return default_in ;
229}
230
static int domain(Family) noexcept
Returns the address 'domain' for the given family, eg.
Definition: gaddress.cpp:468
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:199
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.
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:1418
static std::string fromInt(int i)
Converts int 'i' to a string.
Definition: gstr.h:598