2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include <AbstractSocket.h>
11 #include <netinet/in.h>
15 //#define TRACE_SOCKET
17 # define TRACE(x...) printf(x)
19 # define TRACE(x...) ;
23 BAbstractSocket::BAbstractSocket()
25 fInitStatus(B_NO_INIT
),
33 BAbstractSocket::BAbstractSocket(const BAbstractSocket
& other
)
35 fInitStatus(other
.fInitStatus
),
38 fIsConnected(other
.fIsConnected
)
40 fSocket
= dup(other
.fSocket
);
46 BAbstractSocket::~BAbstractSocket()
53 BAbstractSocket::InitCheck() const
60 BAbstractSocket::IsBound() const
67 BAbstractSocket::IsConnected() const
74 BAbstractSocket::Disconnect()
79 TRACE("%p: BAbstractSocket::Disconnect()\n", this);
89 BAbstractSocket::SetTimeout(bigtime_t timeout
)
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) {
109 BAbstractSocket::Timeout() const
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
127 const BNetworkAddress
&
128 BAbstractSocket::Peer() const
135 BAbstractSocket::MaxTransmissionSize() const
142 BAbstractSocket::WaitForReadable(bigtime_t timeout
) const
144 return _WaitFor(POLLIN
, timeout
);
149 BAbstractSocket::WaitForWritable(bigtime_t timeout
) const
151 return _WaitFor(POLLOUT
, timeout
);
156 BAbstractSocket::Socket() const
162 // #pragma mark - protected
166 BAbstractSocket::Bind(const BNetworkAddress
& local
, int type
)
168 fInitStatus
= _OpenIfNeeded(local
.Family(), type
);
169 if (fInitStatus
!= B_OK
)
172 if (bind(fSocket
, local
, local
.Length()) != 0)
173 return fInitStatus
= errno
;
176 _UpdateLocalAddress();
182 BAbstractSocket::Connect(const BNetworkAddress
& peer
, int type
,
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
)
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
;
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
221 BAbstractSocket::_OpenIfNeeded(int family
, int type
)
226 fSocket
= socket(family
, type
, 0);
230 TRACE("%p: socket opened FD %d\n", this, fSocket
);
236 BAbstractSocket::_UpdateLocalAddress()
238 socklen_t localLength
= sizeof(sockaddr_storage
);
239 if (getsockname(fSocket
, fLocal
, &localLength
) != 0)
247 BAbstractSocket::_WaitFor(int flags
, bigtime_t timeout
) const
249 if (fInitStatus
!= B_OK
)
253 if (timeout
== B_INFINITE_TIMEOUT
)
256 millis
= timeout
/ 1000;
260 entry
.events
= flags
;
262 int result
= poll(&entry
, 1, millis
);
266 return millis
> 0 ? B_TIMED_OUT
: B_WOULD_BLOCK
;