replaced unweildy GAddress functions with wxSockAddressImpl class, similarly to GSock...
[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(bool flag)
108 {
109 wxSocketManager * const manager = wxSocketManager::Get();
110 if ( flag )
111 {
112 manager->Install_Callback(this, wxSOCKET_INPUT);
113 manager->Install_Callback(this, wxSOCKET_OUTPUT);
114 }
115 else // off
116 {
117 manager->Uninstall_Callback(this, wxSOCKET_INPUT);
118 manager->Uninstall_Callback(this, wxSOCKET_OUTPUT);
119 }
120 }
121
122
123 void wxSocketImplUnix::OnStateChange(wxSocketNotify event)
124 {
125 NotifyOnStateChange(event);
126
127 if ( event == wxSOCKET_LOST )
128 Shutdown();
129 }
130
131 void wxSocketImplUnix::OnReadWaiting()
132 {
133 char c;
134
135 if (m_fd == INVALID_SOCKET)
136 {
137 return;
138 }
139
140 int num = recv(m_fd, &c, 1, MSG_PEEK);
141
142 if (num > 0)
143 {
144 OnStateChange(wxSOCKET_INPUT);
145 }
146 else
147 {
148 if (m_server && m_stream)
149 {
150 OnStateChange(wxSOCKET_CONNECTION);
151 }
152 else if (num == 0)
153 {
154 if (m_stream)
155 {
156 /* graceful shutdown */
157 OnStateChange(wxSOCKET_LOST);
158 }
159 else
160 {
161 /* Empty datagram received */
162 OnStateChange(wxSOCKET_INPUT);
163 }
164 }
165 else
166 {
167 /* Do not throw a lost event in cases where the socket isn't really lost */
168 if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINTR))
169 {
170 OnStateChange(wxSOCKET_INPUT);
171 }
172 else
173 {
174 OnStateChange(wxSOCKET_LOST);
175 }
176 }
177 }
178 }
179
180 void wxSocketImplUnix::OnWriteWaiting()
181 {
182 if (m_establishing && !m_server)
183 {
184 int error;
185 SOCKOPTLEN_T len = sizeof(error);
186
187 m_establishing = false;
188
189 getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
190
191 if (error)
192 {
193 OnStateChange(wxSOCKET_LOST);
194 }
195 else
196 {
197 OnStateChange(wxSOCKET_CONNECTION);
198 /* We have to fire this event by hand because CONNECTION (for clients)
199 * and OUTPUT are internally the same and we just disabled CONNECTION
200 * events with the above macro.
201 */
202 OnStateChange(wxSOCKET_OUTPUT);
203 }
204 }
205 else
206 {
207 OnStateChange(wxSOCKET_OUTPUT);
208 }
209 }
210
211 void wxSocketImplUnix::OnExceptionWaiting()
212 {
213 wxFAIL_MSG( "not supposed to be called" );
214 }
215
216 #endif /* wxUSE_SOCKETS */