tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / network / libnetapi / AbstractSocket.cpp
blobb42b4af7b4badd203acb9c15b93737e8914507f9
1 /*
2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <AbstractSocket.h>
9 #include <arpa/inet.h>
10 #include <fcntl.h>
11 #include <netinet/in.h>
12 #include <sys/poll.h>
15 //#define TRACE_SOCKET
16 #ifdef TRACE_SOCKET
17 # define TRACE(x...) printf(x)
18 #else
19 # define TRACE(x...) ;
20 #endif
23 BAbstractSocket::BAbstractSocket()
25 fInitStatus(B_NO_INIT),
26 fSocket(-1),
27 fIsBound(false),
28 fIsConnected(false)
33 BAbstractSocket::BAbstractSocket(const BAbstractSocket& other)
35 fInitStatus(other.fInitStatus),
36 fLocal(other.fLocal),
37 fPeer(other.fPeer),
38 fIsConnected(other.fIsConnected)
40 fSocket = dup(other.fSocket);
41 if (fSocket < 0)
42 fInitStatus = errno;
46 BAbstractSocket::~BAbstractSocket()
48 Disconnect();
52 status_t
53 BAbstractSocket::InitCheck() const
55 return fInitStatus;
59 bool
60 BAbstractSocket::IsBound() const
62 return fIsBound;
66 bool
67 BAbstractSocket::IsConnected() const
69 return fIsConnected;
73 void
74 BAbstractSocket::Disconnect()
76 if (fSocket < 0)
77 return;
79 TRACE("%p: BAbstractSocket::Disconnect()\n", this);
81 close(fSocket);
82 fSocket = -1;
83 fIsConnected = false;
84 fIsBound = false;
88 status_t
89 BAbstractSocket::SetTimeout(bigtime_t timeout)
91 if (timeout < 0)
92 timeout = 0;
94 struct timeval tv;
95 tv.tv_sec = timeout / 1000000LL;
96 tv.tv_usec = timeout % 1000000LL;
98 if (setsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval)) != 0
99 || setsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, &tv,
100 sizeof(timeval)) != 0) {
101 return errno;
104 return B_OK;
108 bigtime_t
109 BAbstractSocket::Timeout() const
111 struct timeval tv;
112 socklen_t size = sizeof(tv);
113 if (getsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, &tv, &size) != 0)
114 return B_INFINITE_TIMEOUT;
116 return tv.tv_sec * 1000000LL + tv.tv_usec;
120 const BNetworkAddress&
121 BAbstractSocket::Local() const
123 return fLocal;
127 const BNetworkAddress&
128 BAbstractSocket::Peer() const
130 return fPeer;
134 size_t
135 BAbstractSocket::MaxTransmissionSize() const
137 return SSIZE_MAX;
141 status_t
142 BAbstractSocket::WaitForReadable(bigtime_t timeout) const
144 return _WaitFor(POLLIN, timeout);
148 status_t
149 BAbstractSocket::WaitForWritable(bigtime_t timeout) const
151 return _WaitFor(POLLOUT, timeout);
156 BAbstractSocket::Socket() const
158 return fSocket;
162 // #pragma mark - protected
165 status_t
166 BAbstractSocket::Bind(const BNetworkAddress& local, int type)
168 fInitStatus = _OpenIfNeeded(local.Family(), type);
169 if (fInitStatus != B_OK)
170 return fInitStatus;
172 if (bind(fSocket, local, local.Length()) != 0)
173 return fInitStatus = errno;
175 fIsBound = true;
176 _UpdateLocalAddress();
177 return B_OK;
181 status_t
182 BAbstractSocket::Connect(const BNetworkAddress& peer, int type,
183 bigtime_t timeout)
185 Disconnect();
187 fInitStatus = _OpenIfNeeded(peer.Family(), type);
188 if (fInitStatus == B_OK)
189 fInitStatus = SetTimeout(timeout);
191 if (fInitStatus == B_OK && !IsBound()) {
192 BNetworkAddress local;
193 local.SetToWildcard(peer.Family());
194 fInitStatus = Bind(local);
196 if (fInitStatus != B_OK)
197 return fInitStatus;
199 BNetworkAddress normalized = peer;
200 if (connect(fSocket, normalized, normalized.Length()) != 0) {
201 TRACE("%p: connecting to %s: %s\n", this,
202 normalized.ToString().c_str(), strerror(errno));
203 return fInitStatus = errno;
206 fIsConnected = true;
207 fPeer = normalized;
208 _UpdateLocalAddress();
210 TRACE("%p: connected to %s (local %s)\n", this, peer.ToString().c_str(),
211 fLocal.ToString().c_str());
213 return fInitStatus = B_OK;
217 // #pragma mark - private
220 status_t
221 BAbstractSocket::_OpenIfNeeded(int family, int type)
223 if (fSocket >= 0)
224 return B_OK;
226 fSocket = socket(family, type, 0);
227 if (fSocket < 0)
228 return errno;
230 TRACE("%p: socket opened FD %d\n", this, fSocket);
231 return B_OK;
235 status_t
236 BAbstractSocket::_UpdateLocalAddress()
238 socklen_t localLength = sizeof(sockaddr_storage);
239 if (getsockname(fSocket, fLocal, &localLength) != 0)
240 return errno;
242 return B_OK;
246 status_t
247 BAbstractSocket::_WaitFor(int flags, bigtime_t timeout) const
249 if (fInitStatus != B_OK)
250 return fInitStatus;
252 int millis = 0;
253 if (timeout == B_INFINITE_TIMEOUT)
254 millis = -1;
255 if (timeout > 0)
256 millis = timeout / 1000;
258 struct pollfd entry;
259 entry.fd = Socket();
260 entry.events = flags;
262 int result = poll(&entry, 1, millis);
263 if (result < 0)
264 return errno;
265 if (result == 0)
266 return millis > 0 ? B_TIMED_OUT : B_WOULD_BLOCK;
268 return B_OK;