disable the events when we get a notification about socket being ready for IO and...
[wxWidgets.git] / src / unix / sockunix.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/sockunix.cpp
3 // Purpose: wxSocketImpl implementation for Unix systems
4 // Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia, David Elliott,
5 // Vadim Zeitlin
6 // Created: April 1997
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997 Guilhem Lavaux
9 // (c) 2008 Vadim Zeitlin
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13
14 #include "wx/wxprec.h"
15
16 #if wxUSE_SOCKETS
17
18 #include "wx/private/fd.h"
19 #include "wx/private/socket.h"
20 #include "wx/unix/private/sockunix.h"
21
22 #include <errno.h>
23
24 #if defined(__WATCOMC__)
25 #include <nerrno.h>
26 #endif
27
28 #include <sys/types.h>
29
30 #ifdef HAVE_SYS_SELECT_H
31 # include <sys/select.h>
32 #endif
33
34 #ifdef __EMX__
35 #include <sys/select.h>
36 #endif
37
38 #ifndef WX_SOCKLEN_T
39
40 #ifdef VMS
41 # define WX_SOCKLEN_T unsigned int
42 #else
43 # ifdef __GLIBC__
44 # if __GLIBC__ == 2
45 # define WX_SOCKLEN_T socklen_t
46 # endif
47 # elif defined(__WXMAC__)
48 # define WX_SOCKLEN_T socklen_t
49 # else
50 # define WX_SOCKLEN_T int
51 # endif
52 #endif
53
54 #endif /* SOCKLEN_T */
55
56 #ifndef SOCKOPTLEN_T
57 #define SOCKOPTLEN_T WX_SOCKLEN_T
58 #endif
59
60 // UnixWare reportedly needs this for FIONBIO definition
61 #ifdef __UNIXWARE__
62 #include <sys/filio.h>
63 #endif
64
65 // ============================================================================
66 // wxSocketImpl implementation
67 // ============================================================================
68
69 /* static */
70 wxSocketImpl *wxSocketImpl::Create(wxSocketBase& wxsocket)
71 {
72 return new wxSocketImplUnix(wxsocket);
73 }
74
75
76 wxSocketError wxSocketImplUnix::GetLastError() const
77 {
78 switch ( errno )
79 {
80 case 0:
81 return wxSOCKET_NOERROR;
82
83 case ENOTSOCK:
84 return wxSOCKET_INVSOCK;
85
86 // unfortunately EAGAIN only has the "would block" meaning for read(),
87 // not for connect() for which it means something rather different but
88 // we can't distinguish between these two situations currently...
89 //
90 // also notice that EWOULDBLOCK can be different from EAGAIN on some
91 // systems (HP-UX being the only known example) while it's defined as
92 // EAGAIN on most others (e.g. Linux)
93 case EAGAIN:
94 #ifdef EWOULDBLOCK
95 #if EWOULDBLOCK != EAGAIN
96 case EWOULDBLOCK:
97 #endif
98 #endif // EWOULDBLOCK
99 case EINPROGRESS:
100 return wxSOCKET_WOULDBLOCK;
101
102 default:
103 return wxSOCKET_IOERR;
104 }
105 }
106
107 void wxSocketImplUnix::DoEnableEvents(int flags, bool enable)
108 {
109 wxSocketManager * const manager = wxSocketManager::Get();
110 if ( enable )
111 {
112 if ( flags & wxSOCKET_INPUT_FLAG )
113 manager->Install_Callback(this, wxSOCKET_INPUT);
114 if ( flags & wxSOCKET_OUTPUT_FLAG )
115 manager->Install_Callback(this, wxSOCKET_OUTPUT);
116 }
117 else // off
118 {
119 if ( flags & wxSOCKET_INPUT_FLAG )
120 manager->Uninstall_Callback(this, wxSOCKET_INPUT);
121 if ( flags & wxSOCKET_OUTPUT_FLAG )
122 manager->Uninstall_Callback(this, wxSOCKET_OUTPUT);
123 }
124 }
125
126 int wxSocketImplUnix::CheckForInput()
127 {
128 char c;
129 int rc;
130 do
131 {
132 rc = recv(m_fd, &c, 1, MSG_PEEK);
133 } while ( rc == -1 && errno == EINTR );
134
135 return rc;
136 }
137
138 void wxSocketImplUnix::OnStateChange(wxSocketNotify event)
139 {
140 NotifyOnStateChange(event);
141
142 if ( event == wxSOCKET_LOST )
143 Shutdown();
144 }
145
146 void wxSocketImplUnix::OnReadWaiting()
147 {
148 wxASSERT_MSG( m_fd != INVALID_SOCKET, "invalid socket ready for reading?" );
149
150 // we need to disable the read notifications until we read all the data
151 // already available for the socket, otherwise we're going to keep getting
152 // them continuously which is worse than inefficient: as IO notifications
153 // have higher priority than idle events in e.g. GTK+, our pending events
154 // whose handlers typically call Read() which would consume the data and so
155 // stop the notifications flood would never be dispatched at all if the
156 // notifications were not disabled
157 DisableEvents(wxSOCKET_INPUT_FLAG);
158
159
160 // find out what are we going to notify about exactly
161 wxSocketNotify notify;
162
163 // TCP listening sockets become ready for reading when there is a pending
164 // connection
165 if ( m_server && m_stream )
166 {
167 notify = wxSOCKET_CONNECTION;
168 }
169 else // check if there is really any input available
170 {
171 switch ( CheckForInput() )
172 {
173 case 1:
174 notify = wxSOCKET_INPUT;
175 break;
176
177 case 0:
178 // reading 0 bytes for a TCP socket means that the connection
179 // was closed by peer but for UDP it just means that we got an
180 // empty datagram
181 notify = m_stream ? wxSOCKET_LOST : wxSOCKET_INPUT;
182 break;
183
184 default:
185 wxFAIL_MSG( "unexpected CheckForInput() return value" );
186 // fall through
187
188 case -1:
189 if ( GetLastError() == wxSOCKET_WOULDBLOCK )
190 {
191 // just a spurious wake up
192 EnableEvents(wxSOCKET_INPUT_FLAG);
193 return;
194 }
195
196 notify = wxSOCKET_LOST;
197 }
198 }
199
200 OnStateChange(notify);
201 }
202
203 void wxSocketImplUnix::OnWriteWaiting()
204 {
205 wxASSERT_MSG( m_fd != INVALID_SOCKET, "invalid socket ready for writing?" );
206
207 // see comment in the beginning of OnReadWaiting() above
208 DisableEvents(wxSOCKET_OUTPUT_FLAG);
209
210
211 // check whether this is a notification for the completion of a
212 // non-blocking connect()
213 if ( m_establishing && !m_server )
214 {
215 m_establishing = false;
216
217 // check whether we connected successfully
218 int error;
219 SOCKOPTLEN_T len = sizeof(error);
220
221 getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
222
223 if ( error )
224 {
225 OnStateChange(wxSOCKET_LOST);
226 return;
227 }
228
229 OnStateChange(wxSOCKET_CONNECTION);
230 }
231
232 OnStateChange(wxSOCKET_OUTPUT);
233 }
234
235 void wxSocketImplUnix::OnExceptionWaiting()
236 {
237 wxFAIL_MSG( "not supposed to be called" );
238 }
239
240 #endif /* wxUSE_SOCKETS */