From c9dd7d0ddfb8c1d5ef801904deeb42765aa28003 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Wed, 27 Apr 2016 21:13:14 -0400 Subject: [PATCH] libbnetapi: Extend socket classes. B{Abstract,Datagram,Secure}Socket: - Add functionality to listen for and accept new connections, thus allowing one to use the socket classes for server functionality as well. BSecureSocket: - Adjust to take into account differences between how SSL needs to be called when accepting an incoming connection vs initiating an outbound one. The handshake on the accepted connection stills fails for unknown reasons at the moment though. Note that these changes break the ABI, and thus any packages making use of them directly will need a rebuild. --- headers/os/net/AbstractSocket.h | 14 ++- headers/os/net/DatagramSocket.h | 5 +- headers/os/net/SecureSocket.h | 8 +- headers/os/net/Socket.h | 11 ++- src/kits/network/libnetapi/AbstractSocket.cpp | 56 +++++++++++- src/kits/network/libnetapi/DatagramSocket.cpp | 11 ++- .../network/libnetapi/ProxySecureSocket.cpp | 2 +- src/kits/network/libnetapi/SecureSocket.cpp | 88 ++++++++++++++++++- src/kits/network/libnetapi/Socket.cpp | 26 +++++- 9 files changed, 198 insertions(+), 23 deletions(-) diff --git a/headers/os/net/AbstractSocket.h b/headers/os/net/AbstractSocket.h index b0033763e53..761379099ee 100644 --- a/headers/os/net/AbstractSocket.h +++ b/headers/os/net/AbstractSocket.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2016, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _ABSTRACT_SOCKET_H @@ -20,8 +20,12 @@ class BAbstractSocket : public BDataIO { status_t InitCheck() const; - virtual status_t Bind(const BNetworkAddress& local) = 0; + virtual status_t Bind(const BNetworkAddress& local, bool reuseAddr) = 0; virtual bool IsBound() const; + virtual bool IsListening() const; + + virtual status_t Listen(int backlog = 10); + virtual status_t Accept(BAbstractSocket*& _socket) = 0; virtual status_t Connect(const BNetworkAddress& peer, bigtime_t timeout = B_INFINITE_TIMEOUT) = 0; @@ -44,9 +48,12 @@ class BAbstractSocket : public BDataIO { int Socket() const; protected: - status_t Bind(const BNetworkAddress& local, int type); + status_t Bind(const BNetworkAddress& local, + bool reuseAddr, int type); status_t Connect(const BNetworkAddress& peer, int type, bigtime_t timeout = B_INFINITE_TIMEOUT); + status_t AcceptNext(int& _acceptedSocket, + BNetworkAddress& _peer); private: status_t _OpenIfNeeded(int family, int type); @@ -60,6 +67,7 @@ class BAbstractSocket : public BDataIO { BNetworkAddress fPeer; bool fIsBound; bool fIsConnected; + bool fIsListening; }; diff --git a/headers/os/net/DatagramSocket.h b/headers/os/net/DatagramSocket.h index c555a9105de..945e0a6d6cf 100644 --- a/headers/os/net/DatagramSocket.h +++ b/headers/os/net/DatagramSocket.h @@ -17,10 +17,13 @@ class BDatagramSocket : public BAbstractSocket { BDatagramSocket(const BDatagramSocket& other); virtual ~BDatagramSocket(); - virtual status_t Bind(const BNetworkAddress& peer); + virtual status_t Bind(const BNetworkAddress& peer, + bool reuseAddr = true); virtual status_t Connect(const BNetworkAddress& peer, bigtime_t timeout = B_INFINITE_TIMEOUT); + virtual status_t Accept(BAbstractSocket*& _socket); + status_t SetBroadcast(bool broadcast); void SetPeer(const BNetworkAddress& peer); diff --git a/headers/os/net/SecureSocket.h b/headers/os/net/SecureSocket.h index 8e13d20836c..ebf1e15e39d 100644 --- a/headers/os/net/SecureSocket.h +++ b/headers/os/net/SecureSocket.h @@ -1,5 +1,5 @@ /* - * Copyright 2011-2015, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2016, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _SECURE_SOCKET_H @@ -27,6 +27,8 @@ class BSecureSocket : public BSocket { // BSocket implementation + virtual status_t Accept(BAbstractSocket*& _socket); + virtual status_t Connect(const BNetworkAddress& peer, bigtime_t timeout = B_INFINITE_TIMEOUT); virtual void Disconnect(); @@ -40,7 +42,9 @@ class BSecureSocket : public BSocket { virtual ssize_t Write(const void* buffer, size_t size); protected: - status_t _Setup(); + status_t _SetupCommon(); + status_t _SetupConnect(); + status_t _SetupAccept(); private: friend class BCertificate; diff --git a/headers/os/net/Socket.h b/headers/os/net/Socket.h index 77ed2cb5653..94070a37867 100644 --- a/headers/os/net/Socket.h +++ b/headers/os/net/Socket.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Copyright 2011-2016, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _SOCKET_H @@ -17,7 +17,11 @@ class BSocket : public BAbstractSocket { BSocket(const BSocket& other); virtual ~BSocket(); - virtual status_t Bind(const BNetworkAddress& peer); + virtual status_t Bind(const BNetworkAddress& peer, + bool reuseAddr = true); + + virtual status_t Accept(BAbstractSocket*& _socket); + virtual status_t Connect(const BNetworkAddress& peer, bigtime_t timeout = B_INFINITE_TIMEOUT); @@ -26,8 +30,7 @@ class BSocket : public BAbstractSocket { virtual ssize_t Read(void* buffer, size_t size); virtual ssize_t Write(const void* buffer, size_t size); -private: - friend class BServerSocket; +protected: void _SetTo(int fd, const BNetworkAddress& local, const BNetworkAddress& peer); diff --git a/src/kits/network/libnetapi/AbstractSocket.cpp b/src/kits/network/libnetapi/AbstractSocket.cpp index b42b4af7b4b..1f851a41d30 100644 --- a/src/kits/network/libnetapi/AbstractSocket.cpp +++ b/src/kits/network/libnetapi/AbstractSocket.cpp @@ -1,5 +1,6 @@ /* * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -25,7 +26,8 @@ BAbstractSocket::BAbstractSocket() fInitStatus(B_NO_INIT), fSocket(-1), fIsBound(false), - fIsConnected(false) + fIsConnected(false), + fIsListening(false) { } @@ -35,7 +37,8 @@ BAbstractSocket::BAbstractSocket(const BAbstractSocket& other) fInitStatus(other.fInitStatus), fLocal(other.fLocal), fPeer(other.fPeer), - fIsConnected(other.fIsConnected) + fIsConnected(other.fIsConnected), + fIsListening(other.fIsListening) { fSocket = dup(other.fSocket); if (fSocket < 0) @@ -63,6 +66,13 @@ BAbstractSocket::IsBound() const } +bool +BAbstractSocket::IsListening() const +{ + return fIsListening; +} + + bool BAbstractSocket::IsConnected() const { @@ -70,6 +80,20 @@ BAbstractSocket::IsConnected() const } +status_t +BAbstractSocket::Listen(int backlog) +{ + if (!fIsBound) + return B_NO_INIT; + + if (listen(Socket(), backlog) != 0) + return fInitStatus = errno; + + fIsListening = true; + return B_OK; +} + + void BAbstractSocket::Disconnect() { @@ -163,12 +187,20 @@ BAbstractSocket::Socket() const status_t -BAbstractSocket::Bind(const BNetworkAddress& local, int type) +BAbstractSocket::Bind(const BNetworkAddress& local, bool reuseAddr, int type) { fInitStatus = _OpenIfNeeded(local.Family(), type); if (fInitStatus != B_OK) return fInitStatus; + if (reuseAddr) { + int value = 1; + if (setsockopt(Socket(), SOL_SOCKET, SO_REUSEADDR, &value, + sizeof(value)) != 0) { + return fInitStatus = errno; + } + } + if (bind(fSocket, local, local.Length()) != 0) return fInitStatus = errno; @@ -191,7 +223,7 @@ BAbstractSocket::Connect(const BNetworkAddress& peer, int type, if (fInitStatus == B_OK && !IsBound()) { BNetworkAddress local; local.SetToWildcard(peer.Family()); - fInitStatus = Bind(local); + fInitStatus = Bind(local, true); } if (fInitStatus != B_OK) return fInitStatus; @@ -214,6 +246,22 @@ BAbstractSocket::Connect(const BNetworkAddress& peer, int type, } +status_t +BAbstractSocket::AcceptNext(int& _acceptedSocket, BNetworkAddress& _peer) +{ + sockaddr_storage source; + socklen_t sourceLength = sizeof(sockaddr_storage); + + int fd = accept(fSocket, (sockaddr*)&source, &sourceLength); + if (fd < 0) + return fd; + + _peer.SetTo(source); + _acceptedSocket = fd; + return B_OK; +} + + // #pragma mark - private diff --git a/src/kits/network/libnetapi/DatagramSocket.cpp b/src/kits/network/libnetapi/DatagramSocket.cpp index 23f59ab06ca..26ab20703fe 100644 --- a/src/kits/network/libnetapi/DatagramSocket.cpp +++ b/src/kits/network/libnetapi/DatagramSocket.cpp @@ -39,9 +39,16 @@ BDatagramSocket::~BDatagramSocket() status_t -BDatagramSocket::Bind(const BNetworkAddress& local) +BDatagramSocket::Bind(const BNetworkAddress& local, bool reuseAddr) { - return BAbstractSocket::Bind(local, SOCK_DGRAM); + return BAbstractSocket::Bind(local, reuseAddr, SOCK_DGRAM); +} + + +status_t +BDatagramSocket::Accept(BAbstractSocket*& _socket) +{ + return B_NOT_SUPPORTED; } diff --git a/src/kits/network/libnetapi/ProxySecureSocket.cpp b/src/kits/network/libnetapi/ProxySecureSocket.cpp index 1ad8a234b07..111dbc3e948 100644 --- a/src/kits/network/libnetapi/ProxySecureSocket.cpp +++ b/src/kits/network/libnetapi/ProxySecureSocket.cpp @@ -70,7 +70,7 @@ BProxySecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) if (httpStatus < 200 || httpStatus > 299) return B_BAD_VALUE; - return _Setup(); + return _SetupConnect(); } diff --git a/src/kits/network/libnetapi/SecureSocket.cpp b/src/kits/network/libnetapi/SecureSocket.cpp index d5e31e32245..ef66cf8a86d 100644 --- a/src/kits/network/libnetapi/SecureSocket.cpp +++ b/src/kits/network/libnetapi/SecureSocket.cpp @@ -1,6 +1,7 @@ /* - * Copyright 2013-2015 Haiku, Inc. + * Copyright 2013-2016 Haiku, Inc. * Copyright 2011-2015, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Rene Gollent, rene@gollent.com. * Copyright 2010, Clemens Zeidler * Distributed under the terms of the MIT License. */ @@ -18,6 +19,8 @@ #include #include +#include + #include "CertificatePrivate.h" @@ -256,6 +259,33 @@ BSecureSocket::~BSecureSocket() } +status_t +BSecureSocket::Accept(BAbstractSocket*& _socket) +{ + int fd = -1; + BNetworkAddress peer; + status_t error = AcceptNext(fd, peer); + if (error != B_OK) + return error; + BSecureSocket* socket = new(std::nothrow) BSecureSocket(); + ObjectDeleter socketDeleter(socket); + if (socket == NULL || socket->InitCheck() != B_OK) { + close(fd); + return B_NO_MEMORY; + } + + socket->_SetTo(fd, fLocal, peer); + error = socket->_SetupAccept(); + if (error != B_OK) + return error; + + _socket = socket; + socketDeleter.Detach(); + + return B_OK; +} + + status_t BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) { @@ -267,7 +297,7 @@ BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) if (status != B_OK) return status; - return _Setup(); + return _SetupConnect(); } @@ -351,7 +381,7 @@ BSecureSocket::Write(const void* buffer, size_t size) status_t -BSecureSocket::_Setup() +BSecureSocket::_SetupCommon() { // Do this only after BSocket::Connect has checked wether we're already // connected. We don't want to kill an existing SSL session, as that would @@ -370,6 +400,17 @@ BSecureSocket::_Setup() SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); + return B_OK; +} + + +status_t +BSecureSocket::_SetupConnect() +{ + status_t error = _SetupCommon(); + if (error != B_OK) + return error; + int returnValue = SSL_connect(fPrivate->fSSL); if (returnValue <= 0) { TRACE("SSLConnection can't connect\n"); @@ -381,6 +422,24 @@ BSecureSocket::_Setup() } +status_t +BSecureSocket::_SetupAccept() +{ + status_t error = _SetupCommon(); + if (error != B_OK) + return error; + + int returnValue = SSL_accept(fPrivate->fSSL); + if (returnValue <= 0) { + TRACE("SSLConnection can't accept\n"); + BSocket::Disconnect(); + return fPrivate->ErrorCode(returnValue); + } + + return B_OK; +} + + #else // OPENSSL_ENABLED @@ -418,6 +477,13 @@ BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const ch } +status_t +BSecureSocket::Accept(BAbstractSocket*& _socket) +{ + return B_UNSUPPORTED; +} + + status_t BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) { @@ -463,7 +529,21 @@ BSecureSocket::InitCheck() status_t -BSecureSocket::_Setup() +BSecureSocket::_SetupCommon() +{ + return B_UNSUPPORTED; +} + + +status_t +BSecureSocket::_SetupConnect() +{ + return B_UNSUPPORTED; +} + + +status_t +BSecureSocket::_SetupAccept() { return B_UNSUPPORTED; } diff --git a/src/kits/network/libnetapi/Socket.cpp b/src/kits/network/libnetapi/Socket.cpp index 987549a7be9..6b891a7f537 100644 --- a/src/kits/network/libnetapi/Socket.cpp +++ b/src/kits/network/libnetapi/Socket.cpp @@ -1,5 +1,6 @@ /* * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -39,9 +40,9 @@ BSocket::~BSocket() status_t -BSocket::Bind(const BNetworkAddress& local) +BSocket::Bind(const BNetworkAddress& local, bool reuseAddr) { - return BAbstractSocket::Bind(local, SOCK_STREAM); + return BAbstractSocket::Bind(local, SOCK_STREAM, reuseAddr); } @@ -52,6 +53,26 @@ BSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) } +status_t +BSocket::Accept(BAbstractSocket*& _socket) +{ + int fd = -1; + BNetworkAddress peer; + status_t error = AcceptNext(fd, peer); + if (error != B_OK) + return error; + BSocket* socket = new(std::nothrow) BSocket(); + if (socket == NULL) { + close(fd); + return B_NO_MEMORY; + } + + socket->_SetTo(fd, fLocal, peer); + _socket = socket; + return B_OK; +} + + // #pragma mark - BDataIO implementation @@ -94,6 +115,7 @@ BSocket::_SetTo(int fd, const BNetworkAddress& local, fSocket = fd; fLocal = local; fPeer = peer; + fIsConnected = true; TRACE("%p: accepted from %s to %s\n", this, local.ToString().c_str(), peer.ToString().c_str());