summaryrefslogtreecommitdiff
path: root/cpp/src/IceBT/Util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceBT/Util.cpp')
-rw-r--r--cpp/src/IceBT/Util.cpp170
1 files changed, 166 insertions, 4 deletions
diff --git a/cpp/src/IceBT/Util.cpp b/cpp/src/IceBT/Util.cpp
index baf3edff738..8d5001d84fd 100644
--- a/cpp/src/IceBT/Util.cpp
+++ b/cpp/src/IceBT/Util.cpp
@@ -87,20 +87,182 @@ SocketAddress
IceBT::createAddr(const string& addr, Ice::Int channel)
{
SocketAddress ret;
- memset(&ret, 0, sizeof(ret));
ret.rc_family = AF_BLUETOOTH;
ret.rc_channel = static_cast<uint8_t>(channel);
parseDeviceAddress(addr, ret.rc_bdaddr);
return ret;
}
+SOCKET
+IceBT::createSocket()
+{
+ SOCKET fd = ::socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if(fd == INVALID_SOCKET)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = errno;
+ throw ex;
+ }
+ return fd;
+}
+
+bool
+IceBT::doConnect(SOCKET fd, const SocketAddress& addr)
+{
+ int size = sizeof(SocketAddress);
+ assert(size != 0);
+
+repeatConnect:
+ if(::connect(fd, reinterpret_cast<const struct sockaddr*>(&addr), size) == SOCKET_ERROR)
+ {
+ if(IceInternal::interrupted())
+ {
+ goto repeatConnect;
+ }
+
+ if(IceInternal::connectInProgress())
+ {
+ return false;
+ }
+
+ IceInternal::closeSocketNoThrow(fd);
+ if(IceInternal::connectionRefused())
+ {
+ ConnectionRefusedException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else if(IceInternal::connectFailed())
+ {
+ ConnectFailedException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ }
+ return true;
+}
+
+void
+IceBT::doFinishConnect(SOCKET fd)
+{
+ //
+ // Note: we don't close the socket if there's an exception. It's the responsibility
+ // of the caller to do so.
+ //
+
+ int val;
+ socklen_t len = static_cast<socklen_t>(sizeof(int));
+ if(::getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&val), &len) == SOCKET_ERROR)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+
+ if(val > 0)
+ {
+ errno = val;
+ if(IceInternal::connectionRefused())
+ {
+ ConnectionRefusedException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else if(IceInternal::connectFailed())
+ {
+ ConnectFailedException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ }
+}
+
+SocketAddress
+IceBT::doBind(SOCKET fd, const SocketAddress& addr)
+{
+ if(addr.rc_channel <= 0)
+ {
+ //
+ // Find an available by channel by looping over the valid channel numbers (1-30) until bind succeeds.
+ //
+ SocketAddress tmp = addr;
+ for(tmp.rc_channel = 1; tmp.rc_channel <= 30; ++tmp.rc_channel)
+ {
+ if(::bind(fd, reinterpret_cast<const struct sockaddr*>(&tmp), sizeof(SocketAddress)) == 0)
+ {
+ break;
+ }
+ }
+ if(tmp.rc_channel > 30)
+ {
+ IceInternal::closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = errno;
+ throw ex;
+ }
+ }
+ else
+ {
+ if(::bind(fd, reinterpret_cast<const struct sockaddr*>(&addr), sizeof(SocketAddress)) == SOCKET_ERROR)
+ {
+ IceInternal::closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = errno;
+ throw ex;
+ }
+ }
+
+ SocketAddress local;
+ socklen_t len = static_cast<socklen_t>(sizeof(SocketAddress));
+# ifdef NDEBUG
+ getsockname(fd, &local, &len);
+# else
+ int ret = getsockname(fd, reinterpret_cast<struct sockaddr*>(&local), &len);
+ assert(ret != SOCKET_ERROR);
+# endif
+ return local;
+}
+
+SOCKET
+IceBT::doAccept(SOCKET fd)
+{
+ int ret;
+
+repeatAccept:
+ if((ret = ::accept(fd, 0, 0)) == INVALID_SOCKET)
+ {
+ if(IceInternal::acceptInterrupted())
+ {
+ goto repeatAccept;
+ }
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = errno;
+ throw ex;
+ }
+
+ return ret;
+}
+
namespace
{
void
fdToLocalAddress(SOCKET fd, SocketAddress& addr)
{
- socklen_t len = static_cast<socklen_t>(sizeof(SocketAddress));
+ socklen_t len = static_cast<socklen_t>(sizeof(sockaddr_rc));
if(::getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
{
IceInternal::closeSocketNoThrow(fd);
@@ -113,7 +275,7 @@ fdToLocalAddress(SOCKET fd, SocketAddress& addr)
bool
fdToRemoteAddress(SOCKET fd, SocketAddress& addr)
{
- socklen_t len = static_cast<socklen_t>(sizeof(SocketAddress));
+ socklen_t len = static_cast<socklen_t>(sizeof(sockaddr_rc));
if(::getpeername(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
{
if(IceInternal::notConnected())
@@ -224,5 +386,5 @@ IceBT::compareAddress(const SocketAddress& addr1, const SocketAddress& addr2)
return 1;
}
- return ::memcmp(&addr1.rc_bdaddr, &addr2.rc_bdaddr, sizeof(DeviceAddress));
+ return ::memcmp(&addr1.rc_bdaddr, &addr2.rc_bdaddr, sizeof(bdaddr_t));
}